Как написать одностраничное приложение на Angular.JS
Новые фреймворки для JavaScript появляются раз в полгода, поэтому трудно что-то выбрать. Рассказываем, почему Angular.JS — один из лучших вариантов.


vlada_maestro / shutterstock
Angular.JS — это фреймворк для работы с JavaScript, поддерживаемый Google. Он используется для создания одностраничных приложений и позволяет взаимодействовать с DOM (англ. Document Object Model — объектная модель документа).
Работает Angular.JS по схеме MVC (англ. Model-View-Controller — модель-вид-контроллер) — она разделяет приложение на три отдельных части, которые можно изменять независимо друг от друга.
Модель
Предоставляет информацию и реагирует на команды контроллера.
Вид
Отвечает за отображение данных модели и следит за изменениями.
Контроллер
Реагирует на действия пользователя и оповещает модель о том, что нужно обновиться.
Такая схема позволяет легко работать с фреймворком, быстро писать код и тестировать его.
Чем отличается Angular.JS от других фреймворков
Главное отличие Angular.JS в том, что он позволяет вставить код прямо в HTML. Допустим, нужно, чтобы в определенном месте менялся текст, когда пользователь взаимодействует с полем ввода:

Вот как это реализуется на чистом JS:
<input type='text' id='TextInput' placeholder='Введите сюда текст'> <br>
<span id='TextSpan'></span>
<script>
var TextInput = document.getElementById('TextInput');
var TextSpan = document.getElementById('TextSpan');
function TextChange() {
TextSpan.innerText = TextInput.value;
}
TextInput.addEventListener('keypress', TextChange);
</script>
На jQuery:
<input type='text' id='TextInput' placeholder='Введите сюда текст'> <br>
<span id='TextSpan'></span>
<script>
$(document).on('keypress','#TextInput', function () {
$('#TextSpan').text($('#TextInput').val());
});
</script>
В первом случае получается громоздкий код. Более компактно выходит на jQuery, но всё равно не сравнится с тем, как это можно написать на Angular.JS:
<div class='wrapper' ng-app>
<input type='text' ng-model='SomeText' placeholder='Введите сюда текст'><br>
{{SomeText}}
</div>
Всё, что мы сделали, — это указали атрибуты ng-app для контейнера и ng-model для поля ввода. Фреймворк реагировал на каждое изменение модели и записывал вводимые данные в переменную SomeText. После этого менялся текст — там, где стоит шаблонизатор {{НазваниеПеременной}}.
То есть Angular.JS самостоятельно отследил изменение поля ввода, поменял значение переменной и обновил вывод в HTML-коде. Разработчику нужно только указать директивы (об этом ниже). В этом заключается основное отличие фреймворка от других.
Давайте рассмотрим работу Angular.JS еще на одном примере. Допустим, нужно реализовать функцию переключения страниц:

Для начала нужно указать HTML-код:
<!DOCTYPE html>
<html ng-app='AngularApp' ng-controller='AngularController as Page'>
<head>
<title>{{Page.Title}} | Проект по изучению Angular.JS</title>
<script src="/angular.min.js"></script>
<script src="/AngularApp.js"></script>
<link rel='stylesheet' href='/style.css'>
</head>
<body>
<div class='wrapper'>
<header class='header'>
<div class='header__content'>
<div class='header__logo'>Изучаем Angular.JS</div>
<nav class='header__nav'>
<div ng-repeat='PageItem in Page.Pages'
class='header__button header__button_selected_{{PageItem.IsSelected}}'
ng-click="Page.MenuClick(PageItem.Name)">
{{PageItem.Title}}
</div>
</nav>
</div>
</header>
<main class='main'>
<article class='article'>
<h2>{{Page.Header}}</h2>
{{Page.Text}}
</article>
</main>
</div>
</body>
</html>
В первую очередь для тега <html> указывается атрибут ng-app (такие атрибуты называются директивами) — в нем содержится название приложения. И теперь все, что находится внутри этого тега, относится к AngularApp. Всего в коде можно указать только один такой атрибут.
Дальше была указана директива ng-controller со значением AngularController as Page. Это означает, что созданный контроллер будет работать с объектом Page. Дальше все переменные и методы вызываются с помощью этого объекта. Например, в <title> будет отображаться поле Page.Title.
После этого создаем меню для страницы. Вместо ручного прописывания кнопок для каждой страницы можно написать такой код:
<nav class='header__nav'>
<div ng-repeat='PageItem in Page.Pages'
class='header__button header__button_selected_{{PageItem.IsSelected}}'
ng-click="Page.MenuClick(PageItem.Name)">
{{PageItem.Title}}
</div>
</nav>
Тут указана одна кнопка с атрибутом ng-repeat. По сути, это обычный цикл forEach, который перебирает все элементы массива (в данном случае PageItem in Page.Pages). Только вместо того чтобы прописывать этот цикл в JS-коде, достаточно указать директиву.
Кнопка получила классы и атрибут ng-click, в котором прописана функция Page.MenuClick () с именем текущего элемента в качестве аргумента. Вот и сам код контроллера:
angular.module('AngularApp', []).controller('AngularController', function () { //Объявление контроллера приложения
var Page = this; //Создание объекта
Page.Pages = [ //Данные о страницах
{
Name: "main",
IsSelected: true,
Title: "Главная",
Header: "Добро пожаловать",
Text: "Это главная страница сайта"
},
{
Name: "blog",
IsSelected: false,
Title: "Блог",
Header: "Блог",
Text: "Тут скоро будут статьи об Angular.JS"
},
{
Name: "about",
IsSelected: false,
Title: "Информация",
Header: "О проекте",
Text: "Этот проект создан для того, чтобы научить вас программировать на Angular.JS"
},
{
Name: "donate",
IsSelected: false,
Title: "Помочь проекту",
Header: "Помочь проекту",
Text: "Нашему проекту нужна ваша помощь!"
}
];
//Выбор данных о главной странице
Page.Title = Page.Pages[0].Title;
Page.Header = Page.Pages[0].Header;
Page.Text = Page.Pages[0].Text;
//Функция переключения страниц
Page.MenuClick = function (PageName) { //Имя страницы в качестве атрибута
angular.forEach(Page.Pages, function (PageItem) { //Перебор всех страниц
PageItem.IsSelected = false; //Отмена выбора
if(PageName == PageItem.Name) { //Поиск совпадения по имени страницы и получения данных
Page.Title = PageItem.Title;
Page.Header = PageItem.Header;
Page.Text = PageItem.Text;
PageItem.IsSelected = true;
}
});
}
Дальше в HTML-коде создаем тело статьи:
<article class='article'>
<h2>{{Page.Header}}</h2>
{{Page.Text}}
</article>
Получился компактный код, в котором ничего не нужно делать, чтобы реализовать функцию, — просто указать места в HTML-коде, с которыми должен работать фреймворк. В контроллере были только данные о страницах и простой метод их переключения.
Где используется Angular.JS
Многие разработчики жалуются, что фреймворк работает медленно из-за того, что приходится постоянно отслеживать все модели, прописанные в коде. Однако на Angular.JS запущены крупные сайты:
- видеохостинг YouTube;
- крупнейшая биржа фрилансеров UpWork.com;
- веб-версия мессенджера Telegram;
- биржа фрилансеров freelancer.com;
- сайт компании Bosch;
- сайт AT& T;
- сайт General Electrics и другие.
Фреймворк востребован и среди менее крупных компаний — около 2300 вакансий на сайте hh.ru по запросу Angular. Поэтому новичку будет просто найти работу.
Заключение
Несмотря на противоречивое отношение программистов к фреймворку, Angular популярен. На это влияют удобство и очень подробная и понятная документация на официальном сайте Angular.JS.