Wield AngularJS Like a Pro

Introductories

Me

Thanks!

  • Amazingly, I get paid for this stuff
  • OS is magical because of people
  • I'm not a peasant

Life Lessons

  • Be humble
  • Don't be afraid to feel stupid
  • The night is young

AngularJS?

  • Two-way data binding
  • Live HTML templating
  • Dependency injection
  • Module system
  • Ajax
  • Animation
  • Caching
  • Contextual Escaping   
  • Events
  • Exceptions
  • Localization
  • Logging
  • Promises
  • Touch
  • Complete reversal of perspective
  • Lots of new terms!
  • Controllers   
  • Directives
  • Providers
  • Services
  • Factories
  • Filters

Controllers


function($scope) {}

Directives


function(elem) { elem.click(...); }

Providers, Services & Factories



Different names for the same thing

Filters



{{ 500 | currency }} == {{ 500 | currency }}

Filters

(secretly just a service)


$filter('currency')(500)

Filters

(secretly just a service)


  • $filter('filter')(posts, {
      archived: true
    })

Filters

(secretly just a service)


  • <div ng-repeat="posts | { archived: true }">

Practices

This file structure...

  • /js
    • directives.js
    • controllers.js
    • services.js
    • ...


...is dumb.

UI == App

Controllers: Small/Nonreusable

Models

  • Domain Objects
  • Data only

Services

  • Object coordination
  • Transactions

Tools

Yeoman, Bower & Friends

Meh.

Batarang!

Libraries

UoR

uor/angular-file


<div ng-controller="FileController">
  <input
    type="file"
    ng-model="model.file"
    change="upload(model)"
  />
</div>

function FileController($scope, $resource) {
    var Files = $resource('/files/:id', { id: "@id" });
    angular.extend($scope, {
        model: { file: null },
        upload: function(model) {
            Files.prototype.$save.call(model.file, function() {
                // Handle server response
            });
        }
    });
});

uor/angular-canvas


<image-editor
  fit="none"
  drop-target
  over-class="drop-active"
  ng-class="$ui.state()"
  drop="$ui.state('loading')"
  load="$ui.state('editing')"
  ng-model="user.avatar"
></image-editor>

uor/angular-http-auth


function LoginController($scope, httpAuth, requestQueue) {
  angular.extend($scope, {
    login: function() {
      httpAuth.basic({
        username: "nate",
        password: "foobar"
      });
      requestQueue.flush();
    }
  });
}

uor/angular-model


<link rel="resource" name="Users" href="http://my.api/users" />

modelProvider.model('Users', {
  $instance: {
    avatar: function() {
      return this.$links.avatar || '/img/avatar.png';
    }
  },
  /* ... */
});

// <img ng-src="{{ user.avatar() }}" />

modelProvider.model('Users', {
  /* ... */
  $class: {
    active: function() {
      return this.all({ active: true })
    }
  }
});

// model('Users').active().then(function(result) { /* ... */ })
  • Promise-based
  • Binds domain logic to API URLs
  • Smart PATCH requests
  • Smart error handling
  • (Almost) Hypermedia-compliant

Future

  • Relationship linking and embedding
  • Smart read/write-through caching
  • Message-orientation

AngularUI

  • Utilities
  • Wrapper Modules
  • Standalone Modules

UI Bootstrap

Carousel


function CarouselDemoController($scope) {
  angular.extend($scope, {
    deck: { interval: 5000, slides: [
      { image: "../img/cats/1.jpg", text: "First"  },
      { image: "../img/cats/2.jpg", text: "Second" },
      { image: "../img/cats/3.jpg", text: "Third"  },
      { image: "../img/cats/4.jpg", text: "Fourth" }
    ]}
  });
}

<div ng-controller="CarouselDemoController">
  <carousel interval="deck.interval">
    <slide ng-repeat="slide in deck.slides" active="slide.active">
      <img ng-src="{{ slide.image }}" style="margin:auto;">
      <div class="carousel-caption">
        <p>{{ slide.text }}

</div> </slide> </carousel> </div>

Accordion


function AccordionDemoController($scope) {
  angular.extend($scope, {
    cats: [
      { image: "../img/cats/1.jpg", text: "First"  },
      { image: "../img/cats/2.jpg", text: "Second" },
      { image: "../img/cats/3.jpg", text: "Third"  },
      { image: "../img/cats/4.jpg", text: "Fourth" }
    ]
  });
}

<body ng-controller="AccordionDemoController">
  <accordion close-others="true">
    <accordion-group
      heading="{{ cat.text }}"
      ng-repeat="cat in cats"
    >
      <img ng-src="{{ cat.image }}" />
    </accordion-group>
  </accordion>
</body>

Date/Timepicker


function Seriously($scope) {
  $scope.myDate = new Date();
}

<div ng-controller="Seriously">
  <div style="display:inline-block; min-height:290px;">
    <div class="well well-sm" ng-model="myDate">
      <datepicker show-weeks="false"></datepicker>
    </div>
  </div>

  <div class="well well-sm" ng-model="myDate">
    <timepicker show-meridian="true"></timepicker>
  </div>
</div>
  • Alerts
  • Buttons
  • Dropdowns
  • Modals
  • Progress Bars   
  • Pagination
  • Ratings
  • Tabs
  • Tooltips
  • Typeahead

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

Others

  • ui-slider
  • ui-select
  • ui-sortable   
  • ui-grid
  • ui-map
  • ui-codemirror / ui-ace
  • ui-layout
  • ...

UI Router

  • Nested states
  • Nested views
  • Hierarchical URL routes
  • Animated transitions

[Insert UI Router Demo Here]

Future

  • Typed Parameters
  • Rich Transition

[Insert App Demo Here]

Performance

ng-bind-once
$rootScope.foo = "badness";
$rootScope.$on("badness", perfHit);
<div
  class="section4 fill"
  ng-if="!isInViewport"
></div>

Custom directives
+ Event delegation
(+ $watchCollection)

Questions?

Thanks/Contact