function MessageCtrl($scope, MessageService) {

    function resetInbox() {
        $scope.messageIndex = {};
        $scope.messageList = [];
        $scope.messageIds = [];
        
        resetSelection();
    }
    
    function resetSelection() {
        $scope.selection = {};
        allSelected = $scope.allSelected = false;
    }

    function updateList() {
        resetInbox();

        // load our messages
        MessageService.getListMessages().then(function(response) {
            var list = response.data,
                ids = [],
                index = {};

            list.forEach(function(message) {
                if (message) {
                    ids.push(String(message.id));
                    index[message.id] = message;
                }
            });

            // store object references by id for faster access
            $scope.messageIndex = index;
            $scope.messageList = list;
            $scope.messageIds = ids;
        });
    }

    function getSelectedIds() {
        var selectedIds = [],
            selection = $scope.selection;

        $scope.messageIds.forEach(function(id) {
            if (selection[id] === true) {
                selectedIds.push(id);
            }
        });

        return selectedIds;
    }

    function markAllAsRead(ids) {
        var index = $scope.messageIndex;

        ids.forEach(function(id) {
            index[id].wasRead = true;
        });
    }

    $scope.toggleSelectedId = function(id) {
        $scope.selection[id] = !$scope.selection[id];
    };

    var allSelected = false;
    $scope.toggleSelectAll = function() {
        var ids = $scope.messageIds,
            selection = $scope.selection;

        if (!ids.length) return;

        allSelected = !allSelected;
        ids.forEach(function(id) {
            selection[id] = allSelected;
        });

        $scope.allSelected = allSelected;
    };

    $scope.markAsRead = function() {
        var selectedIds = getSelectedIds();
        console.log('mark as read', selectedIds);
        
        if (!selectedIds.length) return;

        MessageService.markAsRead(selectedIds).then(function() {
            markAllAsRead(selectedIds);
            resetSelection();
        });
    };

    $scope.updateList = updateList;
    $scope.hasSelection = function() {
        return getSelectedIds().length !== 0;
    };

    resetInbox();
    updateList();
}

function MessageServiceFactory($http) {

    /**
     * Mark messages as read
     * @param {String|String[]} ids     Can be either a single ID or a list of IDs
     */
    function markAsRead(ids) {
        if (ids instanceof Array === false) {
            ids = [ids];
        }

        ids = ids.join(',');

        return $http.get('/inbox/mark-as-read/' + ids);
    }

    /**
     * Load a list of messages from server
     */
    function loadList() {
        return $http.get('/inbox/messages');
    }

    return {
        markAsRead: markAsRead,
        getListMessages: loadList
    };
}

angular.module('inbox', ['ngMockE2E'])
    .controller('MessageCtrl', MessageCtrl)
    .service('MessageService', MessageServiceFactory);
<!DOCTYPE html>
<html ng-app="inbox">

<head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>
        document.write('<base href="' + document.location + '" />');
    </script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js" data-semver="1.0.8"></script>
    <script src="http://code.angularjs.org/1.0.8/angular-mocks.js"></script>
    <script src="app.js"></script>
    <script src="mocks.js"></script>
    <meta content="width=device-width, initial-scale=1.0" name="viewport" />
	<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible" />
</head>

<body ng-controller="MessageCtrl">
    <div class="inbox">
        <h1>Inbox app</h1>
        <div class="toolbar">
            <button ng-click="updateList()">Update list</button>
            <button class="btn-primary" ng-disabled="!hasSelection()" ng-click="markAsRead()">Mark as read</button>
        </div>

        <table>
            <thead>
                <tr ng-class="{selected: allSelected}">
                    <th><span class="selection-mark" ng-click="toggleSelectAll()">&nbsp;</span>
                    </th>
                    <th>Message</th>
                    <th>From</th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="message in messageList" ng-class="{unread: !message.wasRead, selected: selection[message.id]}" ng-click="toggleSelectedId(message.id)">
                    <td><span class="selection-mark">&nbsp;</span>
                    </td>
                    <td class="title">{{ message.title }}</td>
                    <td>{{ message.from }}</td>
                </tr>
            </tbody>
        </table>
    </div>
</body>

</html>
* {
    margin: 0;
    padding: 0;
    font-size: 1em;
    font-family: inherit;
}

body {
    font-family: sans-serif;
}

.inbox {
    font-size: 12px;
    padding: 20px;
}
.inbox h1 {
    margin-bottom: .5em;
    border-bottom: 1px solid #ddd;
    font-size: 2em;
}
.inbox table {
    width: 100%;
}
.inbox .unread td {
    background: #ffe;
}
.inbox .unread .title {
    font-weight: bold;
}
.toolbar {
    padding-bottom: 1em;
}
.toolbar button {
    padding: 7px;
    border-radius: 3px;
    background: whiteSmoke;
    color: #666;
    border: none;
    font-weight: bold;
}
.toolbar button[disabled="disabled"] {
    background: #fafafa;
    color: #aaa;
    font-weight: normal;
}
.toolbar .btn-primary {
    background: #4387FD;
    color: white;
}
.inbox table {
    border-collapse: collapse;
}
.inbox th {
    font-weight: bold;
}
.inbox th,
.inbox td {
    padding: 7px;
}
.inbox th {
    background-color: whiteSmoke;
    text-align: left;
}
.inbox td {
    cursor: pointer;
}
.selection-mark {
    display: inline-block;
    box-sizing: border-box;
    width: 1em;
    height: 1em;
    border: 1px solid #ddd;
    cursor: pointer;
}
.selected .selection-mark {
    background: #4387FD;
    border-color: #4387FD;
}
angular.module('inbox').run(function($httpBackend) {
    // mark message(s) as read
    // e.g.: /inbox/mark-as-read/1,2,3
    $httpBackend.whenGET(/\/inbox\/mark-as-read\/.+/).respond(function() {
        return [200];
    });
    
    // load message list
    $httpBackend.whenGET('/inbox/messages').respond(function() {
        var list = [], i = 10;
        
        while (i--) {
            list.push(makeMessage());
        }
        
        return [200, list];
    });
    
    $httpBackend.whenGET(/.*/).passThrough();
	$httpBackend.whenPOST(/.*/).passThrough();
    
    var $uid = 0;
    function makeUid() {
        return ++$uid;
    }
    
    var words = 'lorem ipsum dolor sit amet consecteur'.split(' ');
    function makeText(numWords) {
        var text = [''], word, wordsLen = words.length;
        
        for (var i = 0; i < numWords; i++) {
            word = words[Math.floor(Math.random() * wordsLen)];
            text.push(word);
        }
        
        return text.join(' ');
    }
    
    function makeMessage() {
        var wasRead = (Math.random() * 10 > 5);
        
        return {
            id: makeUid(),
            title: makeText(10),
            from: makeText(3),
            wasRead: wasRead
        }
    }
});