AngularJS & SPA Lorenzo Dematte' For 33Dev @ Muse
Jan 15, 2015
AngularJS & SPA
Lorenzo Dematte'For 33Dev @ Muse
A) server-side generator, “forms” like (aspx, Jsp/Jsf)B) server-side templating (Haml, Mustache, Smarty)C) server-side MVC frameworksD) jQueryE) Another Javascript framework
A= ?? B = ?? C = ?? D = ?? E = ??
What are you using to build web applications?
(the only image in this slide set. Now we can move on..)
What is AngularJS?
A complete framework for rich SPA applications
What is a SPA?
● Single Page Application● Client side (with server-side help)● Rich, responsive, fast● Desktop-like experience● “Like the big ones” (Twitter, FB, Gmail)
SPA technically
● HTML5 + JS● Service● More likely:
– An MVC/MVVM client framework– Lightweight REST/Json service(s)
● Even Json non-relational DBs!
DOM Manipulation
● It' central● But... Angular hides it!
AngularJS vs. jQuery
● Don't design your page, and then change it with DOM manipulations
● The view is the "official record"● → Data binding
– The “Angular” way
<!DOCTYPE html><html data-ng-app="myapp"><head>
<title>Foo Car rental</title> <script src="scripts/jquery-1.9.1.min.js"></script>
<script src="scripts/angular.min.js"></script><script src="scripts/myapp.js"></script>
<body> ... Name: <input type=”text” ng-model=”name” /> {{ name }}
1: Directives and data-binding
Demo one
More directives: ng-repeat, expression, filters
<div ng-init="friends = [ {name:'John', age:25, gender:'boy'}, {name:'Jessie', age:30, gender:'girl'}, {name:'Johanna', age:28, gender:'girl'}, {name:'Joy', age:15, gender:'girl'}, {name:'Mary', age:28, gender:'girl'}, {name:'Peter', age:95, gender:'boy'}, {name:'Sebastian', age:50, gender:'boy'}, {name:'Erika', age:27, gender:'girl'}, {name:'Patrick', age:40, gender:'boy'}, {name:'Samantha', age:60, gender:'girl'} ]"> I have {{friends.length}} friends. They are: <input type="search" ng-model="q" placeholder="filter friends..." /> <ul class="example-animate-container"> <li class="animate-repeat" ng-repeat="friend in friends | filter:q"> [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old. </li> </ul> </div>
Demo two
Filters
<div>{{ 12345.67 | currency }}</div>
<div>{{ 1288323623006 | date:"mediumDate" }}</div>
<ul ng-repeat="r in result.results | orderBy:sortBy">
<ul ng-repeat="r in result.results | filter:searchTerm | limitTo:10” >
(custom filters)
app.filter("orru", function(){ return function(text, length){ return text; // Do nothing }});
Demo three
2: Views, Controller, Scope
View Data
2: Views, Controller, Scope
View Data
Html Javascript objects/JSON/something remote
2: Views, Controller, Scope
View Data
Html Javascript objects/JSON/something remote
2: Views, Controller, Scope
ViewData
(Model)
ViewModel
(bi-directional)binding
2: Views, Controller, Scope
ViewData
(Model)
Controller
Update(query)
Input(select)
2: Views, Controller, Scope
ViewData
(Model)
$scope
(bi-directional)binding
Controller
Controllers
<!DOCTYPE html><html data-ng-app="myapp"><head>
<title>Foo Car rental</title> <script src="scripts/jquery-1.9.1.min.js"></script>
<script src="scripts/angular.min.js"></script><script src="scripts/myapp.js"></script>
<body><div class="container-narrow">
<div data-ng-controller="SomeController"><div class="masthead" data-ng-show="showNavigation()">
... Name: <input type=”text” ng-model=”name” /> {{ name }}
Controllers
var myApp = angular.module("myApp", []);
myApp.controller('SomeController', function ($scope, someService) {
$scope.name = “Pippo”;
$scope.showNavigation = function() { if (pathUnder("/login") || pathUnder("/registration")) return false; else return true;};
});
Demo four
3: Modules, routes, factories/services
Modules and dependency injection
var myApp = angular.module("myApp", []);
myApp.controller('SomeController', function ($scope, someService) {
$scope.name = “Pippo”;
$scope.showNavigation = function() { if (pathUnder("/login") || pathUnder("/registration")) return false; else return true;};
});
???
RoutesApp.config(function ($routeProvider) {
$routeProvider.when('/', {
controller: 'HomeController', templateUrl: 'partials/home.html'
}).when('/user-info', {
controller: 'UserController', templateUrl: 'partials/user-info.html'
}).when('/login', { controller: 'LoginController',
templateUrl: 'partials/login.html'}).when('/registration', { controller: 'LoginController',
templateUrl: 'partials/registration.html'}).when('/invalid-server-response', { controller: 'UserController',
templateUrl: 'partials/invalid-server-response.html'}).when('/error', { controller: 'UserController',
templateUrl: 'partials/error.html'}).otherwise({ redirectTo: '/' });
});
Routes and views
<div data-ng-view=""></div>
“Partials”
Servicesangular.module("MiniResources", [], ["$provide", function($provide) { $provide.value("miniResources", { nameRequired : "E' necessario specificare un nome",
fieldAdded: "Campo aggiunto con successo",emptyField: "<vuoto>",startFlowQuestion: "Sei sicuro di voler cominicare un flusso",startFlow: "Comincia un nuovo flusso",yes: "Si",no: "No",back: "Torna indietro",all: "Tutti",processing: "Sto elaborando",error: "Errore",close: "Chiudi"
});}]);
Service usage
● They are injected!
miniApp.controller("StepController", function ($scope, …, miniResources)
Demo five
4: Custom directivesapp.directive('ngContent', function ($parse) { return { restrict: 'A', require: '?ngModel', link: function (scope, element, attrs) { if (attrs.ngModel && element.text()) { $parse(attrs.ngModel).assign(scope, element.text()); } scope.$watch(attrs.ngModel, function(value) { element.text(value); }); } };});
Where?
require: '^parentDirective' will give you access to the parentDirective
^ -- Look for the controller on parent elements, not just on the local scope? -- Don't raise an error if the controller isn't found
Demo six
5: UI
UI elements in Angular<h4>Static arrays</h4> <pre>Model: {{selected | json}}</pre> <input type="text" ng-model="selected" typeahead="state for state in states | filter:$viewValue | limitTo:8" class="form-control">
<h4>Asynchronous results</h4> <pre>Model: {{asyncSelected | json}}</pre> <input type="text" ng-model="asyncSelected" placeholder="Locations loaded via $http" typeahead="address for address in getLocation($viewValue) | filter:$viewValue" typeahead-loading="loadingLocations" class="form-control">
Demo seven
...but... in the real world?
● #1: Javascript vs. “Security through obscurity” (F12 - but it is actually good because...)
● #2: you have to design a SPA keeping #1 in mind
● #3: SPA are almost never “single page”● #4: HTTPS and/or OAuth!
In the real world...
● You almost always “blur” the lines– Server-side generation AND client-side rendering– Multiple pages for multiple roles– Use your server!
Thank you!