Intro to Angular.JS Directives

4,828 views

Published on

Delivered at NationJS Conference, In Silver Spring MD, on 10/4/13.

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,828
On SlideShare
0
From Embeds
0
Number of Embeds
979
Actions
Shares
0
Downloads
88
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Intro to Angular.JS Directives

  1. 1. Angular Directives @ NationJS, 2013 by: Christian Lilley about.me/xml @xmlilley Friday, October 4, 13
  2. 2. What are Directives? Friday, October 4, 13
  3. 3. Friday, October 4, 13
  4. 4. Angular, Ember, BackBone: Google Trends Friday, October 4, 13
  5. 5. What Are They, Really? 5(-ish) words: Logic & Behavior For UI “...a way to teach HTML new tricks.” Anything in your app that touches DOM Examples: event-handling, behavior management, template pre-processing & insertion, data-binding, ‘Collection Views’, UI Widgets, conditional display, i18n & localization, etc. Friday, October 4, 13
  6. 6. What Are They, Really? The only other Angular construct that really touches the DOM is: Angular Expressions (text only). Filters The rest of it should be in Directives. (Even the ng-view that executes your routing is simply a model-driven directive...) Friday, October 4, 13
  7. 7. What AREN’T they? Directives. Are. Not. Where. Your. JQuery. Goes! Please, God: No. Friday, October 4, 13
  8. 8. I BUT... Friday, October 4, 13
  9. 9. I Moar “The Superheroic MVW framework.” Friday, October 4, 13
  10. 10. And Angular isn’t just another way to organize the same old UI code!!! Friday, October 4, 13
  11. 11. Opinionated Principles 1.Declarative, Model-Driven Behavior Friday, October 4, 13
  12. 12. Why Declarative? IMPERATIVE = YOUR PROBLEM DECLARATIVE = SOMEBODY ELSE’S PROBLEM Easier To Read, Maintain: Why scatter event-listeners across 100 linked JS files, then need to go search for them to find out what’s happening on an element. Friday, October 4, 13
  13. 13. Declarativeness ROCKS You’re trying to find handlers for this element: Well, where are the event-handlers? On ‘#1’? On ‘.B’? ‘.C’? On ‘button’? What if it’s on ‘parentDiv>:first- child’? You can’t misunderstand what’s happening with declarative directives: <button id=”1” class=”B C”></button> <button md-action-handler></button> Friday, October 4, 13
  14. 14. Why NOT Declarative? HTML is NOT a virgin bride or hothouse flower. The Semantics Wars are over. HTML is a highly-abstracted, Object-Oriented language for app interfaces and for *presenting* documents. Docs themselves are increasingly stored in other formats, like markdown. We’re not abandoning accessibility. But it’s not a religion. Friday, October 4, 13
  15. 15. 1.Declarative, Model-Driven Behavior 2.Modularity, Reusability across contexts: Write Once, Run Anywhere Opinionated Principles Friday, October 4, 13
  16. 16. Reusability It’s all about context-awareness, data-binding & DI. Directives know their own element and local scope. You can pass additional data into directives as attributes, right on the element. Friday, October 4, 13
  17. 17. <div id="header_tabs"> <a href="#/home" active-tab="1">HOME</a> <a href="#/finance" active-tab="1">Finance</a> <a href="#/hr" active-tab="1">Human Resources</a> <a href="#/quarterly" active-tab="1">Quarterly</a> </div> AND... <div id="subnav_tabs"> <a href="#/hr/pay" active-tab="2">Pay</a> <a href="#/hr/benefits" active-tab="2">Benefits</a> <a href="#/hr/help" active-tab="2">Help</a> </div> Friday, October 4, 13
  18. 18. 1.Declarative, Model-Driven Behavior 2.Modularity, Reusability across contexts: Write Once, Run Anywhere 3.Keep it Local Opinionated Principles Friday, October 4, 13
  19. 19. No... Friday, October 4, 13
  20. 20. Yes: ‘Local’ Sticks to a self-contained, modular scope, which understands its context. Uses messages, models to affect things elsewhere. Easier to maintain, easier to read, easier to scale. But the challenge is this: Friday, October 4, 13
  21. 21. My Awesome Website Sweet Product Product Description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. In erat mauris, faucibus quis pharetra sit amet, pretium ac libero. Etiam vehicula eleifend bibendum. Morbi gravida metus ut sapien condimentum sodales mollis augue sodales. Vestibulum quis quam at sem placerat aliquet. Curabitur a felis at sapien ullamcorper fermentum. Mauris molestie arcu et lectus iaculis sit amet eleifend eros posuere. Fusce nec porta orci. Integer vitae neque odio, a sollicitudin lorem. Aenean orci mauris, tristique luctus fermentum eu, feugiat vel massa. Fusce sem $899.99 Buy Now! Cart: 1 Item(s) Clicking Here Needs to Change Things Here Friday, October 4, 13
  22. 22. Let’s Build Some! Friday, October 4, 13
  23. 23. Directive Names Angular uses a convention borrowed from other JS projects: names in HTML are hyphenated... while identifiers in the JS are camel-cased: Expect Angular to do this conversion automatically. Don’t fight it. .directive(‘sampleDirective’, function(){}) <sample-directive></sample-directive> Friday, October 4, 13
  24. 24. How are custom directives different from built-in? They’re not. At all. No, really. (Well, OK: they’re different in naming conventions: don’t use ‘ng-’ in your custom directives.) Friday, October 4, 13
  25. 25. CREATION .directive() is a method we call on an angular.module(), either at creation time or via reference, passing a name and a factory function The factory will return either a function or an object containing a function and other settings angular .module('moduleName', ['dependency1', 'dependency2']) .directive('directiveName', factoryFunction() {}) Friday, October 4, 13
  26. 26. Factories (Note, when we talk about generic ‘factories’, we don’t mean $factory, which is an Angular implementation service.) The factory pattern is all about Functional Programming: using basic Javascript functions to build and return either naiive objects or other functions. Friday, October 4, 13
  27. 27. What do We Do With The Factory Function? Friday, October 4, 13
  28. 28. Two Basic Options: Return a Config Object or a ‘Linking Function’ Friday, October 4, 13
  29. 29. Friday, October 4, 13
  30. 30. Friday, October 4, 13
  31. 31. You’ll See Later, But Ignore For Today: Returning only the Link function Link vs. Compile Pre-Link vs. Post-Link Friday, October 4, 13
  32. 32. Friday, October 4, 13
  33. 33. Using a Config Object angular.module('moduleName'). directive('sampleDirective', function(){ return { link: function(scope, element, attrs) { // this example binds a behavior to the // mouseenter event element.bind("mouseenter", function(){ ... do stuff after mouseenter ... } }, restrict: ‘E’, template: “<div>Hello, World!</div>” }}) Everything but `link` is optional. Friday, October 4, 13
  34. 34. Link Function Args .directive('sampleDirective', function(){ return { link: function(scope, element, attrs) { // this example binds a behavior to the // mouseenter event element.bind("mouseenter", function(){ ... do stuff after mouseenter ... } }, restrict: ‘E’, template: <div>Hello, World!</div> } }) Friday, October 4, 13
  35. 35. Link Function Args 3 standard params for a link function. (Plus optional 4th: controller.) They’re supplied as args by the directive function, if specified. scope: whatever scope object is local element: element declared on: `this` attrs: an object containing the html attributes defined on the element, including the directive invocation itself Supplied to the function not by name but in order. Call them whatever you want. Friday, October 4, 13
  36. 36. jqLite: your path to the DOM Angular will defer to JQuery, if present, but provides its own subset of JQuery for basic DOM tasks. You can’t just use $(), nor find using selectors, unfortunately. But all built-in `element` refs are already pre-wrapped in jqlite object Chain methods as you normally would Friday, October 4, 13
  37. 37. • addClass() • after() • append() • attr() • bind() • children() • clone() • contents() • css() • data() • eq() • find() • hasClass() • html() • next() • on() • off() • parent() • prepend() • prop() • ready() • remove() • removeAttr() • removeClass() • removeData() • replaceWith() • text() • toggleClass() • triggerHandler() • unbind() • val() • wrap() Friday, October 4, 13
  38. 38. Using jqLite (angular.element) .directive('sampleDirective', function(){ return { link: function(scope, element, attrs) { // this example binds a behavior to the // mouseenter event element.bind("mouseenter", function(){ ... do stuff after mouseenter ... } }, restrict: ‘E’, template: <div>Hello, World!</div> }}) $(‘selector’).bind(‘mouseenter’, function() {}) Friday, October 4, 13
  39. 39. ACK! THPPPT!! .bind() is ancient! Where’s .live() ?!? .on() ?!? Friday, October 4, 13
  40. 40. Friday, October 4, 13
  41. 41. A Thought: If angular.element() / jqlite doesn’t support what you’re trying to do... ask yourself: why not? Because they’re lazy bastards? Not so much. Think about other options. Go with the grain, and Angular will reward you. Friday, October 4, 13
  42. 42. Directive Templates Templates can be stored as strings on the `template:` property They can also be loaded from a file, using: `templateUrl: path/to/file/template.html’ Friday, October 4, 13
  43. 43. Templates .directive('sampleDirective', function(){ return { link: function(scope, element, attrs) { // this example binds a behavior to the // mouseenter event element.bind("mouseenter", function(){ ... do stuff after mouseenter ... } }, restrict: ‘E’, template: ‘<div>Hello, World!</div>’ //or: templateUrl: ‘path/to/file.html’ }) Friday, October 4, 13
  44. 44. DEMO BREAKDOWN 1 Friday, October 4, 13
  45. 45. The Restrict Property .directive('sampleDirective', function(){ return { link: function(scope, element, attrs) { // this example binds a behavior to the // mouseenter event element.bind("mouseenter", function(){ ... do stuff after mouseenter ... } }, restrict: ‘E’, template: <div>Hello, World!</div> } }) Friday, October 4, 13
  46. 46. The Restrict Property Remember that directives are re-usable So, we can restrict the usage of a directive to (a) specific context(s), so that we don’t accidentally try to use it in a situation it wasn’t designed for: ‘E’ = Element ‘A’ = Attribute ‘C’ = Class ‘M’ = Comment Stack as a single string: ‘EACM’. Defaults to ‘A’. Friday, October 4, 13
  47. 47. The Replace Property By default, a directive element will wrap the contents of a template. The `element` object will be the outer directive element. To instead replace the directive element (and object) with the contents of the template, use {replace: true} This is esp critical when declaring as an element... Friday, October 4, 13
  48. 48. DEMO BREAKDOWN 2 Friday, October 4, 13
  49. 49. So, about that: Model-Driven & Local Directive Design... Friday, October 4, 13
  50. 50. Specifically, the Model-Driven part... Friday, October 4, 13
  51. 51. Why Model-Driven? After all, the imperative approach works fine... ...if you’re omniscient and precognitive. ... and you really, really like refactoring. Friday, October 4, 13
  52. 52. How Can Directives React to Models? With $watch! Friday, October 4, 13
  53. 53. DEMO BREAKDOWN 3: CLOCK haha! Get it? We’re going to use a clock to demo $watch... Friday, October 4, 13
  54. 54. Keeping Directive Design Local Friday, October 4, 13
  55. 55. How Can Directives React to Stuff that Happens Far, Far Away? Also, with models & $watch! But sometimes, the inheritance chain isn’t a good solution. For those times... Angular events! $on(), $emit(), $broadcast() Friday, October 4, 13
  56. 56. DEMO BREAKDOWN 4: ActiveTab Friday, October 4, 13
  57. 57. Often Overlooked: Controllers Directive Config Objects can provide an optional controller. At first, you think: why? One option: alternative to routing Routes have controllers Sometimes, you don’t want routes Friday, October 4, 13
  58. 58. Often Overlooked: Controllers With its own controller, a directive is a full, standalone interface component, with its own data context, which can be built or torn-down on demand. Friday, October 4, 13
  59. 59. Isolate Scope We have the option, in directives, of using either: the local $scope (from our controller, possibly) a new, per-instance, ‘isolate scope’ Isolate scopes still have a parent $scope, but they’re *encapsulated*: or, detached from the inheritance chain. This is especially useful with repeats, so variables can be fully local to the instance Friday, October 4, 13
  60. 60. Creating Isolate Scope Creating isolate scope is as simple as an object literal assigned to the `scope:` property on the config object: .directive('sampleDirective', function(){ return { link: function(scope, element, attrs) { element.bind("mouseenter", function(){ ... do stuff after mouseenter ... } }, restrict: ‘E’, scope: {name: “Bob”, hobby: “@”} }}) Friday, October 4, 13
  61. 61. Cool! But what’s that ‘@’ doing there? Friday, October 4, 13
  62. 62. Isolate Scope Data-Binding Angular provides us with ways to bind the value of properties in isolate scope to attributes on the element, using special operators: .directive('sampleDirective', function(){ return { link: function() {}, restrict: ‘E’, scope: {name: “Bob”, hobby: “@”} //alt. form:{pasttime: ‘@hobby’} }}) <sample-directive hobby=”scuba-diving”> Friday, October 4, 13
  63. 63. Data-Binding Operators By default, an operator alone will be assumed to refer to a same-named attr Alternately, use form ‘@hobby’ to specify Options: ‘@’- binds the local scope property to primitive value of the DOM attribute. Result is always a string. (Attributes are strings.) ‘=’- binds the local scope property to a parent scope property having same name as the value of the DOM attribute. ‘&’- binds the local scope property to the output of an expression defined in the DOM attribute. It’s like a function-wrapper. Friday, October 4, 13
  64. 64. Thank You! about.me/xml Friday, October 4, 13

×