Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
EmberJS Amsterdam - Closure Actions
Search
Marten
March 10, 2016
Programming
0
90
EmberJS Amsterdam - Closure Actions
Marten
March 10, 2016
Tweet
Share
More Decks by Marten
See All by Marten
Ember Service Worker - EmberFest Edition
martndemus
5
580
Ember.Object
martndemus
0
70
Other Decks in Programming
See All in Programming
TypeScript Language Service Plugin で CSS Modules の開発体験を改善する
mizdra
PRO
3
2.4k
コンポーネントライブラリで実現する、アクセシビリティの正しい実装パターン
schktjm
1
670
技術懸念に立ち向かい 法改正を穏便に乗り切った話
pop_cashew
0
830
TypeScript エンジニアが Android 開発の世界に飛び込んだ話
yuisakamoto
6
960
がんばりすぎないコーディングルール運用術
tsukakei
1
180
コードに語らせよう――自己ドキュメント化が内包する楽しさについて / Let the Code Speak
nrslib
5
1.1k
Parallel::Pipesの紹介
skaji
2
870
Building an Application with TDD, DDD and Hexagonal Architecture - Isn't it a bit too much?
mufrid
0
370
Agent Rules as Domain Parser
yodakeisuke
1
350
Perlで痩せる
yuukis
1
660
Passkeys for Java Developers
ynojima
0
190
TVer iOSチームの共通認識の作り方 - Findy Job LT iOSアプリ開発の裏側 開発組織が向き合う課題とこれから
techtver
PRO
0
710
Featured
See All Featured
Build your cross-platform service in a week with App Engine
jlugia
231
18k
GitHub's CSS Performance
jonrohan
1031
460k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
14
1.5k
How GitHub (no longer) Works
holman
314
140k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
45
7.3k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
137
34k
Mobile First: as difficult as doing things right
swwweet
223
9.6k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
34
2.3k
Making the Leap to Tech Lead
cromwellryan
134
9.3k
Product Roadmaps are Hard
iamctodd
PRO
53
11k
Statistics for Hackers
jakevdp
799
220k
Transcript
CLOSURE ACTIONS EMBER.JS
MARTEN SCHILSTRA @martndemus HELLO MY NAME IS:
I WORK FOR:
CLOSURE ACTIONS EMBER.JS
CLASSIC ACTIONS BEFORE CLOSURE ACTIONS
<button {{action “submit”}}> Submit </button> BINDING ACTIONS TO HTML ELEMENTS
<button {{action “submit”}}> Submit </button> BINDING ACTIONS TO HTML ELEMENTS
<button {{action “submit”}}> Submit </button> BINDING ACTIONS TO HTML ELEMENTS
element action keyword
<form {{action “submit” on=“submit”}}> <!—— form fields ——> <input type=“submit”
/> </form> BINDING ACTIONS TO HTML ELEMENTS
{{#x-button action=“save”}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS
{{#x-button action=“save”}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS
{{#x-button action=“save”}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS an attribute
actions: { submit() { this.sendAction(); } } CALLING ACTIONS FROM
YOUR COMPONENT
actions: { submit() { this.sendAction(); } } CALLING ACTIONS FROM
YOUR COMPONENT
actions: { submit() { this.sendAction(); } } CALLING ACTIONS FROM
YOUR COMPONENT actions hash
actions: { submit() { this.sendAction(); } } CALLING ACTIONS FROM
YOUR COMPONENT
actions: { submit() { this.sendAction(); } } CALLING ACTIONS FROM
YOUR COMPONENT
actions: { saveModel() { // saves model }, submit()
{ this.send(‘saveModel’); } } CALLING ACTIONS FROM YOUR COMPONENT
actions: { saveModel() { // saves model }, submit()
{ this.send(‘saveModel’); } } CALLING ACTIONS FROM YOUR COMPONENT
LOOKS GOOD
LOOKS GOOD, RIGHT?
BUBBLING UP COMPONENTS
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
// controllers/login.js actions: { login(username, password) { // logic }
} {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
// components/login-form.js actions: { submit() { this.sendAction(‘login’, get(this, ‘username’), get(this,
‘password’)); } } {{! templates/components/login-form.hbs }} {{#x-button action=“submit”}} Login {{/x-button}} COMPONENTS/LOGIN-FORM
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
// components/x-button.js actions: { click() { this.sendAction(); } } {{!
templates/components/x-button.hbs }} <button {{action “click”}}> {{yield}} </button> COMPONENTS/X-BUTTON
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
// components/x-button.js actions: { click() { this.sendAction(); } } {{!
templates/components/x-button.hbs }} <button {{action “click”}}> {{yield}} </button> COMPONENTS/X-BUTTON
// components/x-button.js actions: { click() { this.sendAction(); } } {{!
templates/components/x-button.hbs }} <button {{action “click”}}> {{yield}} </button> COMPONENTS/X-BUTTON
// components/x-button.js actions: { click() { this.sendAction(); } } {{!
templates/components/x-button.hbs }} <button {{action “click”}}> {{yield}} </button> COMPONENTS/X-BUTTON
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
// components/login-form.js actions: { submit() { this.sendAction(‘login’, get(this, ‘username’), get(this,
‘password’)); } } {{! templates/components/login-form.hbs }} {{#x-button action=“submit”}} Login {{/x-button}} COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { this.sendAction(‘login’, get(this, ‘username’), get(this,
‘password’)); } } {{! templates/components/login-form.hbs }} {{#x-button action=“submit”}} Login {{/x-button}} COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { this.sendAction(‘login’, get(this, ‘username’), get(this,
‘password’)); } } {{! templates/components/login-form.hbs }} {{#x-button action=“submit”}} Login {{/x-button}} COMPONENTS/LOGIN-FORM
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
// controllers/login.js actions: { login(username, password) { // logic }
} {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password) { // logic }
} {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
{{login-form login=“login”}} {{x-button action=“submit”}} <button {{action “click”}}> login components/login-form components/x-button
BUBBLING UP COMPONENTS
RETURN VALUES
{{login-form login=“login”}} <button {{action=“submit”}}> login components/login-form RETURN VALUES
{{login-form login=“login”}} login components/login-form RETURN VALUES <button {{action=“submit”}}>
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button {{action “submit”}}>Login</button> {{/if}} COMPONENTS/LOGIN-FORM
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button {{action “submit”}}>Login</button> {{/if}} COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let setUser = user
=> set(this, ‘user’, user); this.sendAction(‘login’, get(this, ‘username’), get(this, ‘password’), setUser); } } COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let setUser = user
=> set(this, ‘user’, user); this.sendAction(‘login’, get(this, ‘username’), get(this, ‘password’), setUser); } } COMPONENTS/LOGIN-FORM
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form action=“login”}} LOGIN
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form action=“login”}} LOGIN
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button {{action “submit”}}>Login</button> {{/if}} COMPONENTS/LOGIN-FORM
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button {{action “submit”}}>Login</button> {{/if}} COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let setUser = user
=> set(this, ‘user’, user); this.sendAction(‘login’, get(this, ‘username’), get(this, ‘password’), setUser); } } COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let setUser = user
=> set(this, ‘user’, user); this.sendAction(‘login’, get(this, ‘username’), get(this, ‘password’), setUser); } } COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let setUser = user
=> set(this, ‘user’, user); this.sendAction(‘login’, get(this, ‘username’), get(this, ‘password’), setUser); } } COMPONENTS/LOGIN-FORM
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
// components/login-form.js actions: { submit() { let setUser = user
=> set(this, ‘user’, user); this.sendAction(‘login’, get(this, ‘username’), get(this, ‘password’), setUser); } } COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let setUser = user
=> set(this, ‘user’, user); this.sendAction(‘login’, get(this, ‘username’), get(this, ‘password’), setUser); } } COMPONENTS/LOGIN-FORM
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} {{#x-button action=“submit”}} Login {{/x-button}} {{/if}} COMPONENTS/LOGIN-FORM
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} {{#x-button action=“submit”}} Login {{/x-button}} {{/if}} COMPONENTS/LOGIN-FORM
{{login-form login=“login”}} login components/login-form RETURN VALUES user <button {{action=“submit”}}>
CLOSURE ACTIONS INTRODUCING
{{! before}} <button {{action “submit”}}> Submit </button> BINDING ACTIONS TO
HTML ELEMENTS
{{! before}} <button {{action “submit”}}> Submit </button> {{! with closure
actions}} <button onclick={{action “submit”}}> Submit </button> BINDING ACTIONS TO HTML ELEMENTS
<button onclick={{action “submit”}}> Submit </button> BINDING ACTIONS TO HTML ELEMENTS
<button onclick={{action “submit”}}> Submit </button> BINDING ACTIONS TO HTML ELEMENTS
<button onclick={{action “submit”}}> Submit </button> BINDING ACTIONS TO HTML ELEMENTS
closure action keyword
{{! before}} <form {{action “submit” on=“submit”}}> <!—— form fields ——>
</form> BINDING ACTIONS TO HTML ELEMENTS
{{! before}} <form {{action “submit” on=“submit”}}> <!—— form fields ——>
</form> {{! with closure actions}} <form onsubmit={{action “submit”}}> <!—— form fields ——> </form> BINDING ACTIONS TO HTML ELEMENTS
<form onsubmit={{action “submit”}}> <!—— form fields ——> </form> BINDING ACTIONS
TO HTML ELEMENTS
<form onsubmit={{action “submit”}}> <!—— form fields ——> </form> BINDING ACTIONS
TO HTML ELEMENTS
<form onsubmit={{action “submit”}}> <!—— form fields ——> </form> BINDING ACTIONS
TO HTML ELEMENTS event attribute on element
{{! before}} {{#x-button action=“submit”}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS
{{! before}} {{#x-button action=“submit”}} Submit {{/x-button}} {{! with closure actions}}
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS closure
action keyword
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS {{#x-button
click=(action submit)}} Submit {{/x-button}}
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS {{#x-button
click=(action submit)}} Submit {{/x-button}}
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS {{#x-button
click=(action submit)}} Submit {{/x-button}}
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS {{#x-button
click=(action submit)}} Submit {{/x-button}} no quotes!
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS {{#x-button
click=(action submit)}} Submit {{/x-button}}
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS {{#x-button
click=(action submit)}} Submit {{/x-button}} action called from actions hash
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS {{#x-button
click=(action submit)}} Submit {{/x-button}}
{{#x-button click=(action “submit”)}} Submit {{/x-button}} BINDING ACTIONS TO COMPONENTS {{#x-button
click=(action submit)}} Submit {{/x-button}} action called from component attributes
// before actions: { submit() { this.sendAction(‘submit’); } } CALLING
ACTIONS FROM YOUR COMPONENT
// before actions: { submit() { this.sendAction(‘submit’); } } //
with closure actions actions: { submit() { get(this, ‘submit’)(); } } CALLING ACTIONS FROM YOUR COMPONENT
actions: { submit() { get(this, ‘submit’)(); } } CALLING ACTIONS
FROM YOUR COMPONENT
actions: { submit() { get(this, ‘submit’)(); } } CALLING ACTIONS
FROM YOUR COMPONENT
actions: { submit() { get(this, ‘submit’)(); } } CALLING ACTIONS
FROM YOUR COMPONENT
I THOUGHT YOU SHOULD USE this.attrs.submit();
NO YOU SHOULDN'T locks.svbtle.com/to-attrs-or-not-to-attrs by Ricardo “locks” Mendes
CLOSURE ACTIONS DEEP-DIVE INTO
CLOSURE ACTIONS ACTION PASSING CURRYING RETURN VALUES FIRST ARGUMENT VALUE
OVERRIDING FUNCTIONS
CLOSURE ACTIONS ACTION PASSING CURRYING RETURN VALUES FIRST ARGUMENT VALUE
OVERRIDING FUNCTIONS
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
// controllers/items.js actions: { saveItem(item) { item.save(); } } ITEMS
{{! templates/items.hbs {{item-list saveItem=(action “saveItem”)}}
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{! templates/components/item-list.hbs {{#each items as |item|}} {{item-detail item=item saveItem=(action saveItem)}}
{{/each}} COMPONENTS/ITEM-LIST
{{! templates/components/item-list.hbs {{#each items as |item|}} {{item-detail item=item saveItem=(action saveItem)}}
{{/each}} COMPONENTS/ITEM-LIST no quotes!
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{! templates/components/item-detail.hbs <button onclick={{action saveItem item}}> Save </button> COMPONENTS/ITEM-DETAIL
{{! templates/components/item-detail.hbs <button onclick={{action saveItem item}}> Save </button> COMPONENTS/ITEM-DETAIL again
no quotes!
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{! templates/components/item-detail.hbs <button onclick={{action saveItem item}}> Save </button> COMPONENTS/ITEM-DETAIL
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{! templates/components/item-list.hbs {{#each items as |item|}} {{item-detail item=item saveItem=(action saveItem)}}
{{/each}} COMPONENTS/ITEM-LIST
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
// controllers/items.js actions: { saveItem(item) { item.save(); } } ITEMS
{{! templates/items.hbs {{item-list saveItem=(action “saveItem”)}}
// controllers/items.js actions: { saveItem(item) { item.save(); } } ITEMS
{{! templates/items.hbs {{item-list saveItem=(action “saveItem”)}}
{{item-list saveItem=(action “saveItem”)}} {{item-detail saveItem=(action saveItem)}} <button onclick={{action saveItem item}}>
items components/item-list components/item-detail ACTION PASSING
CLOSURE ACTIONS ACTION PASSING CURRYING RETURN VALUES FIRST ARGUMENT VALUE
OVERRIDING FUNCTIONS
{{item-list itemAction=(action “doAction”)}} {{item-detail itemAction=(action itemAction item)}} <button onclick={{action itemAction
“save”}}> <button onclick={{action itemAction “destroy”}}> items components/item-list components/item-detail CURRYING
{{item-list itemAction=(action “doAction”)}} {{item-detail itemAction=(action itemAction item)}} <button onclick={{action itemAction
“save”}}> <button onclick={{action itemAction “destroy”}}> items components/item-list components/item-detail CURRYING
// controllers/items.js actions: { doAction(item, action) { item[action](); } }
ITEMS {{! templates/items.hbs {{item-list itemAction=(action “doAction”)}}
// controllers/items.js actions: { doAction(item, action) { item[action](); } }
ITEMS {{! templates/items.hbs {{item-list itemAction=(action “doAction”)}}
// controllers/items.js actions: { doAction(item, action) { item[action](); } }
ITEMS {{! templates/items.hbs {{item-list itemAction=(action “doAction”)}}
// controllers/items.js actions: { doAction(item, action) { item[action](); } }
ITEMS {{! templates/items.hbs {{item-list itemAction=(action “doAction”)}}
{{item-list itemAction=(action “doAction”)}} {{item-detail itemAction=(action itemAction item)}} <button onclick={{action itemAction
“save”}}> <button onclick={{action itemAction “destroy”}}> items components/item-list components/item-detail CURRYING
{{! templates/components/item-list.hbs {{#each items as |item|}} {{item-detail item=item itemAction=(action itemAction
item)}} {{/each}} COMPONENTS/ITEM-LIST
{{! templates/components/item-list.hbs {{#each items as |item|}} {{item-detail item=item itemAction=(action itemAction
item)}} {{/each}} COMPONENTS/ITEM-LIST
{{item-list itemAction=(action “doAction”)}} {{item-detail itemAction=(action itemAction item)}} <button onclick={{action itemAction
“save”}}> <button onclick={{action itemAction “destroy”}}> items components/item-list components/item-detail CURRYING
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “save”}}> Save </button> <button onclick={{action
itemAction “destroy”}}> Destroy </button> COMPONENTS/ITEM-DETAIL
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “save”}}> Save </button> <button onclick={{action
itemAction “destroy”}}> Destroy </button> COMPONENTS/ITEM-DETAIL
{{item-list itemAction=(action “doAction”)}} {{item-detail itemAction=(action itemAction item)}} <button onclick={{action itemAction
“save”}}> <button onclick={{action itemAction “destroy”}}> items components/item-list components/item-detail CURRYING
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “save”}}> Save </button> CURRYING {{!
templates/components/item-list.hbs {{#each items as |item|}} {{item-detail item=item itemAction=(action itemAction item)}} {{/each}}
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “save”}}> Save </button> CURRYING {{!
templates/components/item-list.hbs {{#each items as |item|}} {{item-detail item=item itemAction=(action itemAction item)}} {{/each}} {{action itemAction item “save”}}
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “destroy”}}> Destroy </button> CURRYING {{!
templates/components/item-list.hbs {{#each items as |item|}} {{item-detail item=item itemAction=(action itemAction item)}} {{/each}} {{action itemAction item “destroy”}}
{{item-list itemAction=(action “doAction”)}} {{item-detail itemAction=(action itemAction item)}} <button onclick={{action itemAction
“save”}}> <button onclick={{action itemAction “destroy”}}> items components/item-list components/item-detail CURRYING
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “save”}}> Save </button> CURRYING //
controllers/items.js actions: { doAction(item, action) { item[action](); } } {{action itemAction item “save”}}
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “save”}}> Save </button> CURRYING //
controllers/items.js actions: { doAction(item, action) { item[action](); // item.save(); } } {{action itemAction item “save”}}
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “destroy”}}> Save </button> CURRYING //
controllers/items.js actions: { doAction(item, action) { item[action](); } } {{action itemAction item “destroy”}}
{{! templates/components/item-detail.hbs <button onclick={{action itemAction “destroy”}}> Save </button> CURRYING //
controllers/items.js actions: { doAction(item, action) { item[action](); // item.destroy(); } } {{action itemAction item “destroy”}}
CLOSURE ACTIONS ACTION PASSING CURRYING RETURN VALUES FIRST ARGUMENT VALUE
OVERRIDING FUNCTIONS
RETURN VALUES {{login-form login=“login”}} login components/login-form user <button {{action=“submit”}}>
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password, setUser) { let user
= this._login(username, password); setUser(user); } } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password) { return this._login(username, password);
} } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password) { return this._login(username, password);
} } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password) { return this._login(username, password);
} } {{! templates/login.hbs }} {{login-form login=“login”}} LOGIN
// controllers/login.js actions: { login(username, password) { return this._login(username, password);
} } {{! templates/login.hbs }} {{login-form login=(action “login”)}} LOGIN
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button {{action “submit”}}>Login</button> {{/if}} COMPONENTS/LOGIN-FORM
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button {{action “submit”}}>Login</button> {{/if}} COMPONENTS/LOGIN-FORM
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button onclick={{action “submit”}}> Login </button> {{/if}} COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let setUser = user
=> set(this, ‘user’, user); this.sendAction(‘login’, get(this, ‘username’), get(this, ‘password’), setUser); } } COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let user = get(this,
‘login’)( get(this, ‘username’), get(this, ‘password’) ); set(this, ‘user’, user); } } COMPONENTS/LOGIN-FORM
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button onclick={{action “submit”}}> Login </button> {{/if}} COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let user = get(this,
‘login’)( get(this, ‘username’), get(this, ‘password’) ); set(this, ‘user’, user); } } COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let user = get(this,
‘login’)( get(this, ‘username’), get(this, ‘password’) ); set(this, ‘user’, user); } } COMPONENTS/LOGIN-FORM
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
// controllers/login.js actions: { login(username, password) { return this._login(username, password);
} } {{! templates/login.hbs }} {{login-form login=(action “login”)}} LOGIN
// controllers/login.js actions: { login(username, password) { return this._login(username, password);
} } {{! templates/login.hbs }} {{login-form login=(action “login”)}} LOGIN
// controllers/login.js actions: { login(username, password) { return this._login(username, password);
} } {{! templates/login.hbs }} {{login-form login=(action “login”)}} LOGIN
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
{{login-form login=(action “login”)}} login components/login-form RETURN VALUES user <button onclick={{action
“submit”}}>
// components/login-form.js actions: { submit() { let user = get(this,
‘login’)( get(this, ‘username’), get(this, ‘password’) ); set(this, ‘user’, user); } } COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let user = get(this,
‘login’)( get(this, ‘username’), get(this, ‘password’) ); set(this, ‘user’, user); } } COMPONENTS/LOGIN-FORM
// components/login-form.js actions: { submit() { let user = get(this,
‘login’)( get(this, ‘username’), get(this, ‘password’) ); set(this, ‘user’, user); } } COMPONENTS/LOGIN-FORM
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button onclick={{action “submit”}}> Login </button> {{/if}} COMPONENTS/LOGIN-FORM
{{! templates/components/login-form.hbs }} {{#if user}} You have been successfully logged
in as: {{user.username}} {{else}} {{input value=username}} {{input value=password}} <button onclick={{action “submit”}}> Login </button> {{/if}} COMPONENTS/LOGIN-FORM
RETURN VALUES {{login-form login=“login”}} login components/login-form user <button {{action=“submit”}}>
CLOSURE ACTIONS ACTION PASSING CURRYING RETURN VALUES FIRST ARGUMENT VALUE
OVERRIDING FUNCTIONS
<input oninput={{action “updateValue”}} /> FIRST ARGUMENT VALUE
<input oninput={{action “updateValue”}} /> actions: { updateValue() { }
} FIRST ARGUMENT VALUE
<input oninput={{action “updateValue”}} /> actions: { updateValue() { }
} FIRST ARGUMENT VALUE
<input oninput={{action “updateValue”}} /> actions: { updateValue() { }
} FIRST ARGUMENT VALUE event attribute on element
<input oninput={{action “updateValue”}} /> actions: { updateValue(event) { }
} FIRST ARGUMENT VALUE
<input oninput={{action “updateValue”}} /> actions: { updateValue(event) { set(this, ‘value’,
event.target.value); } } FIRST ARGUMENT VALUE
CAN WE MAKE THIS NICER?
<input oninput={{action “updateValue”}} /> actions: { updateValue(event) { set(this, ‘value’,
event.target.value); } } FIRST ARGUMENT VALUE
<input oninput={{action “updateValue” value=“target.value”}} /> actions: { updateValue(event) {
set(this, ‘value’, event.target.value); } } FIRST ARGUMENT VALUE
<input oninput={{action “updateValue” value=“target.value”}} /> actions: { updateValue(event) {
set(this, ‘value’, event.target.value); } } FIRST ARGUMENT VALUE
<input oninput={{action “updateValue” value=“target.value”}} /> actions: { updateValue(event) {
set(this, ‘value’, event.target.value); } } FIRST ARGUMENT VALUE
<input oninput={{action “updateValue” value=“target.value”}} /> actions: { updateValue(event) {
set(this, ‘value’, event.target.value); } } FIRST ARGUMENT VALUE gets value from given path on first argument
<input oninput={{action “updateValue” value=“target.value”}} /> actions: { updateValue(event) {
set(this, ‘value’, event.target.value); } } FIRST ARGUMENT VALUE
<input oninput={{action “updateValue” value=“target.value”}} /> actions: { updateValue(value) {
set(this, ‘value’, value); } } FIRST ARGUMENT VALUE
<input oninput={{action “updateValue” value=“target.value”}} /> FIRST ARGUMENT VALUE
<input oninput={{action “updateValue” value=“target.value”}} /> FIRST ARGUMENT VALUE
<input oninput={{action updateValue value=“target.value”}} /> FIRST ARGUMENT VALUE
{{! templates/components/my-input.hbs }} <input oninput={{action updateValue value=“target.value”}} /> FIRST
ARGUMENT VALUE
{{! templates/components/my-input.hbs }} <input value={{value}} oninput={{action updateValue value=“target.value”}} />
FIRST ARGUMENT VALUE
FIRST ARGUMENT VALUE {{my-input value=value updateValue=(action “updateValue”) }}
FIRST ARGUMENT VALUE {{my-input value=value updateValue=(action “updateValue”) }} actions:
{ updateValue(value) { set(this, ‘value’, value); } }
CLOSURE ACTIONS ACTION PASSING CURRYING RETURN VALUES FIRST ARGUMENT VALUE
OVERRIDING FUNCTIONS
// components/my-input.js input(value) { get(this, ‘update’)(value); } OVERRIDING FUNCTIONS
// components/my-input.js input(value) { get(this, ‘update’)(value); } OVERRIDING FUNCTIONS <script>eval(‘alert(“1337
HAXX”);’)</script>
// components/my-input.js input(value) { get(this, ‘update’)(value); } sanitize(input) { return
input; } OVERRIDING FUNCTIONS
// components/my-input.js input(value) { let sanitized = this.sanitize(value); get(this, ‘update’)(sanitized);
} sanitize(input) { return input; } OVERRIDING FUNCTIONS
// components/my-input.js input(value) { let sanitized = this.sanitize(value); get(this, ‘update’)(sanitized);
} sanitize(input) { return input; } OVERRIDING FUNCTIONS
// components/my-sanitizing-input.js export default MyInput.extend({ sanitize(input) { return escapeEvilHTML(input); }
}); OVERRIDING FUNCTIONS
// components/my-sanitizing-input.js export default MyInput.extend({ sanitize(input) { return escapeEvilHTML(input); }
}); OVERRIDING FUNCTIONS
// components/my-sanitizing-input.js export default MyInput.extend({ sanitize(input) { return escapeEvilHTML(input); }
}); OVERRIDING FUNCTIONS
// components/my-sanitizing-input.js export default MyInput.extend({ sanitize(input) { return escapeEvilHTML(input); }
}); OVERRIDING FUNCTIONS
// components/my-input.js input(value) { let sanitized = this.sanitize(value); get(this, ‘update’)(sanitized);
} sanitize(input) { return input; } OVERRIDING FUNCTIONS
// components/my-input.js input(value) { let sanitized = this.sanitize(value); get(this, ‘update’)(sanitized);
} sanitize(input) { return input; } OVERRIDING FUNCTIONS
// components/my-input.js input(value) { let sanitized = this.sanitize(value); get(this, ‘update’)(sanitized);
} sanitize(input) { return input; } OVERRIDING FUNCTIONS an attribute
{{my-input update=(action “update”) sanitize=(action “myCustomSanitize”) }} OVERRIDING FUNCTIONS
{{my-input update=(action “update”) sanitize=(action “myCustomSanitize”) }} OVERRIDING FUNCTIONS
TROLLING OPPORTUNITY
// What will happen? actions: { alert() { alert(‘1337 HAXX0R’);
} } {{my-component init=(action “alert”)}} OVERRIDING FUNCTIONS
// This will happen! Assertion Failed: You must call
`this._super` when implementing `init` in a component. OVERRIDING FUNCTIONS
OVERRIDING FUNCTIONS
CLOSURE ACTIONS AWESOME ADDONS THAT IMPROVE ON
EMBER-INVOKE-ACTION
EMBER-INVOKE-ACTION Abstracts away some ceremony around calling closure actions Backwards
compatible with classic actions
sendAction send EMBER-INVOKE-ACTION
sendAction send EMBER-INVOKE-ACTION
sendAction send EMBER-INVOKE-ACTION invokeAction invoke
EMBER-ROUTE-ACTION-HELPER
EMBER-ROUTE-ACTION-HELPER Call actions on your route as closure actions Another
reason to forget about controllers
saveModel=(route-action “save”) EMBER-ROUTE-ACTION-HELPER
EMBER-COMPOSABLE-HELPERS
<button {{action (pipe addToCart purchase goToThankYouPage)
item}} > 1-Click Buy </button> EMBER-COMPOSABLE-ACTIONS
<button {{action (pipe addToCart purchase goToThankYouPage)
item}} > 1-Click Buy </button> EMBER-COMPOSABLE-ACTIONS
<button {{action (pipe addToCart purchase goToThankYouPage)
item}} > 1-Click Buy </button> EMBER-COMPOSABLE-ACTIONS
<button {{action (pipe addToCart purchase goToThankYouPage)
item}} > 1-Click Buy </button> EMBER-COMPOSABLE-ACTIONS
<button {{action (pipe addToCart purchase goToThankYouPage)
item}} > 1-Click Buy </button> EMBER-COMPOSABLE-ACTIONS
The square of 4 is {{compute (action "square") 4}}
EMBER-COMPOSABLE-ACTIONS
None