AngularJS е JavaScript MVC рамка, разработена от Google, която ви позволява да създавате добре структурирани приложения отпред, които са лесни за проверка и поддръжка.
Ако все още не сте опитали AngularJS, това е жалко. Рамката се състои от добре интегриран набор от инструменти, които ще ви помогнат да изградите клиентски приложения, добре структурирани в модулна система, с по-малко код и повече гъвкавост.
AngularJS разширява HTML, предоставяйки насоки които добавят функционалност към вашата печалба и ви позволяват да създавате мощни динамични шаблони. Можете също така да създадете свои собствени директиви, създавайки компоненти за многократна употреба, които завършват вашите нужди и абстрахирайки цялата логика за манипулиране на DOM.
Той също така изпълнява двупосочно свързване на данни, свързвайки вашия HTML (изгледи) с JavaScript обекти (модели) безпроблемно. С прости думи, това означава, че всяка актуализация на вашия модел ще бъде незабавно отразена във вашия изглед, без да е необходима каквато и да е DOM манипулация или обработка на събития (например с jQuery).
Angular предоставя услуги на върха на XHR, които значително опростяват вашия код и ви позволяват да абстрахирате API повикванията в услуги за многократна употреба. С това можете да преместите вашия бизнес модел и логика към предния край и да изградите независими задни уеб приложения (агностични).И накрая, обичам Angular поради неговата гъвкавост по отношение на сървърната комуникация. Подобно на повечето JavaScript MVC рамки, Angular ви позволява да работите с всяка сървърна технология, стига да може да обслужва вашето приложение чрез уеб REST API. Но Angular предлага и услуги, различни от XHR, което значително опростява вашия код и ви позволява да абстрахирате API извикванията в услуги за многократна употреба. В резултат на това можете да преместите бизнес модела и логиката към предния край и да изградите уеб приложения заден край независим. В тази публикация ще направим точно това: стъпка по стъпка.
На първо място, ние ще решим естеството на приложението, което искаме да изградим. В това ръководство предпочитаме да не отделяме прекалено много време на задния край, така че ще напишем нещо за базата данни, което е лесно за достъп в интернет, като приложение за спортни новини!
Тъй като съм голям фен на автомобилния спорт и Формула 1, ще използвам услугата API Autosport като наш гръб. За щастие момчетата от Ергаст те са достатъчно любезни, за да предоставят безплатен API за автоспорт, което е идеално за нас.
Като предварителен преглед на това, което ще изградим, разгледайте демо на живо . За да разкрася демото и да покажа някои ъглови шаблони, приложих тема на Bootstrap от WrapBootstrap , но тъй като тази статия не е за CSS, ще я абстрахирам от примерите и ще я оставя изцяло.
Нека започнем нашето примерно приложение с малко Boilerplate. Препоръчвам проекта ъглово семе тъй като не само осигурява страхотен скелет за зареждане, но и поставя основите за модулно тестване с Карма Y. Жасмин (Не правим никакви тестове в тази демонстрация, така че нека оставим това настрана засега; вижте Част 2 от този урок, за да научите повече за настройването на вашия проект, за модулно тестване и от край до край).
РЕДАКТИРАНО (май 2014 г.): Откакто написах този урок, проектът ъглово семе е преминал през някои основни промени (включително добавянето на Бауър като мениджър на пакети). Ако имате някакви въпроси за това как да приложите проекта, хвърлете бърз поглед в първия раздел на вашия справочно ръководство . В урок част 2 , Bower, наред с други инструменти, е обяснено по-подробно.
Добре, сега, когато клонирахме хранилището и инсталирахме зависимостите, скелетът на нашето приложение ще изглежда така:
Сега можем да започнем да кодираме. Тъй като се опитваме да изградим приложение за спортни новини за състезателен шампионат, нека започнем с най-подходящия изглед: таблицата на шампионата.
Като се има предвид, че вече имаме списък с драйвери, дефинирани в обхвата ни (Останете с мен - ще стигнем там), и игнорирайки всеки CSS (за по-лесно четене), нашият HTML може да бъде:
Drivers Championship Standings {{$index + 1}}
{{driver.Driver.givenName}} {{driver.Driver.familyName}} {{driver.Constructors[0].name}} {{driver.points}}
Първото нещо, което ще забележите в този шаблон, е използването на изрази ('{{' и '}}') за връщане на стойности от променливи. В AngularJS изразите ви позволяват да извършите някои изчисления, за да върнете желаната стойност. Някои валидни изрази ще бъдат:
{{ 1 + 1 }}
{ date }
{{ user.name }}
На практика изразите са подобни на JavaScript фрагменти. Въпреки че сте много мощни, не трябва да използвате изрази, за да внедрите логика на по-високо ниво. За целта използваме насоки.
Второто нещо, което ще забележите, е наличието на ng-атрибути, което не бихте забелязали при типично маркиране. Това са насоките.
На високо ниво директивите са заместители (като общи имена, тагове и атрибути), които инструктират AngularJS да прикачи дадено поведение към DOM елемент (или да го трансформира, замени и т.н.). Нека да разгледаме тези, които вече сме виждали:
Директивата ng-app
Той е отговорен за зареждането на вашето приложение, за да определи неговия обхват. В AngularJS можете да имате множество приложения в рамките на една и съща страница, така че тази насока определя къде всяко приложение започва и завършва.
Директивата ng-controller
дефинирайте кой контролер ще отговаря за вашия изглед. В този случай ние го обозначаваме driversController
, което ще предостави нашия списък с проводници (driversList
).
Директивата ng-repeat
Той е един от най-използваните и се използва за определяне на обхвата на вашия шаблон, когато преминавате през колекции. В горния пример повтаряте ред в таблицата за всеки проводник в driversList
.
Разбира се, нашата гледна точка е безполезна без контролер. Нека добавим driversController към нашите controllers.js
:
angular.module('F1FeederApp.controllers', []). controller('driversController', function($scope) { $scope.driversList = [ { Driver: { givenName: 'Sebastian', familyName: 'Vettel' }, points: 322, nationality: 'German', Constructors: [ {name: 'Red Bull'} ] }, { Driver: { givenName: 'Fernando', familyName: 'Alonso' }, points: 207, nationality: 'Spanish', Constructors: [ {name: 'Ferrari'} ] } ]; });
Вероятно сте забелязали променливата $ scope, която предаваме като параметър на контролера. Променливата $scope
трябва да обвързва вашия контролер и изгледи. По-специално, той носи всички данни, които ще бъдат използвани в шаблона. Всичко, което е добавено към него (като driversList
в предишния пример) ще бъде директно достъпно във вашите изгледи. Засега ще работим с масив фиктивни данни (статични), които ще заменим по-късно с нашата API услуга.
Сега добавете това към app.js:
angular.module('F1FeederApp', [ 'F1FeederApp.controllers' ]);
С този ред код инициализираме нашето приложение и регистрираме модулите, от които зависи. Ще се върнем към този файл (app.js
) по-късно.
Сега, нека съберем всичко в index.html
:
F-1 Feeder Drivers Championship Standings {{$index + 1}}
{{driver.Driver.givenName}} {{driver.Driver.familyName}} {{driver.Constructors[0].name}} {{driver.points}}
Модулирани дребни грешки, сега можете да стартирате приложението си и да проверите вашия (статичен) списък с драйвери.
Забележка: Ако имате нужда от помощ за отстраняване на грешки в приложението и преглед на вашите модели и обхват в браузъра, препоръчвам да разгледате впечатляващия batarang; приставка за Chrome.
Тъй като вече знаем как да показваме данните на нашия контролер в нашия изглед, е време да въведем актуални данни от RESTful сървър.
За да улесни комуникацията с HTTP сървъри, AngularJS предоставя услугите $http
и $resource
. Първият е слой отгоре XMLHttpRequest или JSONP , докато последният осигурява по-високо ниво на абстракция. Ще използваме $http
.
За да абстрахираме нашите обаждания към API на сървъра от контролера, ще създадем наша собствена услуга, която ще улавя данните и ще действа като обвивка около $http
като го добавите към нашите services.js
:
angular.module('F1FeederApp.services', []). factory('ergastAPIservice', function($http) { var ergastAPI = {}; ergastAPI.getDrivers = function() { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK' }); } return ergastAPI; });
С първите два реда създаваме нов модул (F1FeederApp.services
) и регистрираме услуга в рамките на този модул (F1FeederApp.services
). Имайте предвид, че ние предаваме $ http като параметър на тази услуга. Това казва на двигателя инжекция на зависимост от Angular, което новата ни услуга изисква ( или зависи ) на услугата $http
.
По подобен начин трябва да кажем на Angular да включи новия ни модул в нашето приложение. Нека го регистрираме с app.js
, като заменим съществуващия ни код с:
angular.module('F1FeederApp', [ 'F1FeederApp.controllers', 'F1FeederApp.services' ]);
Сега всичко, което трябва да направим, е да коригираме нашите controller.js
малко, интегрирайте ergastAPIservice
като зависимост и ще бъдем готови да продължим:
angular.module('F1FeederApp.controllers', []). controller('driversController', function($scope, ergastAPIservice) { $scope.nameFilter = null; $scope.driversList = []; ergastAPIservice.getDrivers().success(function (response) { //Dig into the responde to get the relevant data $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings; }); });
Сега презаредете приложението и проверете резултата. Забележете, че не направихме промени в нашия шаблон, но добавихме променлива nameFilter
в нашия обсег. Ще използваме тази променлива.
Страхотен! Разполагаме с функционален контролер. Но показва само списък с драйвери. Ще добавим някои функции чрез просто въвеждане на текст, което ще филтрира списъка. Нека добавим следния ред към нашите index.html
, точно под етикета:
ng-model
Сега използваме директивата Този ред казва В този момент влиза двупосочното свързване на данни: всеки път, когато се въведе стойност в полето за търсене, Angular незабавно гарантира, че Актуализирайте приложението и погледнете лентата за търсене. Имайте предвид, че този филтър ще търси ключовата дума във всички атрибути на модела, включително тези, които не използваме. Да приемем, че просто искаме да филтрираме Сега, обратно към index.html, актуализираме реда, съдържащ директивата Актуализирайте приложението още веднъж и сега имаме търсене по име. Следващата ни цел е да създадем страница с данни за пилоти, която ще ни позволи да щракнем върху всеки пилот и да видим подробностите за тяхната състезание. Първо, ще включим услугата С тази промяна, навигация до AngularJS ще ви позволи да обвържете маршрутите си с конкретни контролери и изгледи. Но първо трябва да кажем на Angular къде да изобрази тези частични изгледи. За целта ще използваме директивата Сега, когато навигираме през нашите пътища на приложения, Angular ще зареди свързания изглед и ще го изобрази вместо етикета. Всичко, което трябва да направим, е да създадем файл с име Накрая ще решим какво искаме да покажем на страницата с подробности. Какво ще кажете за обобщение на всички релевантни факти за шофьора (например дата на раждане, националност), заедно с таблица, съдържаща последните ви резултати? За целта добавяме следното към Този път предоставяме идентификатора на драйвера на услугата, за да можем да извлечем съответната информация за конкретен драйвер. Сега модифицираме Важното, което трябва да се отбележи тук, е, че инжектираме само услугата Сега, когато разполагаме с данните си, имаме нужда само от останалия частичен изглед. Нека създадем файл с името Забележете, че сега използваме директивата Добавете куп CSS и изобразете страницата си. В крайна сметка трябва да получите нещо подобно: Вече сте готови да стартирате приложението си и се уверете, че и двата маршрута работят по желание. Можете също да добавите статично меню към РЕДАКТИРАНО (май 2014 г.): Получих много заявки за версия на кода за изтегляне, който създадохме в този урок. Затова реших да го направя достъпно тук (лишен от всеки CSS). Истината обаче е, че не препоръчвам да го изтегляте, тъй като това ръководство съдържа всяка стъпка, от която се нуждаете, за да генерирате едно и също приложение със собствените си ръце, което ще бъде много по-полезно и ефективно учебно упражнение. Към този момент в урока сме разгледали всичко, от което се нуждаете, за да напишете просто приложение (например информер за Формула 1). Всяка от останалите страници в демото на живо (напр. Таблица на Constructors 'Championship, подробности за отбора, график) споделя една и съща основна структура и концепции, които сме прегледали. И накрая, имайте предвид, че Angular е много мощна рамка и едва сме надраскали повърхността по отношение на всичко, което може да предложи. В част 2 От този урок ще дадем примери защо Angular се откроява сред своите връстници във фронтовите MVC рамки: тестваемост. Нека да прегледаме процеса на писане и стартиране на модулни тестове с Карма , постигане на непрекъсната интеграция с Йомен , Земя , Y Бауър и други силни страни на тази фантастична интерфейсна рамка.$scope.nameFilter
. Тази директива обвързва текстовото ни поле с променливата index.html
и гарантира, че стойността му винаги е в крак с въведената стойност. Сега нека посетим ng-repeat
още веднъж и нека направим малка корекция на реда, съдържащ директивата : ng-repeat
driversList
че преди извеждане на данните масивът nameFilter
трябва да се филтрира от стойността, съхранена в $scope.nameFilter
.nameFilter
това, което свързваме с него, се актуализира с новата стойност. Тъй като обвързването работи и по двата начина, в момента стойността ng-repeat
се актуализира, вторият лидер, свързан с него (т.е. Driver.givenName
) също получава новата стойност и изгледът се актуализира незабавно.Driver.familyName
и driversController
: Първо, добавяме към $scope.driversList =[];
, точно под реда $scope.searchFilter = function (driver) ;
:ng-repeat
: $routeProvider
Маршрути
app.js
(en app.js
), което ще ни помогне да се справим с тези различни пътища на приложение. След това ще добавим два от тези маршрута: един за таблицата на шампионата и един за данните за водача. Ето нашите нови angular.module('F1FeederApp', [ 'F1FeederApp.services', 'F1FeederApp.controllers', 'ngRoute' ]). config(['$routeProvider', function($routeProvider) { $routeProvider. when('/drivers', {templateUrl: 'partials/drivers.html', controller: 'driversController'}). when('/drivers/:id', {templateUrl: 'partials/driver.html', controller: 'driverController'}). otherwise({redirectTo: '/drivers'}); }]);
:http://domain/#/drivers
driversController
ще зареди partials/drivers.html
и ще намери частичния изглед, който ще се изобрази в ng-view
. Но почакай! Все още нямаме частични възгледи, нали? Ще трябва да ги създадем и ние.Частични изгледи
index.html
, модифицирайки нашите F-1 Feeder
да отразява следното:partials/drivers.html
и да поставим нашата таблица с HTML шампионати там. Също така ще използваме тази възможност, за да свържем името на водача с нашия маршрут от данните за водача:
Drivers Championship Standings {{$index + 1}} {{driver.Driver.givenName}} {{driver.Driver.familyName}}
{{driver.Constructors[0].name}} {{driver.points}} services.js
angular.module('F1FeederApp.services', []) .factory('ergastAPIservice', function($http) { var ergastAPI = {}; ergastAPI.getDrivers = function() { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK' }); } ergastAPI.getDriverDetails = function(id) { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/driverStandings.json?callback=JSON_CALLBACK' }); } ergastAPI.getDriverRaces = function(id) { return $http({ method: 'JSONP', url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/results.json?callback=JSON_CALLBACK' }); } return ergastAPI; });
:controllers.js
angular.module('F1FeederApp.controllers', []). /* Drivers controller */ controller('driversController', function($scope, ergastAPIservice) { $scope.nameFilter = null; $scope.driversList = []; $scope.searchFilter = function (driver) ; ergastAPIservice.getDrivers().success(function (response) { //Digging into the response to get the relevant data $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings; }); }). /* Driver controller */ controller('driverController', function($scope, $routeParams, ergastAPIservice) { $scope.id = $routeParams.id; $scope.races = []; $scope.driver = null; ergastAPIservice.getDriverDetails($scope.id).success(function (response) { $scope.driver = response.MRData.StandingsTable.StandingsLists[0].DriverStandings[0]; }); ergastAPIservice.getDriverRaces($scope.id).success(function (response) { $scope.races = response.MRData.RaceTable.Races; }); });
:$routeParams
$routeParams.id
на контролера на водача. Тази услуга ще ни позволи да осъществим достъп до нашите параметри на URL (за: id, в този случай) чрез partials/driver.html
. <- Back to drivers list
и добавяме:
{{driver.Driver.givenName}} {{driver.Driver.familyName}} Country: {{driver.Driver.nationality}}
Team: {{driver.Constructors[0].name}}
Birth: {{driver.Driver.dateOfBirth}}
Biography
Formula 1 2013 Results Round Grand Prix Team Grid Race {{race.round}} {{race.raceName}}
{{race.Results[0].Constructor.name}} {{race.Results[0].grid}} {{race.Results[0].position}} ng-show
true
за добра употреба. Тази директива ще покаже HTML елемента само ако предоставеният израз е false
(т.е. нито null
, нито index.html
). В този случай аватарът ще се появи само след като обектът на драйвера бъде зареден в обхвата от контролера.Последни щрихи
|_+_|
, за да подобрите навигационните възможности на потребителя. Възможностите са безкрайни. заключение