advertisement

Angular.js Fundamentals

63 %
38 %
advertisement
Information about Angular.js Fundamentals
Technology

Published on March 12, 2014

Author: markykang

Source: slideshare.net

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
advertisement

@markbates

@markbates

FLUENT2014 www.metacasts.tv

www.angularmasterclass.com

Angular Fundamentals

Enough Angular to be Dangerous!

What Will Cover?

What Will Cover?* *hopefully

• Controllers! • ngRoute! • Templates! • ngResource! • Directives! • Filters! • Scope! • Testing! • Code Organization! • Best Practices

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

Part 2 We Code!

Part 1

Features

Features • Plain JavaScript • Data Binding • Routing/PushState • Testing • Templates/Directives/ Controllers • Modular • Dependency Injection • jqLite • Lightweight

Why Angular?

Philosophies

Backbone.js “minimal set of data-structure and view primitives for building web application with JavaScript”

Ember “framework for creating ambitious web applications”

AngularJS “Toolset for building the framework most suited to your application development”

Weight

“production” versions (minified) w/ required dependencies

AngularJS Ember Backbone.js base 109kb 264kb 6.5kb templating language built-in 90kb (handlebars) ?? data adapter built-in 75kb (ember-data) 84kb (jQuery) support N/A 84kb (jQuery) 17kb (json2.js) 5.0kb (underscore.js ) 109kb 513kb 112.5kb

Mindshare

Google

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

“Basic” Models

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

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")

AngularJS App.Beer  =   {}

“Remote” Models

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

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")

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

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

Routers

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)

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

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

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

Controllers/Views

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

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

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

Templates

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>

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>

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>

<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

<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

<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

<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

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>

<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

Pros/Cons

Backbone.js • Too simple • Not opinionated enough • “Memory” management • Unstructured • Spaghetti code • Lightweight • Not opinionated • Simple • Easy to read source • “widget” development Pros Cons

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

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

Getting Started

5 Minute Break

Directives, Filters, and Data Binding

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

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

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

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

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

Demo

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

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

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

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

Demo

Controllers, Templates, and Scope

Controllers, Templates and Scope Template

Controllers, Templates and Scope Template Controller

Controllers, Templates and Scope Template Controller

Controllers, Templates and Scope Template Controller

Demo

Modules

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

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

Module Config Controller angular.module('app', []);

Module Config Controller Factories angular.module('app', []);

Module Config Controller Factories Directives angular.module('app', []);

Module Config Controller Factories Directives Filters angular.module('app', []);

Module Config Controller Factories Directives Filters Routes angular.module('app', []);

Demo

Routing

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

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

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

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

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

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

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

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

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

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

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

Demo

Custom Directives and Event Handling

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

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

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

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

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

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

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

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

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

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

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

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

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

Demo

Events

Scope

Events $broadcast $emit

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

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

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

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

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

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

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

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

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

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

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

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

Demo

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

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

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

Demo

Testing

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

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

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

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

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

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

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

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

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

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

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

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

Demo

Part 2

Setup!

Base Project! github.com/markbates/ fluent-2014

Node.js! http://nodejs.org

Lineman.js! npm install -g lineman@0.27.2

Install Modules! npm install

Code Time!!

Thanks! @markbates www.angularmasterclass.com

Add a comment

Related presentations

Presentación que realice en el Evento Nacional de Gobierno Abierto, realizado los ...

In this presentation we will describe our experience developing with a highly dyna...

Presentation to the LITA Forum 7th November 2014 Albuquerque, NM

Un recorrido por los cambios que nos generará el wearabletech en el futuro

Um paralelo entre as novidades & mercado em Wearable Computing e Tecnologias Assis...

Microsoft finally joins the smartwatch and fitness tracker game by introducing the...

Related pages

Angular Fundamentals | Pluralsight

This course will teach you the Angular fundamentals required to create testable, MVC-style single page applications with AngularJS.
Read more

AngularJS Fundamentals In 60-ish Minutes - YouTube

AngularJS Fundamentals In 60-ish Minutes ... Introduction to Angular.js in 50 Examples (part 1) - Duration: 1:04:49. Curran Kelleher 778,933 views.
Read more

AngularJS — Superheroic JavaScript MVW Framework

AngularJS is what HTML would have been, had it been designed for building web-apps. Declarative templates with data-binding, MVW, MVVM, MVC ...
Read more

GitHub - joeeames/AngularFundamentalsFiles: A few files ...

AngularFundamentalsFiles - A few files from my angular fundamentals course ... Clone with HTTPS Use Git or checkout with SVN using the web URL.
Read more

Dan Wahlin - Video Tutorial: AngularJS Fundamentals in 60 ...

Jump to a Specific Section: Introduction to AngularJS; Getting Started with AngularJS Features; Directives, Filters and Data Binding; Views, Controllers ...
Read more

AngularJS.DE → Startseite

Bei uns findest du alles auf deutsch: Tutorials · Artikel · News · Workshops · Online-Buch · Entwicklerverzeichnis.
Read more

AngularJS in 60 Minutes - Fast and Fluid

AngularJS in 60 Minutes by Dan Wahlin ... My names Dan Wahlin and Ill be walking you through some of the key fundamentals, some of the things I really like.
Read more

AngularJS – Wikipedia

Um Elemente auszuwählen, verwendet AngularJS ein integriertes jQuery Lite (jqLite). Dabei handelt es sich um eine reduzierte Version von jQuery, in ...
Read more

AngularJS Training - OdeToCode

AngularJS Training. Tuesday, January 21, ... At the end of last year I put together and taught a 2 day workshop on AngularJS fundamentals at NDC London, ...
Read more

AngularJS: Get Started | Pluralsight

AngularJS: Get Started. By Scott Allen. This course demonstrates how to use the essential abstractions of AngularJS, including modules, controllers, ...
Read more