У меня есть директива AngularJS, которая отображает коллекцию сущностей в следующем шаблоне:
<table class="table">
<thead>
<tr>
<th><input type="checkbox" ng-click="selectAll()"></th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="e in entities">
<td><input type="checkbox" name="selected" ng-click="updateSelection($event, e.id)"></td>
<td>{{e.title}}</td>
</tr>
</tbody>
</table>
Как видите, здесь <table>
каждая строка может быть выбрана индивидуально с ее собственным флажком, или все строки могут быть выбраны сразу с помощью основного флажка, расположенного в <thead>
. Довольно классический интерфейс.
Как лучше всего:
- Выбрать одну строку (т.е. когда флажок установлен, добавить идентификатор выбранной сущности во внутренний массив и добавить класс CSS к
<tr>
содержащему сущность, чтобы отразить ее выбранное состояние)? - Выбрать сразу все строки? (т.е. выполните ранее описанные действия для всех строк в
<table>
)
Моя текущая реализация - добавить настраиваемый контроллер в мою директиву:
controller: function($scope) {
// Array of currently selected IDs.
var selected = $scope.selected = [];
// Update the selection when a checkbox is clicked.
$scope.updateSelection = function($event, id) {
var checkbox = $event.target;
var action = (checkbox.checked ? 'add' : 'remove');
if (action == 'add' & selected.indexOf(id) == -1) selected.push(id);
if (action == 'remove' && selected.indexOf(id) != -1) selected.splice(selected.indexOf(id), 1);
// Highlight selected row. HOW??
// $(checkbox).parents('tr').addClass('selected_row', checkbox.checked);
};
// Check (or uncheck) all checkboxes.
$scope.selectAll = function() {
// Iterate on all checkboxes and call updateSelection() on them??
};
}
В частности, мне интересно:
- Принадлежит ли приведенный выше код контроллеру или он должен входить в
link
функцию? - Учитывая, что jQuery не обязательно присутствует (AngularJS не требует этого), как лучше всего выполнять обход DOM? Без jQuery мне сложно просто выбрать родительский
<tr>
элемент для данного флажка или выбрать все флажки в шаблоне. - Переход
$event
кupdateSelection()
не выглядит изящным. Нет ли лучшего способа получить состояние (отмечен / не отмечен) элемента, по которому только что щелкнули?
Спасибо.
источник
ngChecked
директиве. (Я сожалею только о том, что мы не можем сделать этот код менее подробным.)Я предпочитаю использовать директивы ngModel и ngChange при работе с флажками . ngModel позволяет вам привязать отмеченное / не отмеченное состояние флажка к свойству объекта:
<input type="checkbox" ng-model="entity.isChecked">
Каждый раз, когда пользователь устанавливает или снимает флажок,
entity.isChecked
значение также изменяется.Если это все, что вам нужно, вам даже не нужны директивы ngClick или ngChange. Поскольку у вас есть флажок «Проверить все», очевидно, что вам нужно сделать больше, чем просто установить значение свойства, когда кто-то проверяет флажок.
При использовании ngModel с флажком лучше использовать ngChange, а не ngClick для обработки отмеченных и непроверенных событий. ngChange создан именно для такого сценария. Он использует ngModelController для привязки данных (он добавляет слушателя к массиву ngModelController
$viewChangeListeners
. Слушатели в этом массиве вызываются после установки значения модели, что позволяет избежать этой проблемы ).<input type="checkbox" ng-model="entity.isChecked" ng-change="selectEntity()">
... а в контроллере ...
var model = {}; $scope.model = model; // This property is bound to the checkbox in the table header model.allItemsSelected = false; // Fired when an entity in the table is checked $scope.selectEntity = function () { // If any entity is not checked, then uncheck the "allItemsSelected" checkbox for (var i = 0; i < model.entities.length; i++) { if (!model.entities[i].isChecked) { model.allItemsSelected = false; return; } } // ... otherwise ensure that the "allItemsSelected" checkbox is checked model.allItemsSelected = true; };
Аналогично галочка «Проверить все» в шапке:
<th> <input type="checkbox" ng-model="model.allItemsSelected" ng-change="selectAll()"> </th>
... и ...
// Fired when the checkbox in the table header is checked $scope.selectAll = function () { // Loop through all the entities and set their isChecked property for (var i = 0; i < model.entities.length; i++) { model.entities[i].isChecked = model.allItemsSelected; } };
CSS
Если вы используете подход ngModel для привязки данных, все, что вам нужно сделать, это добавить директиву ngClass к
<tr>
элементу для динамического добавления или удаления класса при изменении свойства объекта:<tr ng-repeat="entity in model.entities" ng-class="{selected: entity.isChecked}">
См. Полный Plunker здесь .
источник
Ответ Ливиу был мне чрезвычайно полезен. Надеюсь, это не дурной тон, но я сделал скрипку, которая может помочь кому-то другому в будущем.
Необходимы две важные составляющие:
$scope.entities = [{ "title": "foo", "id": 1 }, { "title": "bar", "id": 2 }, { "title": "baz", "id": 3 }]; $scope.selected = [];
источник