Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Templates and Logic in Ember

Templates and Logic in Ember

This talk showcases different approaches to handling application logic in templates - keeping it in the template context vs. in the template itself using nested helpers. It shows how to achieve the same result with either alternative and covers tradeoffs and differences to be aware of.

Marco Otte-Witte

October 27, 2016
Tweet

More Decks by Marco Otte-Witte

Other Decks in Technology

Transcript

  1. "Handlebars.js is an extension to the Mustache templating language created

    by Chris Wanstrath. Handlebars.js and Mustache are both logicless templating languages that keep the view and the code separated like we all know they should be." https://github.com/wycats/handlebars.js/
  2. <div class="entry"> <h1>{{title}}</h1> <div class="body"> {{body}} </div> </div> { title:

    'A post', body: 'Awesome post!' } + = <div class="entry"> <h1>A post</h1> <div class="body"> Awesome post! </div> </div>
  3. <div class="entry"> <h1>{{title}}</h1> <div class="body"> {{body}} </div> {{#if author}} <h1>{{author.firstName}}

    {{author.lastName}}</h1> {{/if}} <h1>Comments</h1> {{#each comments as |comment|}} <h2>By {{comment.author}}</h2> <div class="body">{{comment.text}}</div> {{/each}} </div>
  4. <div class="entry"> <h1>{{title}}</h1> <div class="body"> {{body}} </div> {{#if author}} <h1>{{fullName

    author}}</h1> {{/if}} <h1>Comments</h1> {{#each comments as |comment|}} <h2>By {{fullName comment.author}}</h2> <div class="body">{{comment.text}}</div> {{/each}} </div>
  5. {{#each (take 1 (filter-by (shuffle users) 'isActive' true)) as |user|}}

    {{#let user.firstName user.lastName as |firstName lastName|}} <p> {{concat (capitalize firstName) ' ' (capitalize lastName)}} {{#if (and (eq (capitalize (take 1 firstName)) 'J') (lte user.age 65))}} (he's the special one!) {{/if}} </p> {{/let}} {{/each}}
  6. {{#each (take 1 (filter-by (shuffle model) 'isActive' true)) as |user|}}

    {{#let user.firstName user.lastName as |firstName lastName|}} <p> {{concat (capitalize firstName) ' ' (capitalize lastName)}} {{#if (and (eq (capitalize (take 1 firstName)) 'J') (lte user.age 65))}} (he's the special one!) {{/if}} </p> {{/let}} {{/each}}
  7. <?php each (take 1 (filter-by (shuffle model) 'isActive' true)) as

    |user| ?> <?php let user.firstName user.lastName as |firstName lastName| ?> <p> <?php concat (capitalize firstName) ' ' (capitalize lastName) ?> <?php if (and (eq (capitalize (take 1 firstName)) 'J') (lte user.age 65)) ?> (he's the special one!) <?php /if ?> </p> <?php /let ?> <?php /each ?> https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/PHP-logo.svg/2000px-PHP-logo.svg.png http://vignette2.wikia.nocookie.net/villains/images/c/c8/TrollFace.png/revision/latest?cb=20150813022250
  8. export function gte([value, compareTo]) { return value >= compareTo; }

    export default Ember.Helper.helper(gte); {{#if (gte user.age 65)}} {{/if}} = {{#if user.isSenior}} {{/if}} isSenior: computed('age', function() { return this.get('age') >= 65; })
  9. export function gte([value, compareTo]) { return value >= compareTo; }

    export default Ember.Helper.helper(gte); {{#if (gte user.age 65)}} {{/if}} = {{#if user.isSenior}} {{/if}} isSenior: computed('age', function() { return gte(this.get(['age', 65])); })
  10. export function gte([value, compareTo]) { return value >= compareTo; }

    export default Ember.Helper.helper(gte); {{#if (gte user.age 65)}} {{/if}} = {{#if user.isSenior}} {{/if}} isSenior: computed.gte('age', 65)
  11. {{#each (filter-by users 'isActive' true) as |user|}} {{user.name}} {{/each}} =

    {{#each activeUsers as |user|}} {{user.name}} {{/each}} activeUsers: computed('[email protected]', function() { return this.get('users').filterBy('isActive', true); }) export function filterBy([collection, filterProperty, filterValue]) { return collection.filterBy(filterProperty, filterValue); } export default Ember.Helper.helper(filterBy);
  12. {{#each (filter-by users 'isActive' true) as |user|}} {{user.name}} {{/each}} =

    {{#each activeUsers as |user|}} {{user.name}} {{/each}} activeUsers: computed('[email protected]', function() { return filterBy([this.get('users'), 'isActive', true]); }) export function filterBy([collection, filterProperty, filterValue]) { return collection.filterBy(filterProperty, filterValue); } export default Ember.Helper.helper(filterBy);
  13. {{#each (filter-by users 'isActive' true) as |user|}} {{user.name}} {{/each}} =

    {{#each activeUsers as |user|}} {{user.name}} {{/each}} activeUsers: computed.filterBy('users', 'isActive', true) export function filterBy([collection, filterProperty, filterValue]) { return collection.filterBy(filterProperty, filterValue); } export default Ember.Helper.helper(filterBy);
  14. function fullName([firstName, lastName]) { return `${firstName} ${lastName}`; } fullName: computed('firstName',

    'lastName', function() { return `${this.get('firstName')} ${this.get('lastName')}`; }) Inputs
  15. fullName: computed('firstName', 'lastName', function() { return `${this.get('firstName')} ${this.get('lastName')}`; }) import

    join from '../computeds/join'; … fullName: join('firstName', 'lastName') export default function join(first, second, glue = ' ') { let args = [first, second, function() { return [this.get(first), this.get(second)].join(glue); }]; return computed(...args); } =
  16. export default Ember.Component.extend({ num1: 45, num2: 3.5, num3: 13.4, num4:

    -2, total: sum( sum('num1', 'num2', 'num3'), difference('num3', 'num2'), product(difference('num2', 'num1'), 'num4') ) }); https://github.com/cibernox/ember-cpm
  17. <input type="text" value={{user.firstName}} onchange={{action (mut firstName) value='target.value'}}/> <input type="text" value={{user.lastName}}

    onchange={{action (mut lastName) value='target.value'}}/> <button onclick={{action (mut isEditing) false}}>Cancel</button> <button onclick={{action (pipe (action 'validate') (action (mut user.firstName) firstName) (action (mut user.lastName) lastName) (action 'save') (action (mut isEditing) false) )}}>Save</button>
  18. <input type="text" value={{user.firstName}} onchange={{action 'setFirstName' value='target.value'}}/> <input type="text" value={{user.lastName}} onchange={{action

    'setLastName' value='target.value'}}/> <button onclick={{action 'cancelEditing'}}>Cancel</button> <button onclick={{action 'save'}}>Save</button> save() { this._validate().then(() => { this.get('user').setProperties( this.getProperties('firstName', 'lastName') ); }).then(() => { return this.get('user').save(); }).then(() => { this.set('isEditing', false) }); } +
  19. <input type="text" value={{user.firstName}} onchange={{action 'setFirstName' value='target.value'}}/> <input type="text" value={{user.lastName}} onchange={{action

    'setLastName' value='target.value'}}/> <button onclick={{action 'cancelEditing'}}>Cancel</button> <button onclick={{action 'save'}}>Save</button> + save() { pipe( () => this._validate(), () => this.get('user').setProperties(this.getProperties('firstName', 'lastName')), () => this.get('user').save(), () => this.set('isEditing', false) ); }
  20. export function isSenior([user]) { return user.get('age') >= 65; } export

    default Ember.Helper.helper(gte); {{#if (is-senior user)}} {{/if}}
  21. {{#each (filter-by users 'isActive' true) as |user|}} {{user.name}} {{/each}} export

    function filterBy([collection, filterProperty, filterValue]) { return collection.filterBy(filterProperty, filterValue); } export default Ember.Helper.helper(filterBy); This is what you want to test
  22. <input type="text" value={{user.firstName}} onchange={{action (mut firstName) value='target.value'}}/> <input type="text" value={{user.lastName}}

    onchange={{action (mut lastName) value='target.value'}}/> <button onclick={{action (mut isEditing) false}}>Cancel</button> <button onclick={{action (pipe (action 'validate') (action (mut user.firstName) firstName) (action (mut user.lastName) lastName) (action 'save') (action (mut isEditing) false) )}}>Save</button>
  23. <input type="text" value={{user.firstName}} onchange={{action 'setFirstName' value='target.value'}}/> <input type="text" value={{user.lastName}} onchange={{action

    'setLastName' value='target.value'}}/> <button onclick={{action 'cancelEditing'}}>Cancel</button> <button onclick={{action 'save'}}>Save</button> + save() { pipe( () => this._validate(), () => this.get('user').setProperties(this.getProperties('firstName', 'lastName')), () => this.get('user').save(), () => this.set('isEditing', false) ); }
  24. Q&A