Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
The Hidden Power
of HTMLBars
or, Scope in Ember.js Templates
EmberCamp 2015
@mixonic
Ember.js Core Team
201 Created
Consultants in NewYork City
BrooklynLondon
BrooklynLondon
BrooklynLondon
BrooklynLondon
BrooklynLondon
Chips Fries
BrooklynLondon
Chips Fries
Crisps Chips
BrooklynLondon
Chips Fries
Crisps Chips
BrooklynLondon
Chips Fries
Crisps Chips
Fries
BrooklynLondon
Chips Fries
Crisps Chips
Fries Crisps
BrooklynLondon
Chips Fries
Crisps Chips
Fries Crisps
Metric
BrooklynLondon
Chips Fries
Crisps Chips
Fries Crisps
Metric
FREEDOM
Chips
Crisps
Fries
?
“Hey, look at those chips”
“chips”
? ?
? ?
?
? ?
?
BrooklynLondon
42-48˚ F50-57˚ F
10–14˚ C 5-9˚ C
Scope
EntityScope + Rules + Label
EntityScope + Rules + Label
cold beer
cold beers

are served in NYC
“chips”
thin, flat, and fried

slices of potato
1 {{! app/templates/components/british-pub.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#each snacks as |packet|}}
5 <li>{{p...
1 {{! app/templates/components/british-pub.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#each snacks as |packet|}}
5 <li>{{p...
1 {{! app/templates/components/british-pub.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#each snacks as |packet|}}
5 <li>{{p...
Rules
1. Dynamic Scope
2. Lexical (Static) Scope
Dynamic Scope
“In languages with dynamic
scope the name resolution
depends upon the program state
when the name is encountered
which is ...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name;
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return s...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6 # show_name: Crisp
...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name;
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return s...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name;
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return s...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "F...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "F...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "F...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "F...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6
7 sub local_sub {
8...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6
7 sub local_sub {
8...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6
7 sub local_sub {
8...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6 # show_name: Crisp
...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6 # show_name: Crisp
...
“In languages with dynamic
scope the name resolution
depends upon the program state
when the name is encountered
which is ...
Lexical (Static) Scope
“In languages with lexical scope (also
called static scope), name resolution
depends on the location in the source
code an...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # my_sub: Crisp
6 # show_name: Crisp
7...
1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # my_sub: Fry
6 # show_name: Crisp
7 s...
“In languages with lexical scope (also
called static scope), name resolution
depends on the location in the source
code an...
Benefits of Static Scope
1. Possible to optimize at compile time
2. Easier for developers to read
3. JavaScript and pretty...
1 {{! app/templates/index.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#view 'localized-menu' model}}
5 <li>{{name}}: {{mode...
1 {{! app/templates/index.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#view 'localized-menu' model}}
5 <li>{{name}}: {{mode...
1 {{! app/templates/index.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#view 'localized-menu' model}}
5 <li>{{name}}: {{mode...
1 {{! app/templates/index.hbs }}
2 <h2>{{model.name}} Menu</h2>
3 <ul>
4 {{#each model.snacks as |packet|}}
5 <li>{{packet...
1 {{! app/templates/index.hbs }}
2 <h2>{{model.name}} Menu</h2>
3 <ul>
4 {{#each model.snacks as |packet|}}
5 <li>{{packet...
1 {{! app/templates/index.hbs }}
2 <h2>{{model.name}} Menu</h2>
3 <ul>
4 {{#each model.snacks as |packet|}}
5 <li>{{packet...
Creating a template system with static
scoping is an intentional goal of
HTMLBars/Glimmer, and directs the
underlying arch...
Tools for Static Scope
Closures
Closures
1 function generateSayName() {
2 let name = 'Chips';
3 return function() {
4 alert(name);
5 };
6 }
7
8 var sayNam...
1 function generateSayName() {
2 let name = 'Chips';
3 return function() {
4 alert(name);
5 };
6 }
7
8 var sayName = gener...
Ember Actions as Closures
1 {{#with (action 'alert' name) as |sayName|}}
2 <button {{action sayName}}>Say the name!</butto...
Ember Actions as Closures
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (action 'alert' name)}}
1 {{! ...
Ember Actions as Closures
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (hash
3 sayBritish=(action 'al...
Ember actions are just
JavaScript functions.
Ember Components as Closures
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the...
Pods, Local Lookup, and Closures
bit.ly/pods-local-lookup
speakerdeck.com/rwjblue/a-tale-of-two-pods
Pods
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 routes/
6 index/
7 template.hbs
Pods
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 routes/
6 index/
7 template.hbs
1 {{! app/routes/index/tem...
Pods
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 routes/
6 index/
7 template.hbs
1 {{! app/routes/index/tem...
1 {{! app/components/generate-say-name/template.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-name-button' name='Cri...
1 {{! app/components/generate-say-name/template.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-name-button' name='Cri...
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 say-name-button/
6 template.hbs
7 routes/
8 index/
9 template.h...
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index...
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index...
1 {{! app/routes/index/template.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}}...
1 {{! app/routes/index/template.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}}...
1 {{! .../say-name-button/template.hbs }}
2 <button {{action 'alert' name}}>{{yield}}</button>
1 app/
2 components/
3 gene...
1 {{! .../say-name-button/template.hbs }}
2 <button {{action 'alert' name}}>{{yield}}</button>
1 app/
2 components/
3 gene...
1 {{! app/routes/index/template.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}}...
bit.ly/pods-local-lookup
speakerdeck.com/rwjblue/a-tale-of-two-pods
Tools for Static Scope
Partial Applications
Partial Application
1 function generateSayName() {
2 let name = 'Chips';
3 return function(honorific) {
4 alert(`${honorif...
1 function generateSayName() {
2 let name = 'Chips';
3 return function(honorific) {
4 alert(`${honorific} ${name}`);
5 };
...
1 function generateSayName() {
2 let name = 'Chips';
3 return function(honorific) {
4 alert(`${honorific} ${name}`);
5 };
...
Ember Actions with Partial Application
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name as |sayName|}}
3 <button {{...
Ember Actions with Partial Application
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name as |sayName|}}
3 <button {{...
Ember Components with Partial Application
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (hash
3 sayBri...
Tools for Static Scope
Recursion?!
emberjs.jsbin.com/fubutusejo/1/edit?html,js,output
Ember templates have the scoping rules
and consistency of a real language.
Develop using the patterns and tools you
would use in a real language.
Thanks!
@mixonic
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
Upcoming SlideShare
Loading in …5
×

The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)

1,550 views

Published on

A re-introduction to Ember.js templates, with comparisons between variable use in templates and real programming languages.

Published in: Technology
  • Be the first to comment

The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)

  1. 1. The Hidden Power of HTMLBars or, Scope in Ember.js Templates EmberCamp 2015
  2. 2. @mixonic Ember.js Core Team
  3. 3. 201 Created Consultants in NewYork City
  4. 4. BrooklynLondon
  5. 5. BrooklynLondon
  6. 6. BrooklynLondon
  7. 7. BrooklynLondon
  8. 8. BrooklynLondon Chips Fries
  9. 9. BrooklynLondon Chips Fries Crisps Chips
  10. 10. BrooklynLondon Chips Fries Crisps Chips
  11. 11. BrooklynLondon Chips Fries Crisps Chips Fries
  12. 12. BrooklynLondon Chips Fries Crisps Chips Fries Crisps
  13. 13. BrooklynLondon Chips Fries Crisps Chips Fries Crisps Metric
  14. 14. BrooklynLondon Chips Fries Crisps Chips Fries Crisps Metric FREEDOM
  15. 15. Chips Crisps Fries ?
  16. 16. “Hey, look at those chips”
  17. 17. “chips” ? ? ? ? ? ? ? ?
  18. 18. BrooklynLondon 42-48˚ F50-57˚ F 10–14˚ C 5-9˚ C
  19. 19. Scope
  20. 20. EntityScope + Rules + Label
  21. 21. EntityScope + Rules + Label cold beer cold beers
 are served in NYC “chips” thin, flat, and fried
 slices of potato
  22. 22. 1 {{! app/templates/components/british-pub.hbs }} 2 <h2>{{name}} Menu</h2> 3 <ul> 4 {{#each snacks as |packet|}} 5 <li>{{packet.name}}: {{packet.price}}</li> 6 {{/each}} 7 </ul>
  23. 23. 1 {{! app/templates/components/british-pub.hbs }} 2 <h2>{{name}} Menu</h2> 3 <ul> 4 {{#each snacks as |packet|}} 5 <li>{{packet.name}}: {{packet.price}}</li> 6 {{/each}} 7 </ul> Label
  24. 24. 1 {{! app/templates/components/british-pub.hbs }} 2 <h2>{{name}} Menu</h2> 3 <ul> 4 {{#each snacks as |packet|}} 5 <li>{{packet.name}}: {{packet.price}}</li> 6 {{/each}} 7 </ul> Scope
  25. 25. Rules
  26. 26. 1. Dynamic Scope 2. Lexical (Static) Scope
  27. 27. Dynamic Scope
  28. 28. “In languages with dynamic scope the name resolution depends upon the program state when the name is encountered which is determined by the execution context or calling context.” Wikipedia
  29. 29. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; 5 $name = "Crisp"; 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  30. 30. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; # local_sub: Fry 6 # show_name: Crisp 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  31. 31. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; 5 $name = "Crisp"; 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  32. 32. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; 5 $name = "Crisp"; 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  33. 33. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  34. 34. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  35. 35. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  36. 36. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  37. 37. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; # local_sub: Fry 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  38. 38. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; # local_sub: Fry 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  39. 39. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; # local_sub: Fry 6 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  40. 40. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; # local_sub: Fry 6 # show_name: Crisp 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  41. 41. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; # local_sub: Fry 6 # show_name: Crisp 7 sub local_sub { 8 local $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "local_sub: ", &local_sub(), "n"; 18 print "show_name: ", &show_name(), "n"; What context do you need to understand the value of $name?
  42. 42. “In languages with dynamic scope the name resolution depends upon the program state when the name is encountered which is determined by the execution context or calling context.” Wikipedia
  43. 43. Lexical (Static) Scope
  44. 44. “In languages with lexical scope (also called static scope), name resolution depends on the location in the source code and the lexical context, which is defined by where the named variable or function is defined.” Wikipedia
  45. 45. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; # my_sub: Crisp 6 # show_name: Crisp 7 sub my_sub { 8 my $name = "Fry"; 9 return show_name(); 10 } 11 12 sub show_name { 13 return $name; 14 } 15 16 print "$name: $namen"; 17 print "my_sub: ", &my_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  46. 46. 1 #!/usr/bin/perl -w 2 use strict; 3 4 our $name; # $name: Crisp 5 $name = "Crisp"; # my_sub: Fry 6 # show_name: Crisp 7 sub my_sub { 8 my $name = "Fry"; 9 return show_name($name); 10 } 11 12 sub show_name { 13 return shift || $name; 14 } 15 16 print "$name: $namen"; 17 print "my_sub: ", &my_sub(), "n"; 18 print "show_name: ", &show_name(), "n";
  47. 47. “In languages with lexical scope (also called static scope), name resolution depends on the location in the source code and the lexical context, which is defined by where the named variable or function is defined.” Wikipedia
  48. 48. Benefits of Static Scope 1. Possible to optimize at compile time 2. Easier for developers to read 3. JavaScript and pretty much all languages use it
  49. 49. 1 {{! app/templates/index.hbs }} 2 <h2>{{name}} Menu</h2> 3 <ul> 4 {{#view 'localized-menu' model}} 5 <li>{{name}}: {{model.price}}</li> 6 {{/view}} 7 </ul> Ember 1.x
  50. 50. 1 {{! app/templates/index.hbs }} 2 <h2>{{name}} Menu</h2> 3 <ul> 4 {{#view 'localized-menu' model}} 5 <li>{{name}}: {{model.price}}</li> 6 {{/view}} 7 </ul> Ember 1.x • Index controller • Index controller model • New context from localized-menu • Helper Dynamic
  51. 51. 1 {{! app/templates/index.hbs }} 2 <h2>{{name}} Menu</h2> 3 <ul> 4 {{#view 'localized-menu' model}} 5 <li>{{name}}: {{model.price}}</li> 6 {{/view}} 7 </ul> Ember 1.x Ember 2.x 1 {{! app/templates/index.hbs }} 2 <h2>{{model.name}} Menu</h2> 3 <ul> 4 {{#each model.snacks as |packet|}} 5 <li>{{packet.name}}: {{packet.price}}</li> 6 {{/each}} 7 </ul>
  52. 52. 1 {{! app/templates/index.hbs }} 2 <h2>{{model.name}} Menu</h2> 3 <ul> 4 {{#each model.snacks as |packet|}} 5 <li>{{packet.name}}: {{packet.price}}</li> 6 {{/each}} 7 </ul> Ember 2.x • Property on packet • Helper Static
  53. 53. 1 {{! app/templates/index.hbs }} 2 <h2>{{model.name}} Menu</h2> 3 <ul> 4 {{#each model.snacks as |packet|}} 5 <li>{{packet.name}}: {{packet.price}}</li> 6 {{/each}} 7 </ul> Ember 2.x • Property on packet • Helper Static
  54. 54. 1 {{! app/templates/index.hbs }} 2 <h2>{{model.name}} Menu</h2> 3 <ul> 4 {{#each model.snacks as |packet|}} 5 <li>{{packet.name}}: {{packet.price}}</li> 6 {{/each}} 7 </ul> 1 function buildIndex(model) { 2 let html = `<h2>${model.name} Menu</h2>`; 3 html += '<ul>'; 4 model.snacks.forEach(packet => { 5 html += `<li> 6 ${packet.name}: ${packet.price} 7 </li>`; 8 }); 9 html += '</ul>'; 10 return html; 11 } Ember 2.x
  55. 55. Creating a template system with static scoping is an intentional goal of HTMLBars/Glimmer, and directs the underlying architecture.
  56. 56. Tools for Static Scope Closures
  57. 57. Closures 1 function generateSayName() { 2 let name = 'Chips'; 3 return function() { 4 alert(name); 5 }; 6 } 7 8 var sayName = generateSayName(); 9 10 console.log(sayName()); // alerts: Chips
  58. 58. 1 function generateSayName() { 2 let name = 'Chips'; 3 return function() { 4 alert(name); 5 }; 6 } 7 8 var sayName = generateSayName(); 9 10 console.log(sayName()); // alerts: Chips Closures
  59. 59. Ember Actions as Closures 1 {{#with (action 'alert' name) as |sayName|}} 2 <button {{action sayName}}>Say the name!</button> 3 {{/with}}
  60. 60. Ember Actions as Closures 1 {{! app/templates/components/generate-say-name.hbs }} 2 {{yield (action 'alert' name)}} 1 {{! app/templates/index.hbs }} 2 {{#generate-say-name name='Chip' as |sayName|}} 3 <button {{action sayName}}>Say the name!</button> 4 {{/generate-say-name}}
  61. 61. Ember Actions as Closures 1 {{! app/templates/components/generate-say-name.hbs }} 2 {{yield (hash 3 sayBritish=(action 'alert' 'Crisp') 4 sayAmerican=(action 'alert' 'Chip') 5 )}} 1 {{! app/templates/index.hbs }} 2 {{#generate-say-name as |ux|}} 3 <button {{action ux.sayBritish}}>Say the name!</button> 4 {{/generate-say-name}}
  62. 62. Ember actions are just JavaScript functions.
  63. 63. Ember Components as Closures 1 {{! app/templates/index.hbs }} 2 {{#generate-say-name as |ux|}} 3 {{#ux.sayBritish}}Say the name!{{/ux.sayBritish}} 4 {{/generate-say-name}} 1 {{! app/templates/components/generate-say-name.hbs }} 2 {{yield (hash 3 sayBritish=(component 'say-name-button' name='Crisp') 4 sayAmerican=(component 'say-name-button' name='Chip') 5 )}}
  64. 64. Pods, Local Lookup, and Closures bit.ly/pods-local-lookup speakerdeck.com/rwjblue/a-tale-of-two-pods
  65. 65. Pods 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 routes/ 6 index/ 7 template.hbs
  66. 66. Pods 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 routes/ 6 index/ 7 template.hbs 1 {{! app/routes/index/template.hbs }} 2 {{#generate-say-name as |ux|}} 3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}} 4 {{/generate-say-name}}
  67. 67. Pods 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 routes/ 6 index/ 7 template.hbs 1 {{! app/routes/index/template.hbs }} 2 {{#generate-say-name as |ux|}} 3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}} 4 {{/generate-say-name}}
  68. 68. 1 {{! app/components/generate-say-name/template.hbs }} 2 {{yield (hash 3 sayBritish=(component 'say-name-button' name='Crisp') 4 sayAmerican=(component 'say-name-button' name='Chip') 5 )}} Pods 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 routes/ 6 index/ 7 template.hbs
  69. 69. 1 {{! app/components/generate-say-name/template.hbs }} 2 {{yield (hash 3 sayBritish=(component 'say-name-button' name='Crisp') 4 sayAmerican=(component 'say-name-button' name='Chip') 5 )}} Pods 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 routes/ 6 index/ 7 template.hbs
  70. 70. 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 say-name-button/ 6 template.hbs 7 routes/ 8 index/ 9 template.hbs 1 {{! app/components/generate-say-name/template.hbs }} 2 {{yield (hash 3 sayBritish=(component 'say-name-button' name='Crisp') 4 sayAmerican=(component 'say-name-button' name='Chip') 5 )}} Pods
  71. 71. 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 components/ 6 say-name-button/ 7 template.hbs 8 routes/ 9 index/ 10 template.hbs 1 {{! app/components/generate-say-name/template.hbs }} 2 {{yield (hash 3 sayBritish=(component 'say-name-button' name='Crisp') 4 sayAmerican=(component 'say-name-button' name='Chip') 5 )}} Local Lookup
  72. 72. 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 components/ 6 say-name-button/ 7 template.hbs 8 routes/ 9 index/ 10 template.hbs 1 {{! app/components/generate-say-name/template.hbs }} 2 {{yield (hash 3 sayBritish=(component 'say-name-button' name='Crisp') 4 sayAmerican=(component 'say-name-button' name='Chip') 5 )}} Local Lookup
  73. 73. 1 {{! app/routes/index/template.hbs }} 2 {{#generate-say-name as |ux|}} 3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}} 4 {{/generate-say-name}} 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 components/ 6 say-name-button/ 7 template.hbs 8 routes/ 9 index/ 10 template.hbs Local Lookup
  74. 74. 1 {{! app/routes/index/template.hbs }} 2 {{#generate-say-name as |ux|}} 3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}} 4 {{/generate-say-name}} 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 components/ 6 say-name-button/ 7 template.hbs 8 routes/ 9 index/ 10 template.hbs Local Lookup
  75. 75. 1 {{! .../say-name-button/template.hbs }} 2 <button {{action 'alert' name}}>{{yield}}</button> 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 components/ 6 say-name-button/ 7 template.hbs 8 routes/ 9 index/ 10 template.hbs Local Lookup
  76. 76. 1 {{! .../say-name-button/template.hbs }} 2 <button {{action 'alert' name}}>{{yield}}</button> 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 components/ 6 say-name-button/ 7 template.hbs 8 routes/ 9 index/ 10 template.hbs Local Lookup
  77. 77. 1 {{! app/routes/index/template.hbs }} 2 {{#generate-say-name as |ux|}} 3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}} 4 {{/generate-say-name}} 1 app/ 2 components/ 3 generate-say-name/ 4 template.hbs 5 components/ 6 say-name-button/ 7 template.hbs 8 routes/ 9 index/ 10 template.hbs Local Lookup
  78. 78. bit.ly/pods-local-lookup speakerdeck.com/rwjblue/a-tale-of-two-pods
  79. 79. Tools for Static Scope Partial Applications
  80. 80. Partial Application 1 function generateSayName() { 2 let name = 'Chips'; 3 return function(honorific) { 4 alert(`${honorific} ${name}`); 5 }; 6 } 7 8 var sayName = generateSayName(); 9 10 console.log(sayName('Mr.')); // logs: Mr. Chips
  81. 81. 1 function generateSayName() { 2 let name = 'Chips'; 3 return function(honorific) { 4 alert(`${honorific} ${name}`); 5 }; 6 } 7 8 var sayName = generateSayName(); 9 10 console.log(sayName('Mr.')); // logs: Mr. Chips Partial Application
  82. 82. 1 function generateSayName() { 2 let name = 'Chips'; 3 return function(honorific) { 4 alert(`${honorific} ${name}`); 5 }; 6 } 7 8 var sayName = generateSayName(); 9 10 console.log(sayName('Mr.')); // logs: Mr. Chips Partial Application
  83. 83. Ember Actions with Partial Application 1 {{! app/templates/index.hbs }} 2 {{#generate-say-name as |sayName|}} 3 <button {{action sayName 'Mr.'}}>Say the name!</button> 4 {{/generate-say-name}} 1 {{! app/templates/components/generate-say-name.hbs }} 2 {{yield (action 'alert' 'Crisps')}}
  84. 84. Ember Actions with Partial Application 1 {{! app/templates/index.hbs }} 2 {{#generate-say-name as |sayName|}} 3 <button {{action sayName 'Mr.'}}>Say the name!</button> 4 {{/generate-say-name}} 1 {{! app/templates/components/generate-say-name.hbs }} 2 {{yield (action 'alert' 'Crisps')}} 1 actions: { 2 alert(name, honorific) { 3 console.log(`${honorific} ${name}`); 4 } 5 }
  85. 85. Ember Components with Partial Application 1 {{! app/templates/components/generate-say-name.hbs }} 2 {{yield (hash 3 sayBritish=(component 'say-button-name' honorific='MP') 4 sayAmerican=(component 'say-button-name' honorific='Rep') 5 )}} 1 {{! app/templates/index.hbs }} 2 {{#generate-say-name as |ux|}} 3 {{ux.sayBritish name='Chips'}} 4 {{ux.sayAmerican honorific='Mr.' name='Fry'}} 5 {{/generate-say-name}} 1 {{! app/templates/components/say-button-name.hbs }} 2 <button {{action 'alert' name honorific}}>Say the Name</button>
  86. 86. Tools for Static Scope Recursion?! emberjs.jsbin.com/fubutusejo/1/edit?html,js,output
  87. 87. Ember templates have the scoping rules and consistency of a real language.
  88. 88. Develop using the patterns and tools you would use in a real language.
  89. 89. Thanks! @mixonic

×