После примеров про Hello world, Echo и простой калькулятор, создание списка TODO - это один из ритуальных пассажей для вхождения в мир программирования на любом языке в любом окружении. Давайте посмотрим, как реализовать TODO на AngularJS.

Простой список TODO

После загрузки angular.min.js мы создаем модуль AngularJS с именем todoApp и контролллер todoController. Внутри контроллера мы создаем пустой массив tasks, где будет содержаться список todo. Мы сделаем его атрибутом текущего $scope, чтобы иметь возможность доступа из HTML.

Мы также объявляем функцию add (тоже атрибут $scope), которая получает значение title (Как мы позже увидим, это будет имя поля для ввода), и добавляем его в список задач, используя push. Вот и весь JavaScript, который нам нужен для простого списка TODO.

В части HTML у нас есть элемент div, который определяет область AngularJS-приложения ng-app и AngularJS-контроллера ng-controller.

Внутри контролллера в HTML у нас есть две части. Первая часть это поле для ввода input, связанное с атрибутом $scope.title с помощью ng-model, и кнопка, использующая ng-click для вызова метода $scope.add при нажатии.

Вторая часть использует директиву ng-repeat для прохода по элементам массива $scope.tasks и показа их в виде списка.

examples/angular/todo1.html

<script src="angular.min.js"></script>
<script>
angular.module('todoApp', [])
    .controller('todoController', function($scope){
        $scope.tasks = [];
        $scope.add = function() {
            $scope.tasks.push($scope.title);
        }
    })
</script>
<div ng-app="todoApp" ng-controller="todoController">
    <input ng-model="title"><button ng-click="add()">Add</button>
    <ul>
        <li ng-repeat="t in tasks">{{ t }}</li>
    </ul>
</div>
Try!

Активация поля ввода нажатием ENTER

Несколько обременительно нажимать кнопку для добавления каждого элемента. Будет гораздо лучше, если мы сможем просто нажимать ENTER. Чтобы это сделать, нам нужно обернуть элемент input в form и на форму добавить директиву ng-submit, которая будет вызывать функцию $scope.add. А также для избежания повторного вызова функции $scope.add.

  <form ng-submit="add()">
  <input ng-model="title"><button>Add</button>
  </form>

Дублирующиеся значения в ng-repeat

Если вы попробовали пример выше, то могли заметить, что добавление того же элемента дважды приводит к падению приложения. Причина в том, что директива ng-repeat расчитана на уникальные значения в массиве. Я не уверен, что наличие одинаковых значений в списке TODO это хорошо, но сейчас я бы хотел позволить пользователю добавлять то же самое значение дважды. Для этого мы можем указать ng-repeat использовать $index массива для перебора значений:

<li ng-repeat="t in tasks track by $index">{{ t }}</li>

Удаление элемента из списка TODO

Хотя для большинства из нас реальность такова, что TODO список всегда увеличивается, иногда удача нам сопутствует и дела выполняются. (Или они просто отменяются.) Мы бы хотели иметь способ удалить элемент. Для этого мы собираемся добавить кнопку в конце каждого пункта, которая будет удалять конкретный элемент из списка дел.

Добавить кнопку это просто:

<button ng-click="delete()">x</button>

Соответствующая кнопке функция delete заставила меня почесать голову, но в итоге я справился:

$scope.delete = function() {
    $scope.tasks.splice(this.$index, 1);
}

Когда вызывается функция delete, this содержит атрибут $index, который похоже указывает на индекс текущего элемента. Мы можем использовать это для нахождения нужного элемента в массива tasks. Функция JavaScript splice удалит один элемент из массива, а список сразу же обновится на HTML-странице.

examples/angular/todo2.html

<script src="angular.min.js"></script>
<script>
angular.module('todoApp', [])
    .controller('todoController', function($scope) {
        $scope.tasks = [];
        $scope.add = function() {
            $scope.tasks.push($scope.title);
        }
        $scope.delete = function() {
            $scope.tasks.splice(this.$index, 1);
        }
    })
</script>
<div ng-app="todoApp" ng-controller="todoController">
    <form ng-submit="add()">
    <input ng-model="title"><button>Add</button>
    </form>
    <ul>
        <li ng-repeat="t in tasks track by $index">{{ t }} <button ng-click="delete()">x</button></li>
    </ul>
</div>
Try!