SlideShare a Scribd company logo
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
The Art of AngularJS - DeRailed 2014
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
The Art of AngularJS - DeRailed 2014
The Art of AngularJS - DeRailed 2014
Google's Recommendations for Angular App Structure
The Art of AngularJS - DeRailed 2014
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

More Related Content

What's hot (20)

PPTX
AngularJS Best Practices
Narek Mamikonyan
 
PDF
AngularJS - What is it & Why is it awesome ? (with demos)
Gary Arora
 
PDF
Introduction to AngularJS
Jussi Pohjolainen
 
PPTX
Why angular js Framework
Sakthi Bro
 
PDF
Advanced Tips & Tricks for using Angular JS
Simon Guest
 
PDF
Introduction to AJAX In WordPress
Caldera Labs
 
PPTX
AngularJS - The Next Big Thing?
Tom Hombergs
 
PDF
AngularJS Basics
Ravi Mone
 
PPTX
Single Page WebApp Architecture
Morgan Cheng
 
PDF
AngularJS application architecture
Gabriele Falace
 
PPTX
Single Page Applications in SharePoint with Angular
Sparkhound Inc.
 
PPTX
Angular js for beginners
Munir Hoque
 
PDF
Angular Best Practices v2
Henry Tao
 
PDF
AngularJS with RequireJS
Johannes Weber
 
PDF
AngularJS Basics and Best Practices - CC FE &UX
JWORKS powered by Ordina
 
PPTX
AngularJS intro
dizabl
 
PPTX
Angular js PPT
Imtiyaz Ahmad Khan
 
PPTX
Angular js
Dinusha Nandika
 
PPTX
Introduction to Angularjs
Manish Shekhawat
 
DOCX
multiple views and routing
Brajesh Yadav
 
AngularJS Best Practices
Narek Mamikonyan
 
AngularJS - What is it & Why is it awesome ? (with demos)
Gary Arora
 
Introduction to AngularJS
Jussi Pohjolainen
 
Why angular js Framework
Sakthi Bro
 
Advanced Tips & Tricks for using Angular JS
Simon Guest
 
Introduction to AJAX In WordPress
Caldera Labs
 
AngularJS - The Next Big Thing?
Tom Hombergs
 
AngularJS Basics
Ravi Mone
 
Single Page WebApp Architecture
Morgan Cheng
 
AngularJS application architecture
Gabriele Falace
 
Single Page Applications in SharePoint with Angular
Sparkhound Inc.
 
Angular js for beginners
Munir Hoque
 
Angular Best Practices v2
Henry Tao
 
AngularJS with RequireJS
Johannes Weber
 
AngularJS Basics and Best Practices - CC FE &UX
JWORKS powered by Ordina
 
AngularJS intro
dizabl
 
Angular js PPT
Imtiyaz Ahmad Khan
 
Angular js
Dinusha Nandika
 
Introduction to Angularjs
Manish Shekhawat
 
multiple views and routing
Brajesh Yadav
 

Similar to The Art of AngularJS - DeRailed 2014 (20)

PPTX
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
murtazahaveliwala
 
PPTX
ASP.NET MVC, AngularJS CRUD for Azerbaijan Technical University
Syed Shanu
 
PPTX
Mean stack Magics
Aishura Aishu
 
PDF
Mini-Training: AngularJS
Betclic Everest Group Tech Team
 
PDF
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Fwdays
 
PPTX
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
All Things Open
 
PPTX
Ruby on Rails + AngularJS + Twitter Bootstrap
Marcio Marinho
 
PPT
Angular data binding by Soft Solutions4U
sharsen
 
PDF
Efektivni vyvoj webovych aplikaci v Ruby on Rails (Webexpo)
Karel Minarik
 
PPTX
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
POSSCON
 
PDF
SF Cordova Meetup
Andreas Argelius
 
PDF
A gently introduction to AngularJS
Gregor Woiwode
 
PDF
The Modern Java Web Developer - JavaOne 2013
Matt Raible
 
PDF
Drupalcon Mumbai
Sumit Kataria
 
PDF
From Backbone to Ember and Back(bone) Again
jonknapp
 
PDF
Angular server side rendering - Strategies & Technics
Eliran Eliassy
 
PDF
CFUGbe talk about Angular JS
Alwyn Wymeersch
 
PDF
Node.js and Selenium Webdriver, a journey from the Java side
Mek Srunyu Stittri
 
PDF
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
Mek Srunyu Stittri
 
PDF
Heroku pop-behind-the-sense
Ben Lin
 
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
murtazahaveliwala
 
ASP.NET MVC, AngularJS CRUD for Azerbaijan Technical University
Syed Shanu
 
Mean stack Magics
Aishura Aishu
 
Mini-Training: AngularJS
Betclic Everest Group Tech Team
 
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Fwdays
 
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
All Things Open
 
Ruby on Rails + AngularJS + Twitter Bootstrap
Marcio Marinho
 
Angular data binding by Soft Solutions4U
sharsen
 
Efektivni vyvoj webovych aplikaci v Ruby on Rails (Webexpo)
Karel Minarik
 
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
POSSCON
 
SF Cordova Meetup
Andreas Argelius
 
A gently introduction to AngularJS
Gregor Woiwode
 
The Modern Java Web Developer - JavaOne 2013
Matt Raible
 
Drupalcon Mumbai
Sumit Kataria
 
From Backbone to Ember and Back(bone) Again
jonknapp
 
Angular server side rendering - Strategies & Technics
Eliran Eliassy
 
CFUGbe talk about Angular JS
Alwyn Wymeersch
 
Node.js and Selenium Webdriver, a journey from the Java side
Mek Srunyu Stittri
 
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
Mek Srunyu Stittri
 
Heroku pop-behind-the-sense
Ben Lin
 
Ad

More from Matt Raible (20)

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

Recently uploaded (20)

PDF
Staying Human in a Machine- Accelerated World
Catalin Jora
 
PPTX
The Project Compass - GDG on Campus MSIT
dscmsitkol
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
PDF
“Squinting Vision Pipelines: Detecting and Correcting Errors in Vision Models...
Edge AI and Vision Alliance
 
PDF
“Computer Vision at Sea: Automated Fish Tracking for Sustainable Fishing,” a ...
Edge AI and Vision Alliance
 
PDF
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
PPTX
Agentforce World Tour Toronto '25 - Supercharge MuleSoft Development with Mod...
Alexandra N. Martinez
 
DOCX
Python coding for beginners !! Start now!#
Rajni Bhardwaj Grover
 
PDF
Peak of Data & AI Encore AI-Enhanced Workflows for the Real World
Safe Software
 
PDF
Automating Feature Enrichment and Station Creation in Natural Gas Utility Net...
Safe Software
 
PDF
The 2025 InfraRed Report - Redpoint Ventures
Razin Mustafiz
 
PPTX
Seamless Tech Experiences Showcasing Cross-Platform App Design.pptx
presentifyai
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
PPTX
Digital Circuits, important subject in CS
contactparinay1
 
PPTX
Designing_the_Future_AI_Driven_Product_Experiences_Across_Devices.pptx
presentifyai
 
PPTX
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
PPTX
MuleSoft MCP Support (Model Context Protocol) and Use Case Demo
shyamraj55
 
PDF
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
Staying Human in a Machine- Accelerated World
Catalin Jora
 
The Project Compass - GDG on Campus MSIT
dscmsitkol
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
“Squinting Vision Pipelines: Detecting and Correcting Errors in Vision Models...
Edge AI and Vision Alliance
 
“Computer Vision at Sea: Automated Fish Tracking for Sustainable Fishing,” a ...
Edge AI and Vision Alliance
 
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
Agentforce World Tour Toronto '25 - Supercharge MuleSoft Development with Mod...
Alexandra N. Martinez
 
Python coding for beginners !! Start now!#
Rajni Bhardwaj Grover
 
Peak of Data & AI Encore AI-Enhanced Workflows for the Real World
Safe Software
 
Automating Feature Enrichment and Station Creation in Natural Gas Utility Net...
Safe Software
 
The 2025 InfraRed Report - Redpoint Ventures
Razin Mustafiz
 
Seamless Tech Experiences Showcasing Cross-Platform App Design.pptx
presentifyai
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
Digital Circuits, important subject in CS
contactparinay1
 
Designing_the_Future_AI_Driven_Product_Experiences_Across_Devices.pptx
presentifyai
 
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
MuleSoft MCP Support (Model Context Protocol) and Use Case Demo
shyamraj55
 
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 

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
  • 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
  • 36. Google's Recommendations for Angular App Structure
  • 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