Маршрутизация

Представления и одностраничные приложения

Последнее обновление: 27.04.2017

Одним из ключевых компонентов всех MVC-фреймворков являются представления (view). И фреймворк AngularJS не исключение, с тем только отличием, что AngularJS позволяет при использовании представлений создавать одностраничные приложения или так называемые Single Page Applications. Посмотрим на примере.

Для этого содадим новый проект. Для файлов javascript в проект добавим для папку js. В этой папке создадим новый каталог lib, в который положим два файла фреймворка AngularJS: angular.min.js и angular-route.min.js.

Файл angular-route.min.js идет вместе с главной библиотекой AngularJS и он как раз содержит функциональность модуля ngRoute, который необходим для обеспечения маршрутизации.

Теперь укажем маршруты для использования представлений. Добавим в папку js файл определения модулей приложения app.js:

var questApp = angular.module('questApp', ["ngRoute"])
	.config(function($routeProvider){
		$routeProvider.when('/question',
		{
			templateUrl:'views/question.html',
			controller:'QuestionController'
		});
		$routeProvider.when('/answer',
		{
			templateUrl:'views/answer.html',
			controller:'AnswerController'
		});
});

Чтобы подключить функциональность маршрутов, нам надо подключить другой модуль ngRoute.

С помощью метода config мы определяем маршруты приложения. Для конфигурации маршрутов используется объект $routeProvider.

Метод $routeProvider.when принимает два параметра: название маршрута и объект маршрута. Объект маршрута задает представление и обрабатывающий его контроллер с помощью параметров templateUrl и controller. Поэтому для представлений нам не надо определять контроллер с помощью директивы.

Итак, у нас есть два маршурта, и для каждого маршрута нам надо создать свой контроллер и свое представление. Поэтому в папке js также создадим еще один каталог controllers. В него добавим новый файл QuestionController.js:

questApp.controller('QuestionController', 
    function QuestionController($scope, dataService){
     
        var promiseObj=dataService.getData();
        promiseObj.then(function(value) { $scope.question=value; });
         
        $scope.voteUp = function (answer){
            answer.rate++;
        };
        $scope.voteDown = function (answer){
            answer.rate--;
        };
    }
)

И также добавим в папку js/controllers еще один файл AnswerController.js:

questApp.controller('AnswerController',
    function AnswerController($scope, $http){
		
		$scope.response={};
        $scope.save = function (answer, answerForm){
            if(answerForm.$valid){
                
				$http.post("postAnswer.php", answer).then(function success(response) {
					$scope.response=response.data;
				});
            }
        };
    }
)

Первый контроллер QuestionController использует для получения даных сервис dataService, поэтому создадим его. Для этого в папку js добавим новый файл dataService.js:

questApp.factory('dataService', function($http, $q){
    return{
        getData: function(){
            var deferred = $q.defer();
            $http({method: 'GET', url: 'question.json'}).
				then (function success(response) {
						deferred.resolve(response.data.question);
					}, function error(response) {
						deferred.reject(response.status);
					}
				);
             
            return deferred.promise;
        }
    }
})

Этот сервис обращается к файлу question.js, который находится в корневом каталоге:

{
    "question":{
        "text": "Какой js-фреймворк лучше использовать?",
        "author": "Иван Иванов",
        "date": "20/10/2013",
        "answers":
        [{
            "id" : 1,
            "text": "AngularJS!",
            "author": "Вова Сидоров",
            "date": "20/10/2013",
            "rate":2
        },{
            "id" : 2,
            "text": "AngularJS лучше всех",
            "author": "Олег Кузнецов",
            "date": "21/10/2013",
            "rate":3
        }]
    }
}

И также в корневом каталоге для представлений содадим папку views. Поместим в папку views первое представление, которое назовем question.html и которое будет иметь следующий код:

<div>
<div class="quest">
<h3>{{question.text}}</h3>
<p>{{question.author}} </p> <p><i>{{question.date}}</i></p>
</div>
<h3>Ответы</h3>
<div class="answers">
<div ng-repeat="answer in question.answers | orderBy:sortparam" class="answer">
<div class="vote">
    <a class="vote-up" ng-click="voteUp(answer)"></a>
    <span class="rate">{{answer.rate}}</span>
    <a class="vote-down" ng-click="voteDown(answer)"></a>
</div>
<b>{{answer.text}}</b>
<p>{{answer.author}}</p>
<p><i>{{answer.date}}</i></p>
</div>
</div>

Это представление будет выводить вопрос и список ответов на него, взаимодействуя с контроллером QuestionController. То есть для представления не нужны теги body и head, только разметка, имеющая отношение к самому представлению. Обратите внимание, что элемент div верхнего уровня не содержит директивы ng-controller="QuestionController", как в предыдущих темах. Так как связь с контроллером мы зададим напрямую с помощью определения маршрута.

Второе представление пусть будет содержать форму для ответа. Назовем его answer.html и добавим в него следующий код:

<div ng-controller="QuestionController">
<div class="quest">
<h3>{{question.text}}</h3>
<p>{{question.author}} </p> <p><i>{{question.date}}</i></p>
</div>
</div>
<div>
<form name="answerForm">
<fieldset>
<p><label for="answerText">Текст ответа</label>
<input id="answerText" ng-model="answer.text" required placeholder="Введите ответ" /></p>
<p><label for="answerAuthor">Автор ответа</label>
<input id="answerAuthor" ng-model="answer.author" required placeholder="Введите автора" /></p>
</fieldset>
<button type="submit" ng-click="save(answer, answerForm)">Сохранить</button>
</form>
</div>

Здесь немного иначе. Так как мы можем при определении маршрута указать для представления только один контроллер для представления, здесь явным образом с помощью директивы ng-controller="QuestionController" для первого блока div указано, что этот блок будет обрабатываться другим конкретным контроллером.

И в конце определим в корне проекта главную веб-страницу index.html:

<!doctype html>
<html ng-app="questApp">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="css/mystyles.css" />
</head>
<body>
<nav><a href="#!question">Вопрос</a>|<a href="#!answer">Ответить</a></nav>
<ng-view></ng-view>
<script src="js/lib/angular.min.js"></script>
<script src="js/lib/angular-route.min.js"></script>
<script src="js/app.js"></script>
<script src="js/dataService.js"></script>
<script src="js/controllers/QuestionController.js"></script>
<script src="js/controllers/AnswerController.js"></script>
</body>
</html>

В итоге проект будет иметь следующую структуру:

Представления в AngularJS

Для перемещения по представлениям здесь использовано навигационное меню nav с ссылками типа <a href="#/question">Вопрос</a>. Атрибут href здесь не указывает на конкретную страницу html. Он указывает на маршрут, определенный ранее. Перед каждым маршрутом стоит знак # для того, чтобы в браузере можно было при необходимости обращаться напрямую к данному ресурсу.

После определения меню идет директива <ng-view></ng-view>, определенная в модуле ngRoute. Она представляет место, где производиться рендеринг представления, соответствующего маршруту.

Теперь, если мы запустим приложение, то нам отобразиться примитивное меню. Выберем из него первый пункт, и сразу приложение выведет на странице index.html представление views/question.html:

Теперь выберем другой пункт меню, и сработает другой маршрут, хотя мы по-прежнему будем находиться на странице index.html:

Хотя все у нас работает, но при первом обращении к приложению у нас не используется никакого представления, и мы наблюдаем только меню. Но мы можем это исправить, указав маршрут по умолчанию. Для этого изменим файл конфигурации модуля приложения следующим образом:

var questApp = angular.module('questApp', ["ngRoute"])
	.config(function($routeProvider){
		$routeProvider.when('/question',
		{
			templateUrl:'views/question.html',
			controller:'QuestionController'
		});
		$routeProvider.when('/answer',
		{
			templateUrl:'views/answer.html',
			controller:'AnswerController'
		});
		$routeProvider.otherwise({redirectTo: '/question'});
});

Метод $routeProvider.otherwise указывает на маршрут по умолчанию. В данном случае будет загружаться представление views/question.html.

Таким образом, фреймворк AngularJS позволяет нам легко создавать одностраничные приложения.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850