SlideShare une entreprise Scribd logo
1  sur  64
Télécharger pour lire hors ligne
The Art of
Matt Raible • http://raibledesigns.com
Photos by
Modern Principles in Web Development
Design for mobile first (even if you’re
not building a mobile app)

Build only single page apps

Create and use your own REST API

“Sex sells” applies to web apps

© 2014 Raible Designs
Jobs on Dice.com
February 2014
500

375

250

125

© 2014 Raible Designs

ut
ko
oc
Kn

be
r
Em

lar
gu
An

Ba

ck

bo
n

e

0
LinkedIn Skills
February 2014
30,000

22,500

15,000

7,500

© 2014 Raible Designs

be
r
Em

ut
ko
oc
Kn

lar
gu
An

Ba

ck

bo
n

e

0
Google Trends

© 2014 Raible Designs
Indeed Job Trends

Absolute
Relative
© 2014 Raible Designs
Stack Overflow

© 2014 Raible Designs
Who wants to learn

© 2014 Raible Designs

?
The History of AngularJS
Started by Miško Hevery in 2009

GWT = 3 developers, 6 months

AngularJS = 1 developer, 3 weeks

Learn more:

https://www.youtube.com/watch?v=X0VsStcCCM8

© 2014 Raible Designs
The History of AngularJS
AngularJS

GWT

18000

17,000
13500
9000
4500
0

1,000

Lines of Code

© 2014 Raible Designs
Hello World
<!doctype html>
<html ng-app>
<head>
<title>Hello World</title>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" ng-model="name" placeholder="Enter a name here">
<hr>
<h1>Hello {{name}}!</h1>
</div>
<script src="http://code.angularjs.org/1.2.13/angular.min.js"></script>
</body>
</html>

© 2014 Raible Designs
Architecture Principles

Boilerplate

Structure

D.R.Y.
Testability
© 2014 Raible Designs
Code Organization
Start with Angular Seed*

!

git clone https://github.com/angular/angular-seed.git

!
!
!

* more options to be discussed later…
© 2014 Raible Designs
App Definition
var app = angular.module('myApp', []);

<!DOCTYPE html>
<html ng-app="myApp">

© 2014 Raible Designs
App Definition with separate files
app.js

!
!

angular.module('myApp', ['ngRoute',
'myApp.filters',
'myApp.services',
'myApp.directives',
'myApp.controllers'
])

controllers.js
angular.module('myApp.controllers', []).
controller('MyCtrl1', [function() {
!
}])

© 2014 Raible Designs
Model View Controller

© 2014 Raible Designs
Data Binding
friend.js

!

$scope.friend = {
name: "Fernand"
};

!

friend.html

{{friend.name}}
// 1-way
<input ng-model="friend.name"> // 2-way

© 2014 Raible Designs
Solving FOUC
This will work just fine — if it’s not on the first page:

!

<p>{{friend.name}}</p>

Use ng-cloak or ng-bind attribute:

<p ng-cloak>{{friend.name}}</p>
!
<p ng-bind="friend.name"></p>

© 2014 Raible Designs
Directives
<div ng-repeat="entry in news.entries">
<span ng-bind="entry.title"></span>
<button ng-click="delete($index)">
Delete
</button>
</div>

© 2014 Raible Designs
Directives with valid HTML5
<div data-ng-repeat="entry in news.entries">
<span data-ng-bind="entry.title"></span>
<button data-ng-click="delete($index)">
Delete
</button>
</div>
<div data-ng:repeat="entry in news.entries">
<span data-ng:bind="entry.title"></span>
<button data-ng:click="delete($index)">
Delete
</button>
</div>

© 2014 Raible Designs
Custom Directives
$scope.customer = {
name: 'Franklin',
address: '1830 Blake'
};
<div ng-controller="MyController">
<my-customer></my-customer>
</div>

.directive('myCustomer', function() {
return {
template: 'Name: {{customer.name}} 
Address: {{customer.address}}'
};
});

© 2014 Raible Designs
Built-In Directives
ng-href


ng-selected


ng-src


ng-class


ng-disabled


ng-style


ng-checked


!

ng-readonly


© 2014 Raible Designs
Services
var services = angular.module('myApp.services', ['ngResource']);
!
services.factory('LoginService', function($resource) {
return $resource(':action', {}, {
authenticate: {
method: 'POST',
params: {'action': 'authenticate'},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}
}
);
});
!
services.factory('NewsService', function($resource) {
return $resource('news/:id', {id: '@id'});
});

© 2014 Raible Designs
$http
$http({method: 'GET', url: '/news'}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});

$http.get('/news').success(successCallback);
$http.post('/news', data).success(successCallback);

© 2014 Raible Designs
$q
myApp.factory('HelloWorld', function($q, $timeout) {
!
var getMessages = function() {
var deferred = $q.defer();
!
$timeout(function() {
deferred.resolve(['Hello', 'world!']);
}, 2000);
!
return deferred.promise;
};
!
return {
getMessages: getMessages
};
});
© 2014 Raible Designs
$q
myApp.controller('HelloCtrl', function($scope, HelloWorld) {
!
HelloWorld.getMessages().then(function(messages) {
$scope.messages = messages;
});
!
});

© 2014 Raible Designs
Dependency Injection
.controller('LoginController', function($scope, $rootScope, $location,
$http, $cookieStore, LoginService) {
$scope.login = function () {
LoginService.authenticate($.param({username: $scope.username, 

password: $scope.password}),
function (user) {
$rootScope.user = user;
$http.defaults.headers.common[xAuthTokenHeaderName] = user.token;
$cookieStore.put('user', user);
$location.path("/");
});
};
})

© 2014 Raible Designs
Filters
!
!
!
!

{{ name | uppercase }}
!
<!-- Displays: 123.46 -->
{{ 123.456789 | number:2 }}
!
<!-- In en-US locale, '$1000.00' will be shown -->
{{ 1000 | currency }}
!
<!-- all of the words with e in them ["Lerner","Likes","Eat"] -->
{{ ['Ari', 'Lerner', 'Likes', 'To', 'Eat', 'Pizza'] | filter:'e' }}

!

also: lowercase, limitTo, orderBy
© 2014 Raible Designs
Routes
.config(['$routeProvider', '$locationProvider', '$httpProvider',
function ($routeProvider, $locationProvider, $httpProvider) {
$routeProvider.when('/create', {
templateUrl: 'partials/create.html', controller: 'CreateController'
});
$routeProvider.when('/edit/:id', {
templateUrl: 'partials/edit.html', controller: 'EditController'
});
$routeProvider.when('/login', {
templateUrl: 'partials/login.html', controller: 'LoginController'
});
$routeProvider.otherwise({
templateUrl: 'partials/index.html', controller: 'IndexController'
});
!
$locationProvider.hashPrefix('!');
}]
)
© 2014 Raible Designs
Routing: Navigation
$rootScope.logout = function () {
delete $rootScope.user;
delete $http.defaults.headers.common[xAuthTokenHeaderName];
$cookieStore.remove('user');
$location.path("/login");
};

© 2014 Raible Designs
Routing: Navigation
$rootScope.logout = function () {
delete $rootScope.user;
delete $http.defaults.headers.common[xAuthTokenHeaderName];
$cookieStore.remove('user');
$location.path("/login");
};

© 2014 Raible Designs
Code Organization Revisited
Lineman helps you build fat-client JavaScript apps

It produces happiness by building assets, mocking servers, and running
specs on every file change
git clone https://github.com/linemanjs/lineman-angular-template.git my-app
cd my-app
sudo npm install -g lineman
npm install
lineman run

© 2014 Raible Designs
Google's Recommendations for Angular App Structure
Testing
Testem - test runner, framework agnostic

Jasmine - unit tests, framework agnostic

Protractor - integration tests, angular specific

Lineman - productivity, framework agnostic

© 2014 Raible Designs
Testing: Controllers
describe("controller: LoginController", function() {
!
beforeEach(function() {
module("app");
});
!
beforeEach(inject(function($controller, $rootScope, $location,
AuthenticationService, $httpBackend) {
this.$location = $location;
this.$httpBackend = $httpBackend;
this.scope = $rootScope.$new();
this.redirect = spyOn($location, 'path');
$controller('LoginController', {
$scope: this.scope,
$location: $location,
AuthenticationService: AuthenticationService
});
}));
© 2014 Raible Designs
Testing: Controllers
afterEach(function() {
this.$httpBackend.verifyNoOutstandingRequest();
this.$httpBackend.verifyNoOutstandingExpectation();
});

!

describe("successfully logging in", function() {
it("should redirect you to /home", function() {
this.$httpBackend.expectPOST('/login',
this.scope.credentials).respond(200);
this.scope.login();
this.$httpBackend.flush();
expect(this.redirect).toHaveBeenCalledWith('/home');
});
});

});

© 2014 Raible Designs
Testing: Directives
beforeEach(inject(function($rootScope, $compile) {
this.directiveMessage = 'ralph was here';
this.html = "<div shows-message-when-hovered message='"
+ this.directiveMessage + "'></div>";
this.scope = $rootScope.$new();
this.scope.message = this.originalMessage = 'things are looking grim';
this.elem = $compile(this.html)(this.scope);
}));
!
describe("when a user mouses over the element", function() {
it("sets the message on the scope to the message attribute", function() {
this.elem.triggerHandler('mouseenter');
expect(this.scope.message).toBe(this.directiveMessage);
});
});

© 2014 Raible Designs
Testing: Directives with CoffeeScript
describe "directive: shows-message-when-hovered (coffeescript)", ->
!
Given -> module("app")
!
Given inject ($rootScope, $compile) ->
@directiveMessage = 'ralph was here'
@html = "<div shows-message-when-hovered
message='#{@directiveMessage}'></div>"
@scope = $rootScope.$new()
@scope.message = @originalMessage = 'things are looking grim'
@elem = $compile(@html)(@scope)
!
describe "when a user mouses over the element", ->
When -> @elem.triggerHandler('mouseenter')
Then "the message on the scope is set to the message attribute", ->
@scope.message == @directiveMessage

© 2014 Raible Designs
Testing: End-to-End
protractor = require("protractor")
require "protractor/jasminewd"
require 'jasmine-given'

!

describe "my angular app", ->
ptor = protractor.getInstance()
describe "visiting the login page", ->
Given -> ptor.get "/"

!

describe "when a user logs in", ->
Given -> ptor.findElement(protractor.By.input("credentials.username")).sendKeys "Ralph"
Given -> ptor.findElement(protractor.By.input("credentials.password")).sendKeys "Wiggum"
When -> ptor.findElement(protractor.By.id("log-in")).click()
Then -> ptor.findElement(protractor.By.binding("{{ message }}")).getText().then (text) ->
expect(text).toEqual "Mouse Over these images to see a directive at work"

© 2014 Raible Designs
Building with Grunt
sudo npm install
!
sudo npm install -g grunt-cli
!
vi package.json
!
"grunt": "~0.4.1",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-uglify": "~0.2.7",
"grunt-contrib-cssmin": "~0.7.0",
"grunt-usemin": "~2.0.2",
"grunt-contrib-copy": "~0.5.0",
"grunt-rev": "~0.1.0",
"grunt-contrib-clean": "~0.5.0",
"matchdep": "~0.3.0"

© 2014 Raible Designs
Gruntfile.js
module.exports = function (grunt) {

!
!
!

!

grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
clean: ["dist", '.tmp'],
copy: {
main: {
expand: true,
cwd: 'app/',
src: ['**', '!js/**', '!lib/**', '!**/*.css'],
dest: 'dist/'
}
},
rev: {
files: {
src: ['dist/**/*.{js,css}']
}
},
© 2014 Raible Designs
Gruntfile.js
!

useminPrepare: {
html: 'app/index.html'
},

!

usemin: {
html: ['dist/index.html']
},

!

uglify: {
options: {
report: 'min',
mangle: false
}
}
});

!
© 2014 Raible Designs
Gruntfile.js
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

!

// Tell Grunt what to do when we type "grunt" into the terminal
grunt.registerTask('default', [
'copy', 'useminPrepare', 'concat', 'uglify', 'cssmin', 'rev', 'usemin'
]);

};

© 2014 Raible Designs
index.html comments
<head>
<title>My AngularJS App</title>
<!-- build:css css/seed.min.css -->
<link rel="stylesheet" href="css/app.css"/>
<link rel="stylesheet" href="css/app2.css"/>
<!-- endbuild -->
</head>
<body>
<!-- build:js js/seed.min.js -->
<script src="lib/angular/angular.js"></script>
<script src="lib/angular/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/services.js"></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>
<script src="js/directives.js"></script>
<!-- endbuild -->
</body>
© 2014 Raible Designs
dist/index.html
<head>
<title>My AngularJS App</title>
<link rel="stylesheet" href="css/f050d0dc.seed.min.css"/>
</head>
<body>
!
<script src="js/8973cf0f.seed.min.js"></script>
</body>

© 2014 Raible Designs
After Grunt

http://raibledesigns.com/rd/entry/using_grunt_with_angularjs_for

© 2014 Raible Designs
You shouldn’t have to worry about FEO

http://raibledesigns.com/rd/entry/you_shouldn_t_have_to
© 2014 Raible Designs
HTTP/2 Performance Anti-Patterns?
Split dominant content domains

Reduce requests

	 Merging

	 Sprites

	 DataURIs
http://www.slideshare.net/andydavies
© 2014 Raible Designs
CloudBees

© 2014 Raible Designs
UI Bootstrap

http://angular-ui.github.io/bootstrap

<script src="lib/angular/ui-bootstrap-0.10.0.min.js"></script>
<script src="lib/angular/ui-bootstrap-tpls-0.10.0.min.js"></script>
angular.module('myApp', ['ui.bootstrap']);

© 2014 Raible Designs
Ionic Framework

http://ionicframework.com

© 2014 Raible Designs
AngularJS Batarang

© 2014 Raible Designs
My Experience
Developing with AngularJS Series

Part I: The Basics

Part II: Dialogs and Data

Part III: Services

Part IV: Making it Pop


© 2014 Raible Designs
My Experience

http://vimeo.com/mraible/angularjs-deep-dive

#dv13javaweb$

© 2014 Raible Designs
How to Become an Artist
Part 1 of 3: Learn the Basics on Your Own

Take some time and try various mediums of art

Recognize your strengths

Do your research and learn the basics

Get the supplies you will need

Observe the world around you

Make time for your art every day

Seek out the opinions of others

Develop your own style

http://www.wikihow.com/Become-an-Artist
© 2014 Raible Designs
Shortcut to becoming an Angular Artist

JUST DO IT.
© 2014 Raible Designs
Questions?
Contact Me!

http://raibledesigns.com

@mraible


Presentations

http://slideshare.net/mraible


Code

http://github.com/mraible
© 2014 Raible Designs
Who to follow on Twitter
AngularJS Team at Google


Web Performance


	 Miško Hevery - @mhevery


	 Ilya Grigorik - @igrigorik


	 Igor Minar - @IgorMinar


	 Andy Davis - @andydavies


	 Brian Ford - @briantford


	 Steve Souders - @Souders


!

© 2014 Raible Designs
Resources
Angular Dart

	 https://angulardart.org 

Devoxx AngularJS Talks on Parleys.com 

http://parleys.com/play/5148922b0364bc17fc56c91b (2012)

http://parleys.com/play/529321a5e4b054cd7d2ef4e1 (2013)

Egghead.io - https://egghead.io/
© 2014 Raible Designs
Code
Angular Seed

https://github.com/angular/angular-seed 

Lineman Application Template using AngularJS

	 https://github.com/linemanjs/lineman-angular-template

AngularJS + Rest + Spring Security

	 https://github.com/joshlong/boot-examples/tree/master/x-auth-security
© 2014 Raible Designs

Contenu connexe

Tendances

Single Page WebApp Architecture
Single Page WebApp ArchitectureSingle Page WebApp Architecture
Single Page WebApp Architecture
Morgan Cheng
 
multiple views and routing
multiple views and routingmultiple views and routing
multiple views and routing
Brajesh Yadav
 

Tendances (20)

AngularJS Best Practices
AngularJS Best PracticesAngularJS Best Practices
AngularJS Best Practices
 
AngularJS - What is it & Why is it awesome ? (with demos)
AngularJS - What is it & Why is it awesome ? (with demos)AngularJS - What is it & Why is it awesome ? (with demos)
AngularJS - What is it & Why is it awesome ? (with demos)
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJS
 
Why angular js Framework
Why angular js Framework Why angular js Framework
Why angular js Framework
 
Advanced Tips & Tricks for using Angular JS
Advanced Tips & Tricks for using Angular JSAdvanced Tips & Tricks for using Angular JS
Advanced Tips & Tricks for using Angular JS
 
Introduction to AJAX In WordPress
Introduction to AJAX In WordPressIntroduction to AJAX In WordPress
Introduction to AJAX In WordPress
 
AngularJS - The Next Big Thing?
AngularJS - The Next Big Thing?AngularJS - The Next Big Thing?
AngularJS - The Next Big Thing?
 
AngularJS Basics
AngularJS BasicsAngularJS Basics
AngularJS Basics
 
Single Page WebApp Architecture
Single Page WebApp ArchitectureSingle Page WebApp Architecture
Single Page WebApp Architecture
 
AngularJS application architecture
AngularJS application architectureAngularJS application architecture
AngularJS application architecture
 
Single Page Applications in SharePoint with Angular
Single Page Applications in SharePoint with AngularSingle Page Applications in SharePoint with Angular
Single Page Applications in SharePoint with Angular
 
Angular js for beginners
Angular js for beginnersAngular js for beginners
Angular js for beginners
 
Angular Best Practices v2
Angular Best Practices v2Angular Best Practices v2
Angular Best Practices v2
 
AngularJS with RequireJS
AngularJS with RequireJSAngularJS with RequireJS
AngularJS with RequireJS
 
AngularJS Basics and Best Practices - CC FE &UX
AngularJS Basics and Best Practices - CC FE &UXAngularJS Basics and Best Practices - CC FE &UX
AngularJS Basics and Best Practices - CC FE &UX
 
AngularJS intro
AngularJS introAngularJS intro
AngularJS intro
 
Angular js PPT
Angular js PPTAngular js PPT
Angular js PPT
 
Angular js
Angular jsAngular js
Angular js
 
Introduction to Angularjs
Introduction to AngularjsIntroduction to Angularjs
Introduction to Angularjs
 
multiple views and routing
multiple views and routingmultiple views and routing
multiple views and routing
 

Similaire à The Art of AngularJS - DeRailed 2014

Similaire à The Art of AngularJS - DeRailed 2014 (20)

AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJSAngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
 
ASP.NET MVC, AngularJS CRUD for Azerbaijan Technical University
ASP.NET MVC, AngularJS CRUD for Azerbaijan Technical UniversityASP.NET MVC, AngularJS CRUD for Azerbaijan Technical University
ASP.NET MVC, AngularJS CRUD for Azerbaijan Technical University
 
Mean stack Magics
Mean stack MagicsMean stack Magics
Mean stack Magics
 
Mini-Training: AngularJS
Mini-Training: AngularJSMini-Training: AngularJS
Mini-Training: AngularJS
 
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
 
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
I Know It Was MEAN, But I Cut the Cord to LAMP AnywayI Know It Was MEAN, But I Cut the Cord to LAMP Anyway
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
 
Ruby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter BootstrapRuby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter Bootstrap
 
Angular data binding by Soft Solutions4U
Angular data binding by Soft Solutions4UAngular data binding by Soft Solutions4U
Angular data binding by Soft Solutions4U
 
Efektivni vyvoj webovych aplikaci v Ruby on Rails (Webexpo)
Efektivni vyvoj webovych aplikaci v Ruby on Rails (Webexpo)Efektivni vyvoj webovych aplikaci v Ruby on Rails (Webexpo)
Efektivni vyvoj webovych aplikaci v Ruby on Rails (Webexpo)
 
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
I Know It Was MEAN, But I Cut the Cord to LAMP AnywayI Know It Was MEAN, But I Cut the Cord to LAMP Anyway
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
 
SF Cordova Meetup
SF Cordova MeetupSF Cordova Meetup
SF Cordova Meetup
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJS
 
The Modern Java Web Developer - JavaOne 2013
The Modern Java Web Developer - JavaOne 2013The Modern Java Web Developer - JavaOne 2013
The Modern Java Web Developer - JavaOne 2013
 
Drupalcon Mumbai
Drupalcon MumbaiDrupalcon Mumbai
Drupalcon Mumbai
 
From Backbone to Ember and Back(bone) Again
From Backbone to Ember and Back(bone) AgainFrom Backbone to Ember and Back(bone) Again
From Backbone to Ember and Back(bone) Again
 
Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics
 
React Native Workshop
React Native WorkshopReact Native Workshop
React Native Workshop
 
CFUGbe talk about Angular JS
CFUGbe talk about Angular JSCFUGbe talk about Angular JS
CFUGbe talk about Angular JS
 
Node.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java sideNode.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java side
 
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 -  Fullstack end-to-end Test Automation with node.jsForwardJS 2017 -  Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
 

Plus de Matt Raible

Plus de Matt Raible (20)

Keep Identities in Sync the SCIMple Way - ApacheCon NA 2022
Keep Identities in Sync the SCIMple Way - ApacheCon NA 2022Keep Identities in Sync the SCIMple Way - ApacheCon NA 2022
Keep Identities in Sync the SCIMple Way - ApacheCon NA 2022
 
Micro Frontends for Java Microservices - Belfast JUG 2022
Micro Frontends for Java Microservices - Belfast JUG 2022Micro Frontends for Java Microservices - Belfast JUG 2022
Micro Frontends for Java Microservices - Belfast JUG 2022
 
Micro Frontends for Java Microservices - Dublin JUG 2022
Micro Frontends for Java Microservices - Dublin JUG 2022Micro Frontends for Java Microservices - Dublin JUG 2022
Micro Frontends for Java Microservices - Dublin JUG 2022
 
Micro Frontends for Java Microservices - Cork JUG 2022
Micro Frontends for Java Microservices - Cork JUG 2022Micro Frontends for Java Microservices - Cork JUG 2022
Micro Frontends for Java Microservices - Cork JUG 2022
 
Comparing Native Java REST API Frameworks - Seattle JUG 2022
Comparing Native Java REST API Frameworks - Seattle JUG 2022Comparing Native Java REST API Frameworks - Seattle JUG 2022
Comparing Native Java REST API Frameworks - Seattle JUG 2022
 
Reactive Java Microservices with Spring Boot and JHipster - Spring I/O 2022
Reactive Java Microservices with Spring Boot and JHipster - Spring I/O 2022Reactive Java Microservices with Spring Boot and JHipster - Spring I/O 2022
Reactive Java Microservices with Spring Boot and JHipster - Spring I/O 2022
 
Comparing Native Java REST API Frameworks - Devoxx France 2022
Comparing Native Java REST API Frameworks - Devoxx France 2022Comparing Native Java REST API Frameworks - Devoxx France 2022
Comparing Native Java REST API Frameworks - Devoxx France 2022
 
Lock That Sh*t Down! Auth Security Patterns for Apps, APIs, and Infra - Devne...
Lock That Sh*t Down! Auth Security Patterns for Apps, APIs, and Infra - Devne...Lock That Sh*t Down! Auth Security Patterns for Apps, APIs, and Infra - Devne...
Lock That Sh*t Down! Auth Security Patterns for Apps, APIs, and Infra - Devne...
 
Native Java with Spring Boot and JHipster - Garden State JUG 2021
Native Java with Spring Boot and JHipster - Garden State JUG 2021Native Java with Spring Boot and JHipster - Garden State JUG 2021
Native Java with Spring Boot and JHipster - Garden State JUG 2021
 
Java REST API Framework Comparison - PWX 2021
Java REST API Framework Comparison - PWX 2021Java REST API Framework Comparison - PWX 2021
Java REST API Framework Comparison - PWX 2021
 
Web App Security for Java Developers - PWX 2021
Web App Security for Java Developers - PWX 2021Web App Security for Java Developers - PWX 2021
Web App Security for Java Developers - PWX 2021
 
Mobile App Development with Ionic, React Native, and JHipster - Connect.Tech ...
Mobile App Development with Ionic, React Native, and JHipster - Connect.Tech ...Mobile App Development with Ionic, React Native, and JHipster - Connect.Tech ...
Mobile App Development with Ionic, React Native, and JHipster - Connect.Tech ...
 
Lock That Shit Down! Auth Security Patterns for Apps, APIs, and Infra - Joker...
Lock That Shit Down! Auth Security Patterns for Apps, APIs, and Infra - Joker...Lock That Shit Down! Auth Security Patterns for Apps, APIs, and Infra - Joker...
Lock That Shit Down! Auth Security Patterns for Apps, APIs, and Infra - Joker...
 
Web App Security for Java Developers - UberConf 2021
Web App Security for Java Developers - UberConf 2021Web App Security for Java Developers - UberConf 2021
Web App Security for Java Developers - UberConf 2021
 
Java REST API Framework Comparison - UberConf 2021
Java REST API Framework Comparison - UberConf 2021Java REST API Framework Comparison - UberConf 2021
Java REST API Framework Comparison - UberConf 2021
 
Native Java with Spring Boot and JHipster - SF JUG 2021
Native Java with Spring Boot and JHipster - SF JUG 2021Native Java with Spring Boot and JHipster - SF JUG 2021
Native Java with Spring Boot and JHipster - SF JUG 2021
 
Lock That Shit Down! Auth Security Patterns for Apps, APIs, and Infra - Sprin...
Lock That Shit Down! Auth Security Patterns for Apps, APIs, and Infra - Sprin...Lock That Shit Down! Auth Security Patterns for Apps, APIs, and Infra - Sprin...
Lock That Shit Down! Auth Security Patterns for Apps, APIs, and Infra - Sprin...
 
Reactive Java Microservices with Spring Boot and JHipster - Denver JUG 2021
Reactive Java Microservices with Spring Boot and JHipster - Denver JUG 2021Reactive Java Microservices with Spring Boot and JHipster - Denver JUG 2021
Reactive Java Microservices with Spring Boot and JHipster - Denver JUG 2021
 
Get Hip with JHipster - Colorado Springs Open Source User Group 2021
Get Hip with JHipster - Colorado Springs Open Source User Group 2021Get Hip with JHipster - Colorado Springs Open Source User Group 2021
Get Hip with JHipster - Colorado Springs Open Source User Group 2021
 
JHipster and Okta - JHipster Virtual Meetup December 2020
JHipster and Okta - JHipster Virtual Meetup December 2020JHipster and Okta - JHipster Virtual Meetup December 2020
JHipster and Okta - JHipster Virtual Meetup December 2020
 

Dernier

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Dernier (20)

Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 

The Art of AngularJS - DeRailed 2014

  • 1. The Art of Matt Raible • http://raibledesigns.com Photos by
  • 2. Modern Principles in Web Development Design for mobile first (even if you’re not building a mobile app) Build only single page apps Create and use your own REST API “Sex sells” applies to web apps © 2014 Raible Designs
  • 3.
  • 4. Jobs on Dice.com February 2014 500 375 250 125 © 2014 Raible Designs ut ko oc Kn be r Em lar gu An Ba ck bo n e 0
  • 5. LinkedIn Skills February 2014 30,000 22,500 15,000 7,500 © 2014 Raible Designs be r Em ut ko oc Kn lar gu An Ba ck bo n e 0
  • 6. Google Trends © 2014 Raible Designs
  • 8. Stack Overflow © 2014 Raible Designs
  • 9. Who wants to learn © 2014 Raible Designs ?
  • 10. The History of AngularJS Started by Miško Hevery in 2009 GWT = 3 developers, 6 months AngularJS = 1 developer, 3 weeks Learn more: https://www.youtube.com/watch?v=X0VsStcCCM8 © 2014 Raible Designs
  • 11. The History of AngularJS AngularJS GWT 18000 17,000 13500 9000 4500 0 1,000 Lines of Code © 2014 Raible Designs
  • 12. Hello World <!doctype html> <html ng-app> <head> <title>Hello World</title> </head> <body> <div> <label>Name:</label> <input type="text" ng-model="name" placeholder="Enter a name here"> <hr> <h1>Hello {{name}}!</h1> </div> <script src="http://code.angularjs.org/1.2.13/angular.min.js"></script> </body> </html> © 2014 Raible Designs
  • 14. Code Organization Start with Angular Seed* ! git clone https://github.com/angular/angular-seed.git ! ! ! * more options to be discussed later… © 2014 Raible Designs
  • 15. App Definition var app = angular.module('myApp', []); <!DOCTYPE html> <html ng-app="myApp"> © 2014 Raible Designs
  • 16. App Definition with separate files app.js ! ! angular.module('myApp', ['ngRoute', 'myApp.filters', 'myApp.services', 'myApp.directives', 'myApp.controllers' ]) controllers.js angular.module('myApp.controllers', []). controller('MyCtrl1', [function() { ! }]) © 2014 Raible Designs
  • 17. Model View Controller © 2014 Raible Designs
  • 18. Data Binding friend.js ! $scope.friend = { name: "Fernand" }; ! friend.html {{friend.name}} // 1-way <input ng-model="friend.name"> // 2-way © 2014 Raible Designs
  • 19. Solving FOUC This will work just fine — if it’s not on the first page: ! <p>{{friend.name}}</p> Use ng-cloak or ng-bind attribute: <p ng-cloak>{{friend.name}}</p> ! <p ng-bind="friend.name"></p> © 2014 Raible Designs
  • 20. Directives <div ng-repeat="entry in news.entries"> <span ng-bind="entry.title"></span> <button ng-click="delete($index)"> Delete </button> </div> © 2014 Raible Designs
  • 21. Directives with valid HTML5 <div data-ng-repeat="entry in news.entries"> <span data-ng-bind="entry.title"></span> <button data-ng-click="delete($index)"> Delete </button> </div> <div data-ng:repeat="entry in news.entries"> <span data-ng:bind="entry.title"></span> <button data-ng:click="delete($index)"> Delete </button> </div> © 2014 Raible Designs
  • 22. Custom Directives $scope.customer = { name: 'Franklin', address: '1830 Blake' }; <div ng-controller="MyController"> <my-customer></my-customer> </div> .directive('myCustomer', function() { return { template: 'Name: {{customer.name}} Address: {{customer.address}}' }; }); © 2014 Raible Designs
  • 24. Services var services = angular.module('myApp.services', ['ngResource']); ! services.factory('LoginService', function($resource) { return $resource(':action', {}, { authenticate: { method: 'POST', params: {'action': 'authenticate'}, headers: {'Content-Type': 'application/x-www-form-urlencoded'} } } ); }); ! services.factory('NewsService', function($resource) { return $resource('news/:id', {id: '@id'}); }); © 2014 Raible Designs
  • 25. $http $http({method: 'GET', url: '/news'}). success(function(data, status, headers, config) { // this callback will be called asynchronously // when the response is available }). error(function(data, status, headers, config) { // called asynchronously if an error occurs // or server returns response with an error status. }); $http.get('/news').success(successCallback); $http.post('/news', data).success(successCallback); © 2014 Raible Designs
  • 26. $q myApp.factory('HelloWorld', function($q, $timeout) { ! var getMessages = function() { var deferred = $q.defer(); ! $timeout(function() { deferred.resolve(['Hello', 'world!']); }, 2000); ! return deferred.promise; }; ! return { getMessages: getMessages }; }); © 2014 Raible Designs
  • 27. $q myApp.controller('HelloCtrl', function($scope, HelloWorld) { ! HelloWorld.getMessages().then(function(messages) { $scope.messages = messages; }); ! }); © 2014 Raible Designs
  • 28. Dependency Injection .controller('LoginController', function($scope, $rootScope, $location, $http, $cookieStore, LoginService) { $scope.login = function () { LoginService.authenticate($.param({username: $scope.username, 
 password: $scope.password}), function (user) { $rootScope.user = user; $http.defaults.headers.common[xAuthTokenHeaderName] = user.token; $cookieStore.put('user', user); $location.path("/"); }); }; }) © 2014 Raible Designs
  • 29. Filters ! ! ! ! {{ name | uppercase }} ! <!-- Displays: 123.46 --> {{ 123.456789 | number:2 }} ! <!-- In en-US locale, '$1000.00' will be shown --> {{ 1000 | currency }} ! <!-- all of the words with e in them ["Lerner","Likes","Eat"] --> {{ ['Ari', 'Lerner', 'Likes', 'To', 'Eat', 'Pizza'] | filter:'e' }} ! also: lowercase, limitTo, orderBy © 2014 Raible Designs
  • 30. Routes .config(['$routeProvider', '$locationProvider', '$httpProvider', function ($routeProvider, $locationProvider, $httpProvider) { $routeProvider.when('/create', { templateUrl: 'partials/create.html', controller: 'CreateController' }); $routeProvider.when('/edit/:id', { templateUrl: 'partials/edit.html', controller: 'EditController' }); $routeProvider.when('/login', { templateUrl: 'partials/login.html', controller: 'LoginController' }); $routeProvider.otherwise({ templateUrl: 'partials/index.html', controller: 'IndexController' }); ! $locationProvider.hashPrefix('!'); }] ) © 2014 Raible Designs
  • 31. Routing: Navigation $rootScope.logout = function () { delete $rootScope.user; delete $http.defaults.headers.common[xAuthTokenHeaderName]; $cookieStore.remove('user'); $location.path("/login"); }; © 2014 Raible Designs
  • 32. Routing: Navigation $rootScope.logout = function () { delete $rootScope.user; delete $http.defaults.headers.common[xAuthTokenHeaderName]; $cookieStore.remove('user'); $location.path("/login"); }; © 2014 Raible Designs
  • 33. Code Organization Revisited Lineman helps you build fat-client JavaScript apps It produces happiness by building assets, mocking servers, and running specs on every file change git clone https://github.com/linemanjs/lineman-angular-template.git my-app cd my-app sudo npm install -g lineman npm install lineman run © 2014 Raible Designs
  • 34.
  • 35.
  • 36. Google's Recommendations for Angular App Structure
  • 37.
  • 38. Testing Testem - test runner, framework agnostic Jasmine - unit tests, framework agnostic Protractor - integration tests, angular specific Lineman - productivity, framework agnostic © 2014 Raible Designs
  • 39. Testing: Controllers describe("controller: LoginController", function() { ! beforeEach(function() { module("app"); }); ! beforeEach(inject(function($controller, $rootScope, $location, AuthenticationService, $httpBackend) { this.$location = $location; this.$httpBackend = $httpBackend; this.scope = $rootScope.$new(); this.redirect = spyOn($location, 'path'); $controller('LoginController', { $scope: this.scope, $location: $location, AuthenticationService: AuthenticationService }); })); © 2014 Raible Designs
  • 40. Testing: Controllers afterEach(function() { this.$httpBackend.verifyNoOutstandingRequest(); this.$httpBackend.verifyNoOutstandingExpectation(); }); ! describe("successfully logging in", function() { it("should redirect you to /home", function() { this.$httpBackend.expectPOST('/login', this.scope.credentials).respond(200); this.scope.login(); this.$httpBackend.flush(); expect(this.redirect).toHaveBeenCalledWith('/home'); }); }); }); © 2014 Raible Designs
  • 41. Testing: Directives beforeEach(inject(function($rootScope, $compile) { this.directiveMessage = 'ralph was here'; this.html = "<div shows-message-when-hovered message='" + this.directiveMessage + "'></div>"; this.scope = $rootScope.$new(); this.scope.message = this.originalMessage = 'things are looking grim'; this.elem = $compile(this.html)(this.scope); })); ! describe("when a user mouses over the element", function() { it("sets the message on the scope to the message attribute", function() { this.elem.triggerHandler('mouseenter'); expect(this.scope.message).toBe(this.directiveMessage); }); }); © 2014 Raible Designs
  • 42. Testing: Directives with CoffeeScript describe "directive: shows-message-when-hovered (coffeescript)", -> ! Given -> module("app") ! Given inject ($rootScope, $compile) -> @directiveMessage = 'ralph was here' @html = "<div shows-message-when-hovered message='#{@directiveMessage}'></div>" @scope = $rootScope.$new() @scope.message = @originalMessage = 'things are looking grim' @elem = $compile(@html)(@scope) ! describe "when a user mouses over the element", -> When -> @elem.triggerHandler('mouseenter') Then "the message on the scope is set to the message attribute", -> @scope.message == @directiveMessage © 2014 Raible Designs
  • 43. Testing: End-to-End protractor = require("protractor") require "protractor/jasminewd" require 'jasmine-given' ! describe "my angular app", -> ptor = protractor.getInstance() describe "visiting the login page", -> Given -> ptor.get "/" ! describe "when a user logs in", -> Given -> ptor.findElement(protractor.By.input("credentials.username")).sendKeys "Ralph" Given -> ptor.findElement(protractor.By.input("credentials.password")).sendKeys "Wiggum" When -> ptor.findElement(protractor.By.id("log-in")).click() Then -> ptor.findElement(protractor.By.binding("{{ message }}")).getText().then (text) -> expect(text).toEqual "Mouse Over these images to see a directive at work" © 2014 Raible Designs
  • 44. Building with Grunt sudo npm install ! sudo npm install -g grunt-cli ! vi package.json ! "grunt": "~0.4.1", "grunt-contrib-concat": "~0.3.0", "grunt-contrib-uglify": "~0.2.7", "grunt-contrib-cssmin": "~0.7.0", "grunt-usemin": "~2.0.2", "grunt-contrib-copy": "~0.5.0", "grunt-rev": "~0.1.0", "grunt-contrib-clean": "~0.5.0", "matchdep": "~0.3.0" © 2014 Raible Designs
  • 45. Gruntfile.js module.exports = function (grunt) { ! ! ! ! grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), clean: ["dist", '.tmp'], copy: { main: { expand: true, cwd: 'app/', src: ['**', '!js/**', '!lib/**', '!**/*.css'], dest: 'dist/' } }, rev: { files: { src: ['dist/**/*.{js,css}'] } }, © 2014 Raible Designs
  • 46. Gruntfile.js ! useminPrepare: { html: 'app/index.html' }, ! usemin: { html: ['dist/index.html'] }, ! uglify: { options: { report: 'min', mangle: false } } }); ! © 2014 Raible Designs
  • 47. Gruntfile.js require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); ! // Tell Grunt what to do when we type "grunt" into the terminal grunt.registerTask('default', [ 'copy', 'useminPrepare', 'concat', 'uglify', 'cssmin', 'rev', 'usemin' ]); }; © 2014 Raible Designs
  • 48. index.html comments <head> <title>My AngularJS App</title> <!-- build:css css/seed.min.css --> <link rel="stylesheet" href="css/app.css"/> <link rel="stylesheet" href="css/app2.css"/> <!-- endbuild --> </head> <body> <!-- build:js js/seed.min.js --> <script src="lib/angular/angular.js"></script> <script src="lib/angular/angular-route.js"></script> <script src="js/app.js"></script> <script src="js/services.js"></script> <script src="js/controllers.js"></script> <script src="js/filters.js"></script> <script src="js/directives.js"></script> <!-- endbuild --> </body> © 2014 Raible Designs
  • 49. dist/index.html <head> <title>My AngularJS App</title> <link rel="stylesheet" href="css/f050d0dc.seed.min.css"/> </head> <body> ! <script src="js/8973cf0f.seed.min.js"></script> </body> © 2014 Raible Designs
  • 51. You shouldn’t have to worry about FEO http://raibledesigns.com/rd/entry/you_shouldn_t_have_to © 2014 Raible Designs
  • 52. HTTP/2 Performance Anti-Patterns? Split dominant content domains Reduce requests Merging Sprites DataURIs http://www.slideshare.net/andydavies © 2014 Raible Designs
  • 54. UI Bootstrap http://angular-ui.github.io/bootstrap <script src="lib/angular/ui-bootstrap-0.10.0.min.js"></script> <script src="lib/angular/ui-bootstrap-tpls-0.10.0.min.js"></script> angular.module('myApp', ['ui.bootstrap']); © 2014 Raible Designs
  • 56. AngularJS Batarang © 2014 Raible Designs
  • 57. My Experience Developing with AngularJS Series Part I: The Basics
 Part II: Dialogs and Data
 Part III: Services
 Part IV: Making it Pop
 © 2014 Raible Designs
  • 59. How to Become an Artist Part 1 of 3: Learn the Basics on Your Own Take some time and try various mediums of art Recognize your strengths Do your research and learn the basics Get the supplies you will need Observe the world around you Make time for your art every day Seek out the opinions of others Develop your own style http://www.wikihow.com/Become-an-Artist © 2014 Raible Designs
  • 60. Shortcut to becoming an Angular Artist JUST DO IT. © 2014 Raible Designs
  • 62. Who to follow on Twitter AngularJS Team at Google Web Performance Miško Hevery - @mhevery Ilya Grigorik - @igrigorik Igor Minar - @IgorMinar Andy Davis - @andydavies Brian Ford - @briantford Steve Souders - @Souders ! © 2014 Raible Designs
  • 63. Resources Angular Dart https://angulardart.org Devoxx AngularJS Talks on Parleys.com http://parleys.com/play/5148922b0364bc17fc56c91b (2012) http://parleys.com/play/529321a5e4b054cd7d2ef4e1 (2013) Egghead.io - https://egghead.io/ © 2014 Raible Designs
  • 64. Code Angular Seed https://github.com/angular/angular-seed Lineman Application Template using AngularJS https://github.com/linemanjs/lineman-angular-template AngularJS + Rest + Spring Security https://github.com/joshlong/boot-examples/tree/master/x-auth-security © 2014 Raible Designs