Используем AngularJS в Windows Phone 8.1 приложениях

В этом посте я расскажу вам как подключить и начать использовать популярный JavaScript фреймворк AngularJS для разработки приложений для Windows Phone 8.1. Вы сможете подключить AngularJS к своему проекту и начать использовать его возможности.

Создаем проект и подключаем AngularJs

Создаем новый проект для Windows Phone 8.1 на JavaScript по шаблону Blank App.

Подключаем AngularJS. Он доступен в виде установочного пакета в NuGet
Открываем NuGet Package Manager Console и выполняем команды:

 install-package AngularJS.Core install-package AngularJS.Animate install-package Angular.UI.UI-Router 

AngularJS.Core – библиотека с базовыми возможностями AngularJS. 

AngularJS.Animate – анимационные возможности. 

Angular.UI.UI-Router – навигация, работа с представлениями.

Angular-WinJS — чтобы получить возможность использовать AngularJS вместе с WinJS, вам нужно установить этот модуль. К сожалению, в настоящее время он не опубликован в виде пакета NuGet и нам придется скачать его с GitHub вручную. 

Добавьте скачанный скрипт в папку scripts в проекте:

Вносим изменения в библиотеки

Как только вы попробуете подключить библиотеки Angular на вашу страницу и запустить приложение, произойдет страшное, то есть ошибка. 

В соответствии с моделью безопасности Windows Phone приложений, вы не можете динамически менять содержимое элементов страницы. Но можете это делать внутри конструкции

 MSApp.execUnsafeLocalFunction(function () { }); 

То есть, в файле scripts/angular.js необходимо обернуть все изменения innerHTML или вызовы метода prepend или insert..  в эту конструкцию.

Исправленный файл доступен по ссылке на Github

Используем AngularJS на странице приложения

1. Откроем файл default.html, добавим ссылки на библиотеки AngularJS.

В теле страницы разместим специальный контейнер, в который средствами AngularJS мы будем загружать представление:

 <div ui-view></div> 

 

Полный код файла default.html

 <!DOCTYPE html > <html> <head> <meta charset="utf-8" /> <title>demo</title> <link href="//Microsoft.Phone.WinJS.2.1/css/ui-light.css" rel="stylesheet" /> <script src="//Microsoft.Phone.WinJS.2.1/js/base.js"></script> <script src="//Microsoft.Phone.WinJS.2.1/js/ui.js"></script> <!-- Angular references --> <script src="/scripts/angular.js"></script> <script src="/scripts/angular-animate.js"></script> <script src="/scripts/angular-ui-router.js"></script> <script src="/scripts/angular-winjs.js"></script> <!-- demo references --> <link href="/css/default.css" rel="stylesheet" /> <script src="/js/default.js"></script> </head> <body class="phone" > <div ui-view></div> </body> </html> 

2. Создадим новую папку views в который мы будем хранить представления для страниц.
3. В папке views создадим файл mainView.html для представления главной страницы. 
Наша основная страница будет содержать только поздравление с прошедшим праздником и кнопку на панели действий.

Полный код файла mainView.html

 <div class="demoView fragment"> <h1 style="font-size:2em"> {{greeting}} </h1> <win-app-bar> <win-app-bar-command icon="'accept'" label="'ok'" ng-click="ok()"></win-app-bar-command> </win-app-bar> </div> 

Конструкция  {{greeting}}  поможет нам вывести значение переменной, которую мы определим в контроллере, а кнопка подтверждения будет представлять собой кнопку на панели действий, созданную средствами WinJS.

4. Откроем js/default.js – основной файл приложения, в котором будет находиться весь код и заменим его содержимое.

Полный код файла default.js

  (function () { "use strict"; var app = WinJS.Application; var activation = Windows.ApplicationModel.Activation; var angular_app = angular.module('demo', ['ui.router', 'ngAnimate', 'winjs']); app.onactivated = function (args) { if (args.detail.kind === activation.ActivationKind.launch) { if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) { } else { } var angularLoadedSignal = new WinJS._Signal(); angular.element(document).ready(function () { try { angular.bootstrap(document, ['demo']); angularLoadedSignal.complete(); } catch (e) { if (!(typeof e.message == 'string' || e.message instanceof String)) { throw e; } if (e.message.indexOf('[ng:btstrpd]') !== 0) { throw e; } } }); args.setPromise(angularLoadedSignal.promise); } }; app.oncheckpoint = function (args) { }; //наполняем представление данными и обрабатываем события angular_app.controller('mainViewCtrl', ['$scope', function ($scope) { $scope.greeting = 'С Днем народного единства!'; $scope.ok = function () { var msgpopup = new Windows.UI.Popups.MessageDialog("Если вы хотите закрыть окно, нажмите на кнопку","Отправить поздравление"); msgpopup.commands.append(new Windows.UI.Popups.UICommand("ok", function () { })); msgpopup.showAsync(); }; }]); //настраиваем, указываем шаблон и контроллер angular_app.config(function ($stateProvider) { $stateProvider .state('mainView', { url: '/mainView', templateUrl: '/views/mainView.html', controller: 'mainViewCtrl', }); }); //переходим на view при открытии приложения angular_app.constant('homeStateName', 'mainView'); angular_app.run(function (navigationSvc) { navigationSvc.goHome(); }); (function () { var NavigationSvc = function ($q, $state, adapterSvc, homeStateName) { WinJS.Navigation.addEventListener('navigating', function (args) { var targetState = args.detail.location; var angularPromise = $state.go(targetState, args.detail.state); args.detail.setPromise(adapterSvc.toWinJSPromise(angularPromise)); }); this.goHome = function () { return adapterSvc.toAngularPromise(WinJS.Navigation.navigate(homeStateName)); }; this.navigateTo = function (view, initialState) { return adapterSvc.toAngularPromise(WinJS.Navigation.navigate(view, initialState)); }; this.goBack = function () { return adapterSvc.toAngularPromise(WinJS.Navigation.back()); }; this.goForward = function () { return adapterSvc.toAngularPromise(WinJS.Navigation.forward()); } }; angular_app.service('navigationSvc', NavigationSvc); }()); angular_app.service('adapterSvc', ['$q', function ($q) { return { toAngularPromise: function (winjsPromise) { var deferred = $q.defer(); winjsPromise.then(function (value) { deferred.resolve(value); }, function (err) { deferred.reject(err); }, function (value) { deferred.notify(value); }); return deferred.promise; }, toWinJSPromise: function (angularPromise) { var signal = new WinJS._Signal(); angularPromise.then(function (value) { signal.complete(value); }, function (err) { signal.error(err); }, function (value) { signal.progress(value); }); return signal.promise; } } }]); app.start(); })(); 

В этом коде мы:

  • Инициализируем библиотеки AngularJS и заставляем выполниться механизм bootstrap при загрузке страницы приложения. Подробнее как работает bootstrap в AngularJS описано в руководстве.

  • Создаем контроллер demoViewCtrl, в котором создаем переменную и обрабатываем событие нажатия на кнопку на панели действий

  • Реализуем навигацию и загрузку представления в контейнер.
    Некоторые детали про навигацию Как вы знаете, в WinJS есть своя библиотека для навигации WinJS.Navigation и вы можете создавать одностраничные приложения (single page apps), где все остальные страницы подгружаются в DOM одной основной страницы, или использовать привычную модель навигации и осуществлять переходы между страницами. 

    AngularJS имеет возможности навигации между представлениями в рамках одностраничного приложения, которые очень похожи на концепцию навигации в WinJS. Функции работы с навигацией доступны в виде отдельного модуля на сайте AngularJS. Популярной альтернативой модуль UI Router (мы уже установили из NuGet).

    Начав использовать AngularJS вы можете выбирать какими механизмами (WinJS или AngularJS) вы будете пользоваться в своем проекте. Единственное что надо помнить – это то, что у тебе телефона есть аппаратная кнопка Back, про которую AngularJS ничего не знает, и чтобы она работала, мы используем гибридный вариант навигации AngularJS+WinJS.

5. Запускаем приложение. Приложение должно запуститься и загрузить представление. 

Заключение

Все больше технологий, которые мы привыкли видеть и использовать в веб, становятся доступны для мобильных платформ. И это просто замечательно.

Библиотеки Angular для Windows Phone

Библиотека Angular-WinJS 
Исправленный файл angular.js
Пример кода: ToDoList для Windows Phone 8.1 на AngularJS

Полезные ссылки

Документация по AngularJS