your first angularjs app: a comprehensive tutorial

23
Your First AngularJS App: A Comprehensive Tutorial A Step-by-Step Guide to Your First AngularJS App

Upload: toptal

Post on 10-Aug-2015

93 views

Category:

Software


7 download

TRANSCRIPT

Your First AngularJS App: A Comprehensive TutorialA Step-by-Step Guide to Your First AngularJS App

What is AngularJS?

•“Superheroic JavaScript MVW Framework”•“AngularJS is what HTML would have been, had it been designed for building web-apps”

•Developed by Google•Declarative templates with data-binding, dependency injection and great testability, all implemented with pure client-side JavaScript

Why should I use AngularJS?

•Extends HTML by providing directives• Implements two-way data binding•Provides services on top of XHR that dramatically simplify code

An app we want to build

• Backend• Autosport API service by Ergast

• Frontend• AngularJS and angular-seed

• Design• Bootstrap theme Plastic Admin

A sports feed app - Formula 1

Getting Started

App’s skeleton using

angular-seed

Getting Started (cont.)

What we want to get

The championship

table

HTML

• Expressions {{ and }}

• Basic Directives

• ng-app• ng-controller• ng-repeat

<body ng-app="F1FeederApp" ng-controller="driversController"> <table> <thead> <tr><th colspan="4">Drivers Championship Standings</th></tr> </thead> <tbody> <tr ng-repeat="driver in driversList"> <td>{{$index + 1}}</td> <td> <img src="img/flags/{{driver.Driver.nationality}}.png" /> {{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}} </td> <td>{{driver.Constructors[0].name}}</td> <td>{{driver.points}}</td> </tr> </tbody> </table></body>

Javascript

• Initialize an app with app.js

• Add Controllers - controllers.js

• $scope variable

• Link controllers and views

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"} ] } ];});

controllers.js

angular.module('F1FeederApp', [ 'F1FeederApp.controllers']);

app.js

HTML<!DOCTYPE html><html><head> <title>F-1 Feeder</title></head>

<body ng-app="F1FeederApp" ng-controller="driversController"> <table> <thead> <tr><th colspan="4">Drivers Championship Standings</th></tr> </thead> <tbody> <tr ng-repeat="driver in driversList"> <td>{{$index + 1}}</td> <td> <img src="img/flags/{{driver.Driver.nationality}}.png" /> {{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}} </td> <td>{{driver.Constructors[0].name}}</td> <td>{{driver.points}}</td> </tr> </tbody> </table> <script src="bower_components/angular/angular.js"></script> <script src="bower_components/angular-route/angular-route.js"></script> <script src="js/app.js"></script> <script src="js/services.js"></script> <script src="js/controllers.js"></script></body></html>

index.html

Loading Data From the Server

• To fetch data from a RESTful server AngularJS provides two services

• $http• $resource

• $http is passed as a parameter to the service - dependency injection

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; });

services.js

Tweaking app.js and controllers.js

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; }); });

controllers.js

angular.module('F1FeederApp', [ 'F1FeederApp.controllers', 'F1FeederApp.services']);

app.js

Filters

• Add a simple text search input to index.html

<input type="text" ng-model="nameFilter" placeholder=“Search..."/><tr ng-repeat="driver in driversList | filter: nameFilter">

• ng-model directive binds text field to the $scope.nameFilter variable

• ng-repeat is now filtered by the value stored in nameFilter

• Two-way data binding: search field > $scope.nameFilter > ng-repeat

Filters (cont.)

• Filter by Driver.givenName and Driver.familyName:

$scope.searchFilter = function (driver) { var keyword = new RegExp($scope.nameFilter, 'i'); return !$scope.nameFilter || keyword.test(driver.Driver.givenName) ||

keyword.test(driver.Driver.familyName);};

• Update ng-repeat directive in index.html:

<tr ng-repeat="driver in driversList | filter: searchFilter">

Routes• Next goal is to create a driver details page

• include $routeProvider service in 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'});

}]);

• URL http://domain/#/drivers loads driversController and render partial view partials/drivers.html

Partial Views• To tell Angular where to render partial views, we use ng-view directive

• Modified index.html<!DOCTYPE html><html><head> <title>F-1 Feeder</title></head>

<body ng-app="F1FeederApp"> <ng-view></ng-view> <script src="bower_components/angular/angular.js"></script> <script src="bower_components/angular-route/angular-route.js"></script> <script src="js/app.js"></script> <script src="js/services.js"></script> <script src="js/controllers.js"></script></body></html>

Partial Views (cont.)<input type="text" ng-model="nameFilter" placeholder="Search..."/><table><thead> <tr><th colspan="4">Drivers Championship Standings</th></tr></thead><tbody> <tr ng-repeat="driver in driversList | filter: searchFilter"> <td>{{$index + 1}}</td> <td> <img src="img/flags/{{driver.Driver.nationality}}.png" /> <a href="#/drivers/{{driver.Driver.driverId}}">

{{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}} </a></td>

<td>{{driver.Constructors[0].name}}</td> <td>{{driver.points}}</td> </tr></tbody></table>

partials/drivers.html

Partial Views (cont.)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; });

services.js

Partial Views (cont.)angular.module('F1FeederApp.controllers', []). /* Drivers controller */ controller('driversController', function($scope, ergastAPIservice) { $scope.nameFilter = null; $scope.driversList = []; $scope.searchFilter = function (driver) { var re = new RegExp($scope.nameFilter, 'i'); return !$scope.nameFilter || re.test(driver.Driver.givenName) || re.test(driver.Driver.familyName); }; 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; }); });

controllers.js

Partial Views (cont.)<section id="main"> <a href="./#/drivers"><- Back to drivers list</a> <nav id="secondary" class="main-nav"> <div class="driver-picture"> <div class="avatar"> <img ng-show="driver" src="img/drivers/{{driver.Driver.driverId}}.png" /> <img ng-show="driver" src="img/flags/{{driver.Driver.nationality}}.png" /><br/> {{driver.Driver.givenName}} {{driver.Driver.familyName}} </div> </div> <div class="driver-status"> Country: {{driver.Driver.nationality}} <br/> Team: {{driver.Constructors[0].name}}<br/> Birth: {{driver.Driver.dateOfBirth}}<br/> <a href="{{driver.Driver.url}}" target="_blank">Biography</a> </div> </nav>

partials/drivers.html

<div class="main-content"> <table class="result-table"> <thead> <tr><th colspan="5">Formula 1 2013 Results</th></tr> </thead> <tbody> <tr> <td>Round</td> <td>Grand Prix</td> <td>Team</td> <td>Grid</td> <td>Race</td> </tr> <tr ng-repeat="race in races"> <td>{{race.round}}</td> <td><img src="img/flags/{{race.Circuit.Location.country}}.png" />{{race.raceName}}</td> <td>{{race.Results[0].Constructor.name}}</td> <td>{{race.Results[0].grid}}</td> <td>{{race.Results[0].position}}</td> </tr> </tbody> </table> </div></section>

Finish

Conclusion• We have a simple app• Angular is a very powerful framework and we’ve barely scratched the surface

• Check Part 2 of this tutorial• Why and where Angular stands out • Writing and running unit tests with Karma• Integration with Yeomen, Grunt, and Bower• Other strengths of this fantastic front-end framework

About the Author

Raoni Boaventura, BrazilRaoni is an experienced software developer and who has contributed to a wealth of projects using Ruby on Rails, JavaScript, and PHP on top of many other programming languages and frameworks. He is an excellent problem solver, and a great communicator as both a team member and a team lead.

MEMBER SINCE March 9, 2012

Bonus Materials

Send a quick email to: [email protected]

• Source code of the sample project• Audio MP3 file to listen on the go• PPT slide deck• PDF file• Original blog post