AngularJS содержит множество встроенных директив, но их функциональности не всегда достаточно. Иногда необходимо применить более комплексное решение, чем стандартные элементы html, использующие встроенные директивы.
Создадим свою директиву. Для этого в папке js создадим новый файл answerList.js со следующим содержанием:
questApp.directive("answerList", function () { return function (scope, element, attrs) { var data = scope[attrs["answerList"]]; if (angular.isArray(data.answers)) { var ulElem = angular.element("<ul>"); element.append(ulElem); for (var i = 0; i < data.answers.length; i++) { var liElem = angular.element('<li>'); liElem.append(angular.element('<p>').text(data.answers[i].text)); ulElem.append(liElem); } } } });
В итоге весь проект будет выглядеть следующим образом:
Разберем директиву. Директива создается с помощью метода Module.directive(). В данном случае модулем является questApp
,
объявленный в другом файле. Данный метод принимает два параметра: название директивы и функцию, которая собственно и создает директиву.
В качестве названия используется "answerList". Согласно соглашениям об именовании любая буква в верхнем регистре расценивается как начало нового слова, которое будет отделено от предыдущего дефисом. То есть для AngularJS "answerList" будет представлять "answer-list" или "answer-List".
В функцию создания директивы передается три параметра:
scope - объект $scope, установленный в контроллере
element - элемент, к которому применяется директива
attrs - коллекция атрибутов в виде пары ключ-значение, где ключом является название атрибута
Например, далее мы будем передавать объект $scope.question в эту директиву:
<div answer-list="question"></div>
В данном случае элементом является элемент div
, а коллекция атрибутов будет содержать единcтвенный атрибут - директиву
answer-list
. А question - это объект $scope.question
И в строке var data = scope[attrs["answerList"]];
мы как раз получим этот объект question, переданный в директиву. Но фактически мы могли
пойти и другим путем - сразу получить данный объект без использования коллекции атрибутов:
var data = scope.question;
Далее мы можем уже обращаться к объектам, которые заключены внутри $scope.question: data.answers
. Но перед обращением мы проверяем,
является ли нужный нам объект массивом: angular.isArray(data.answers)
Дальше в директиве идет создание html-элементов и перебор элементов внутри массива data.answers. Для создания элементов применяется функция angular.element(), а для добавления созданных элементов в другой - метод append()
Применим директиву на главной странице:
<!doctype html> <html ng-app="questApp"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="css/mystyles.css" /> </head> <body> <div ng-controller="QuestionController"> <div class="quest"> <h3>{{question.text}}</h3> <p>{{question.author}} </p> <p><i>{{question.date}}</i></p> </div> <h3>Ответы</h3> <div answer-list="question"></div> </div> <script src="js/lib/angular.min.js"></script> <script src="js/app.js"></script> <script src="js/controllers/QuestionController.js"></script> <script src="js/answerList.js"></script> </body> </html>
Теперь изменим директиву, чтобы веб-страница получилась такой же как и в прошлых темах:
questApp.directive("answerList", function () { return function (scope, element, attrs) { var data = scope[attrs["answerList"]]; if (angular.isArray(data.answers)) { var divElem = angular.element("<div>").addClass("answers"); element.append(divElem); for (var i = 0; i < data.answers.length; i++) { var answerElem = angular.element('<div>').addClass("answer"); var voteElem = angular.element('<div>').addClass("vote"); var voteUpElem = angular.element('<a>').addClass("vote-up"); voteElem.append(voteUpElem); var rateElem = angular.element('<span>').addClass("rate").text(data.answers[i].rate); voteElem.append(rateElem); var voteDownElem = angular.element('<a>').addClass("vote-down"); voteElem.append(voteDownElem); answerElem.append(voteElem); answerElem.append(angular.element('<b>').text(data.answers[i].text)); answerElem.append(angular.element('<p>').text(data.answers[i].author)); var iElem =angular.element('<i>').text(data.answers[i].date); var dateElem = angular.element('<p>').append(iElem); answerElem.append(dateElem); divElem.append(answerElem); } } } });
И наша страница станет более привычной: