angular.js fundamentals

167
@markbates

Upload: mark

Post on 08-May-2015

1.146 views

Category:

Technology


1 download

DESCRIPTION

As present at FluentConf 2014 on March 11th, 2014. AngularJS is one of the most popular, and powerful, JavaScript frameworks for building rich client-side applications. AngularJS is both simultaneously both simple to use and extremely full featured. With AngularJS a little goes a long way, but to make the most of it, you need to know what you’re doing. In this workshop we will build a complex application to help exercise all of the salient points of the AngularJS framework. Topics covered include, ngResource, directives, fitlers, routing, templates, controllers, testing, and more. Code can be found at: https://github.com/markbates/fluent-2014

TRANSCRIPT

Page 1: Angular.js Fundamentals

@markbates

Page 2: Angular.js Fundamentals

@markbates

Page 3: Angular.js Fundamentals
Page 4: Angular.js Fundamentals
Page 5: Angular.js Fundamentals

FLUENT2014www.metacasts.tv

Page 6: Angular.js Fundamentals

www.angularmasterclass.com

Page 7: Angular.js Fundamentals

Angular Fundamentals

Page 8: Angular.js Fundamentals

Enough Angular to be Dangerous!

Page 9: Angular.js Fundamentals

What Will Cover?

Page 10: Angular.js Fundamentals

What Will Cover?**hopefully

Page 11: Angular.js Fundamentals

• Controllers!

• ngRoute!

• Templates!

• ngResource!

• Directives!

• Filters!

• Scope!

• Testing!

• Code Organization!

• Best Practices

Page 12: Angular.js Fundamentals

Part 1• Features/Why

Angular?!

• Getting Started/Setting Up!

• Directives, Filters, and Data Binding!

• Controllers, Templates, and Scope!

• Modules!

• Routing!

• Custom Directives and Event Handling!

• Testing

Page 13: Angular.js Fundamentals

Part 2

We Code!

Page 14: Angular.js Fundamentals

Part 1

Page 15: Angular.js Fundamentals

Features

Page 16: Angular.js Fundamentals

Features• Plain JavaScript

• Data Binding

• Routing/PushState

• Testing

• Templates/Directives/Controllers

• Modular

• Dependency Injection

• jqLite

• Lightweight

Page 17: Angular.js Fundamentals

Why Angular?

Page 18: Angular.js Fundamentals

Philosophies

Page 19: Angular.js Fundamentals

Backbone.js“minimal set of data-structure and view primitives

for building web application with JavaScript”

Page 20: Angular.js Fundamentals

Ember“framework for creating ambitious web applications”

Page 21: Angular.js Fundamentals

AngularJS“Toolset for building the framework

most suited to your application development”

Page 22: Angular.js Fundamentals
Page 23: Angular.js Fundamentals
Page 24: Angular.js Fundamentals

Weight

Page 25: Angular.js Fundamentals

“production” versions (minified) w/ required dependencies

Page 26: Angular.js Fundamentals

AngularJS Ember Backbone.js

base 109kb 264kb 6.5kb

templating language built-in

90kb (handlebars) ??

data adapter built-in75kb

(ember-data)84kb

(jQuery)

support N/A 84kb (jQuery)

17kb (json2.js)

5.0kb (underscore.js

)

109kb 513kb 112.5kb

Page 27: Angular.js Fundamentals

Mindshare

Page 28: Angular.js Fundamentals

Google

Page 29: Angular.js Fundamentals

AngularJS Backbone.js Ember

Watchers 2,155 1,442 824

Stars 21,408 17,291 9,570

Forks 6,670 3,783 2,044

Github

Page 30: Angular.js Fundamentals

“Basic” Models

Page 31: Angular.js Fundamentals

Backbone.jsclass  App.Beer  extends  Backbone.Model      class  App.Beers  extends  Backbone.Collection  !  model:  Beer

Page 32: Angular.js Fundamentals

EmberApp.Beer  =  DS.Model.extend      title:  DS.attr("string")      abv:  DS.attr("number")      country_id:  DS.attr("number")      brewery_id:  DS.attr("number")      brewery:  DS.belongsTo("App.Brewery")      country:  DS.belongsTo("App.Country")

Page 33: Angular.js Fundamentals

AngularJSApp.Beer  =  {}

Page 34: Angular.js Fundamentals

“Remote” Models

Page 35: Angular.js Fundamentals

Backbone.jsclass  App.Beer  extends  Backbone.Model      urlRoot:  "/api/v1/beers"        class  App.Beers  extends  Backbone.Collection          url:  -­‐>          if  @brewery_id?              return  "/api/v1/breweries/#{@brewery_id}/beers"          else              return  "/api/v1/beers"          model:  Beer

Page 36: Angular.js Fundamentals

EmberApp.Beer  =  DS.Model.extend      title:  DS.attr("string")      abv:  DS.attr("number")      country_id:  DS.attr("number")      brewery_id:  DS.attr("number")      brewery:  DS.belongsTo("App.Brewery")      country:  DS.belongsTo("App.Country")

Page 37: Angular.js Fundamentals

EmberDS.RESTAdapter.reopen      namespace:  'api/v1'      App.Store  =  DS.Store.extend      revision:  14      adapter:  DS.RESTAdapter.create()

Page 38: Angular.js Fundamentals

AngularJSApp.factory  "Beer",  ($resource)  -­‐>      return  $resource  "/api/v1/beers/:id",                                        {id:  "@id"},                                        {update:  {method:  "PUT"}}

Page 39: Angular.js Fundamentals

Routers

Page 40: Angular.js Fundamentals

Backbone.js@Router  =  Backbone.Router.extend          initialize:  -­‐>          @countries  =  new  Countries()          routes:          "breweries/:brewery_id":  "brewery"          "breweries/:brewery_id/edit":  "breweryEdit"          brewery:  (brewery_id)  -­‐>          @changeView(new  BreweryView(collection:  @countries,  model:  new  Brewery(id:  brewery_id)))          breweryEdit:  (brewery_id)  -­‐>          @changeView(new  BreweryEditView(collection:  @countries,  model:  new  Brewery(id:  brewery_id)))          changeView:  (view)  =>          @currentView?.remove()          @currentView  =  view          $("#outlet").html(@currentView.el)

Page 41: Angular.js Fundamentals

Ember

App.Router.map  -­‐>      @resource  "brewery",  {path:  "brewery/:brewery_id"}

Page 42: Angular.js Fundamentals

EmberApp.BreweryRoute  =  Ember.Route.extend      model:  (params)-­‐>          App.Brewery.find(params.brewery_id)

Page 43: Angular.js Fundamentals

AngularJSApp.config  ($routeProvider)  -­‐>          $routeProvider          .when("/breweries/:id",  {              templateUrl:  "/assets/brewery.html",              controller:  "BreweryController"          })          .when("/breweries/:id/edit",  {              templateUrl:  "/assets/edit_brewery.html",              controller:  "EditBreweryController"          })

Page 44: Angular.js Fundamentals

Controllers/Views

Page 45: Angular.js Fundamentals

Backbone.jsclass  @BreweryEditView  extends  Backbone.View          template:  "brewery_edit"          events:          "click  #save-­‐button":  "saveClicked"          "keypress  #brewery-­‐title":  "titleEdited"          initialize:  -­‐>          super          @countriesView  =  new  CountriesView(collection:  @collection)          @$el.html(@countriesView.el)          @model.on  "change",  @render          @model.fetch()          render:  =>          @$("#country-­‐outlet").html(@renderTemplate())          return  @

   saveClicked:  (e)  =>          e?.preventDefault()          attrs  =              title:  @$("#brewery-­‐title").val()              synonyms:  @$("#brewery-­‐synonyms").val()              address:  @$("#brewery-­‐address").val()          @model.save  attrs,              success:  (model,  response,  options)  =>                  App.navigate("/breweries/#{@model.id}",  trigger:  true)              error:  (model,  xhr,  options)  -­‐>                  errors  =  []                  for  key,  value  of  xhr.responseJSON.errors                      errors.push  "#{key}:  #{value.join(",  ")}"                  alert  errors.join("\n")          titleEdited:  (e)  =>          title  =  @$("#brewery-­‐title").val()          @$("h2").text(title)  !    #  further  code  omitted

Page 46: Angular.js Fundamentals

EmberApp.BreweryController  =  Ember.ObjectController.extend        save:  -­‐>          @store.commit()          #  further  code  omitted

Page 47: Angular.js Fundamentals

AngularJS@EditBreweryController  =  ($scope,  $routeParams,  $location,  Brewery)  -­‐>          $scope.brewery  =  Brewery.get(id:  $routeParams.id)          $scope.save  =  -­‐>          success  =  -­‐>              $location.path("/breweries/#{$routeParams.id}")              $scope.errors  =  null          failure  =  (object)-­‐>              $scope.errors  =  object.data.errors          $scope.brewery.$update  {},  success,  failure

Page 48: Angular.js Fundamentals

Templates

Page 49: Angular.js Fundamentals

Backbone.js<h2><%=  @model.displayName()  %></h2>      <form>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="title">Title</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("title")  %>'id='brewery-­‐title'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="synonyms">Synonyms</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("synonyms")  %>'id='brewery-­‐synonyms'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="address">Address</label>          <div  class="controls">              <textarea  class='input-­‐xxlarge'  id='brewery-­‐address'><%=  @model.get("address")  %></textarea>          </div>      </div>          <button  class='btn  btn-­‐primary'  id='save-­‐button'>Save</button>      <a  href="/breweries/<%=  @model.id  %>"  class='btn'>Cancel</a>      </form>

Page 50: Angular.js Fundamentals

Backbone.js<h2><%=  @model.displayName()  %></h2>  

   

<form>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="title">Title</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("title")  %>'id='brewery-­‐title'>          </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("synonyms")  %>'id='brewery-­‐synonyms'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="address">Address</label>  

       <div  class="controls">  

           <textarea  class='input-­‐xxlarge'  id='brewery-­‐address'><%=  @model.get("address")  %></textarea>  

       </div>  

   </div>  

   

   <button  class='btn  btn-­‐primary'  id='save-­‐button'>Save</button>  

   <a  href="/breweries/<%=  @model.id  %>"  class='btn'>Cancel</a>  

   

</form>

Page 51: Angular.js Fundamentals

Backbone.js<h2><%=  @model.displayName()  %></h2>  

   

<form>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="title">Title</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("title")  %>'id='brewery-­‐title'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("synonyms")  %>'id='brewery-­‐synonyms'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="address">Address</label>  

       <div  class="controls">  

           <textarea  class='input-­‐xxlarge'  id='brewery-­‐address'><%=  @model.get("address")  %></textarea>          </div>  

   </div>  

   

   <button  class='btn  btn-­‐primary'  id='save-­‐button'>Save</button>  

   <a  href="/breweries/<%=  @model.id  %>"  class='btn'>Cancel</a>  

   

</form>

Page 52: Angular.js Fundamentals

<div  class='span12'>  

   <h2>{{displayName}}</h2>  

   <h3>  

       {{cityState}}  

       {{#linkTo  "country"  country}}  

           {{country.title}}  

       {{/linkTo}}  

   </h3>  

   {{#if  isEditing}}  

       <form>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="title">Title</label>  

               <div  class="controls">  

                   {{view  Ember.TextField  valueBinding="title"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

               <div  class="controls">  

                   {{view  Ember.TextField  valueBinding="synonyms"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

               <div  class="controls">  

                   {{view  Ember.TextArea  valueBinding="address"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

   

           <button  class='btn  btn-­‐primary'  {{action  "save"}}>Save</button>  

   

       </form>  

   {{  else  }}  

       {{  partial  "brewery/show"  }}  

   {{/if}}  

</div>

Ember

Page 53: Angular.js Fundamentals

<div  class='span12'>  

   <h2>{{displayName}}</h2>  

   <h3>  

       {{cityState}}  

       {{#linkTo  "country"  country}}  

           {{country.title}}  

       {{/linkTo}}  

   </h3>  

   {{#if  isEditing}}  

       <form>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="title">Title</label>  

               <div  class="controls">  

                   {{view  Ember.TextField  valueBinding="title"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

               <div  class="controls">  

                   {{view  Ember.TextField  valueBinding="synonyms"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

               <div  class="controls">  

                   {{view  Ember.TextArea  valueBinding="address"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

   

           <button  class='btn  btn-­‐primary'  {{action  "save"}}>Save</button>  

   

       </form>  

   {{  else  }}  

       {{  partial  "brewery/show"  }}  

   {{/if}}  

</div>

Ember

Page 54: Angular.js Fundamentals

<div  class='span12'>  

   <h2>{{displayName}}</h2>  

   <h3>  

       {{cityState}}  

       {{#linkTo  "country"  country}}  

           {{country.title}}  

       {{/linkTo}}  

   </h3>  

   {{#if  isEditing}}  

       <form>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="title">Title</label>  

               <div  class="controls">  

                   {{view  Ember.TextField  valueBinding="title"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

               <div  class="controls">  

                   {{view  Ember.TextField  valueBinding="synonyms"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

   

           <div  class="control-­‐group">  

               <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

               <div  class="controls">  

                   {{view  Ember.TextArea  valueBinding="address"  class='input-­‐xxlarge'}}  

               </div>  

           </div>  

           <button  class='btn  btn-­‐primary'  {{action  "save"}}>Save</button>  

       </form>  

   {{  else  }}  

       {{  partial  "brewery/show"  }}  

   {{/if}}  

</div>

Ember

Page 55: Angular.js Fundamentals

<form>  

   <h3>{{brewery.title}}</h3>  

   <div  ng-­‐include='"/assets/_errors.html"'></div>  

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="title">Title</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  ng-­‐

model='brewery.title'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  ng-­‐

model='brewery.synonyms'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="address">Address</label>  

       <div  class="controls">  

           <textarea  class='input-­‐xxlarge'  ng-­‐model='brewery.address'></

textarea>  

       </div>  

   </div>  

   

   <button  class='btn  btn-­‐primary'  ng-­‐click='save()'>Save</button>  

   

</form>

AngularJS

Page 56: Angular.js Fundamentals

AngularJS<form>  

   <h3>{{brewery.title}}</h3>  

   <div  ng-­‐include='"/assets/_errors.html"'></div>  

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="title">Title</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.title'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.synonyms'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="address">Address</label>  

       <div  class="controls">  

           <textarea  class='input-­‐xxlarge'  ng-­‐model='brewery.address'></textarea>  

       </div>  

   </div>  

   

   <button  class='btn  btn-­‐primary'  ng-­‐click='save()'>Save</button>  

   

</form>

Page 57: Angular.js Fundamentals

<form>  

   <h3>{{brewery.title}}</h3>  

   <div  ng-­‐include='"/assets/_errors.html"'></div>  

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="title">Title</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.title'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="synonyms">Synonyms</label>  

       <div  class="controls">  

           <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.synonyms'>  

       </div>  

   </div>  

   

   <div  class="control-­‐group">  

       <label  class="control-­‐label"  for="address">Address</label>  

       <div  class="controls">  

           <textarea  class='input-­‐xxlarge'  ng-­‐model='brewery.address'></textarea>  

       </div>  

   </div>  

   <button  class='btn  btn-­‐primary'  ng-­‐click='save()'>Save</button>  

 </form>

AngularJS

Page 58: Angular.js Fundamentals

Pros/Cons

Page 59: Angular.js Fundamentals

Backbone.js• Too simple

• Not opinionated enough

• “Memory” management

• Unstructured

• Spaghetti code

• Lightweight

• Not opinionated

• Simple

• Easy to read source

• “widget” development

Pros Cons

Page 60: Angular.js Fundamentals

Ember• Too complex

• Overly opinionated

• Heavyweight

• ember-data - not production ready (very buggy)

• Little to no mind-share outside of Rails

• Difficult to read source code

• Structured

• Highly opinionated

• “less” code

• “large” apps

Pros Cons

Page 61: Angular.js Fundamentals

AngularJS• Difficult to read source

code

• jQuery plugins require custom directives

• Large apps requiring self-imposed structure

• Lightly structured

• Lightly opinionated

• “less” code

• Plain JavaScript

• Simple/Powerful

• Easy to test

• Lightweight

• small, medium, or large apps

Pros Cons

Page 62: Angular.js Fundamentals

Getting Started

Page 63: Angular.js Fundamentals
Page 64: Angular.js Fundamentals
Page 65: Angular.js Fundamentals
Page 66: Angular.js Fundamentals
Page 67: Angular.js Fundamentals
Page 68: Angular.js Fundamentals
Page 69: Angular.js Fundamentals

5 Minute Break

Page 70: Angular.js Fundamentals

Directives, Filters, and Data Binding

Page 71: Angular.js Fundamentals

Directives<body ng-app>! <ng-view></ng-view>! <ul>! <li ng-repeat='comment in comments'>! {{comment.body}}! </li>! </ul>!</body>

Page 72: Angular.js Fundamentals

Directives<body ng-app>! <ng-view></ng-view>! <ul>! <li ng-repeat='comment in comments'>! {{comment.body}}! </li>! </ul>!</body>

Page 73: Angular.js Fundamentals

Directives<body ng-app>! <ng-view></ng-view>! <ul>! <li ng-repeat='comment in comments'>! {{comment.body}}! </li>! </ul>!</body>

Page 74: Angular.js Fundamentals

Directives<body ng-app>! <ng-view></ng-view>! <ul>! <li ng-repeat='comment in comments'>! {{comment.body}}! </li>! </ul>!</body>

Page 75: Angular.js Fundamentals

Directives<body ng-app>! <ng-view></ng-view>! <ul>! <li ng-repeat='comment in comments'>! {{comment.body}}! </li>! </ul>!</body>

Page 76: Angular.js Fundamentals

Demo

Page 77: Angular.js Fundamentals

Filters<ul>! <li ng-repeat='c in comments | orderBy:"date"'>! {{c.author | uppercase}}! </li>!</ul>

Page 78: Angular.js Fundamentals

Filters<ul>! <li ng-repeat='c in comments | orderBy:"date"'>! {{c.author | uppercase}}! </li>!</ul>

Page 79: Angular.js Fundamentals

Filters<ul>! <li ng-repeat='c in comments | orderBy:"date"'>! {{c.author | uppercase}}! </li>!</ul>

Page 80: Angular.js Fundamentals

<ul>! <li ng-repeat='c in comments | orderBy:"date"'>! {{c.author | uppercase}}! </li>!</ul>

Filters

Page 81: Angular.js Fundamentals

Demo

Page 82: Angular.js Fundamentals

Controllers, Templates, and Scope

Page 83: Angular.js Fundamentals

Controllers, Templates and Scope

Template

Page 84: Angular.js Fundamentals

Controllers, Templates and Scope

Template Controller

Page 85: Angular.js Fundamentals

Controllers, Templates and Scope

Template Controller

Page 86: Angular.js Fundamentals

Controllers, Templates and Scope

Template Controller

Page 87: Angular.js Fundamentals

Demo

Page 88: Angular.js Fundamentals

Modules

Page 89: Angular.js Fundamentals

Module

angular.module('app', []);

Page 90: Angular.js Fundamentals

Module

Config

angular.module('app', []);

Page 91: Angular.js Fundamentals

Module

Config Controller

angular.module('app', []);

Page 92: Angular.js Fundamentals

Module

Config Controller Factories

angular.module('app', []);

Page 93: Angular.js Fundamentals

Module

Config Controller Factories Directives

angular.module('app', []);

Page 94: Angular.js Fundamentals

Module

Config Controller Factories Directives Filters

angular.module('app', []);

Page 95: Angular.js Fundamentals

Module

Config Controller Factories Directives Filters

Routes

angular.module('app', []);

Page 96: Angular.js Fundamentals

Demo

Page 97: Angular.js Fundamentals

Routing

Page 98: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 99: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 100: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 101: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 102: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 103: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 104: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 105: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 106: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 107: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 108: Angular.js Fundamentals

App.config(function($routeProvider, $locationProvider) {! $locationProvider.html5Mode(true);!! $routeProvider.when('/posts', {! controller: 'PostsIndexController',! templateUrl: 'posts/index.html'! })! .when('/posts/:id',{! controller: 'PostsShowController',! templateUrl: 'posts/show.html'! })! .otherwise({! redirectTo: '/posts'! });!});

Routing

Page 109: Angular.js Fundamentals

Demo

Page 110: Angular.js Fundamentals

Custom Directives and Event Handling

Page 111: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 112: Angular.js Fundamentals

DirectivesApp.directive("upCaser", function() {! return {! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Page 113: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 114: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 115: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 116: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 117: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 118: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 119: Angular.js Fundamentals

<div up-caser>! <p>some text</p>! <p>some other text</p>!</div>

Directives

Page 120: Angular.js Fundamentals

Directives<up-caser>! <p>some text</p>! <p>some other text</p>!</up-caser>

Page 121: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 122: Angular.js Fundamentals

Directives<up-caser>! <p>some text</p>! <p>some other text</p>!</up-caser>

Page 123: Angular.js Fundamentals

App.directive("upCaser", function() {! return {! restrict: 'AEC',! link: function(scope, el, attrs) {! $(el).find('p').each(function(i, p) {! p = $(p);! p.text(p.text().toUpperCase());! });! }! };!});

Directives

Page 124: Angular.js Fundamentals

Demo

Page 125: Angular.js Fundamentals

Events

Page 126: Angular.js Fundamentals

Scope

Page 127: Angular.js Fundamentals

Events

$broadcast

$emit

Page 128: Angular.js Fundamentals

App.directive("alerter", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! setTimeout(function() {! scope.$emit("up", "Hello Up!");! scope.$broadcast("down", "Hello Down!");! scope.$apply();! }, 3000);! }! };!});

Events

Page 129: Angular.js Fundamentals

App.directive("alerter", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! setTimeout(function() {! scope.$emit("up", "Hello Up!");! scope.$broadcast("down", "Hello Down!");! scope.$apply();! }, 3000);! }! };!});

Events

Page 130: Angular.js Fundamentals

App.directive("alerter", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! setTimeout(function() {! scope.$emit("up", "Hello Up!");! scope.$broadcast("down", "Hello Down!");! scope.$apply();! }, 3000);! }! };!});

Events

Page 131: Angular.js Fundamentals

App.directive("alerter", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! setTimeout(function() {! scope.$emit("up", "Hello Up!");! scope.$broadcast("down", "Hello Down!");! scope.$apply();! }, 3000);! }! };!});

Events

Page 132: Angular.js Fundamentals

App.directive("alerter", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! setTimeout(function() {! scope.$emit("up", "Hello Up!");! scope.$broadcast("down", "Hello Down!");! scope.$apply();! }, 3000);! }! };!});

Events

Page 133: Angular.js Fundamentals

App.directive("alerter", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! setTimeout(function() {! scope.$emit("up", "Hello Up!");! scope.$broadcast("down", "Hello Down!");! scope.$apply();! }, 3000);! }! };!});

Events

Page 134: Angular.js Fundamentals

App.controller('SomeController', function($scope) {! $scope.$on("up", function(data, message) {! $scope.up_message = message;! });!});

Events

Page 135: Angular.js Fundamentals

App.controller('SomeController', function($scope) {! $scope.$on("up", function(data, message) {! $scope.up_message = message;! });!});

Events

Page 136: Angular.js Fundamentals

App.controller('SomeController', function($scope) {! $scope.$on("up", function(data, message) {! $scope.up_message = message;! });!});

Events

Page 137: Angular.js Fundamentals

App.controller('SomeController', function($scope) {! $scope.$on("up", function(data, message) {! $scope.up_message = message;! });!});

Events

Page 138: Angular.js Fundamentals

App.controller('SomeController', function($scope) {! $scope.$on("up", function(data, message) {! $scope.up_message = message;! });!});

Events

Page 139: Angular.js Fundamentals

App.controller('SomeController', function($scope) {! $scope.$on("up", function(data, message) {! $scope.up_message = message;! });!});

Events

Page 140: Angular.js Fundamentals

Demo

Page 141: Angular.js Fundamentals

App.controller('Main', function($scope) {! $scope.clicker = function() {! $scope.pressed = true;! };!});

Events

Page 142: Angular.js Fundamentals

App.directive("alerter", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! scope.$watch('pressed', function() {! if (scope.pressed) {! $(el).text('Oi!');! }! });! }! };!});

Events

Page 143: Angular.js Fundamentals

App.directive("alerter", function() {! return {! restrict: 'E',! link: function(scope, el, attrs) {! scope.$watch('pressed', function() {! if (scope.pressed) {! $(el).text('Oi!');! }! });! }! };!});

Events

Page 144: Angular.js Fundamentals

Demo

Page 145: Angular.js Fundamentals

Testing

Page 146: Angular.js Fundamentals
Page 147: Angular.js Fundamentals

App.controller('FooController', function($scope) {!! $scope.setFoo = function(val) {! $scope.foo = val;! };!!});

Testing

Page 148: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 149: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 150: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 151: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 152: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 153: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 154: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 155: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 156: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 157: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 158: Angular.js Fundamentals

describe('FooController', function() {!! beforeEach(function() {module('app')});!! beforeEach(inject(function($rootScope, $controller) {! this.scope = $rootScope.$new();! $controller('FooController', {$scope: this.scope})! }));!! describe('setFoo()', function() {!! it('sets the foo value', function() {! expect(this.scope.foo).not.toBeDefined();! this.scope.setFoo('Bar');! expect(this.scope.foo).toEqual('Bar');! });! });!});

Testing

Page 159: Angular.js Fundamentals

Demo

Page 160: Angular.js Fundamentals

Part 2

Page 161: Angular.js Fundamentals

Setup!

Page 162: Angular.js Fundamentals

Base Project!github.com/markbates/

fluent-2014

Page 163: Angular.js Fundamentals

Node.js!http://nodejs.org

Page 164: Angular.js Fundamentals

Lineman.js!npm install -g

[email protected]

Page 165: Angular.js Fundamentals

Install Modules!npm install

Page 166: Angular.js Fundamentals

Code Time!!

Page 167: Angular.js Fundamentals

Thanks! @markbates

www.angularmasterclass.com