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
86
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
67
Other Decks in Programming
See All in Programming
どうして手を動かすよりもチーム内のコードレビューを優先するべきなのか
okashoi
3
280
短期間での新規プロダクト開発における「コスパの良い」Goのテスト戦略」 / kamakura.go
n3xem
2
170
責務を分離するための例外設計 - PHPカンファレンス 2024
kajitack
8
1.8k
情報漏洩させないための設計
kubotak
3
500
数十万行のプロジェクトを Scala 2から3に完全移行した
xuwei_k
0
310
テストコード書いてみませんか?
onopon
2
170
htmxって知っていますか?次世代のHTML
hiro_ghap1
0
350
17年周年のWebアプリケーションにTanStack Queryを導入する / Implementing TanStack Query in a 17th Anniversary Web Application
saitolume
0
250
Zoneless Testing
rainerhahnekamp
0
120
毎日13時間もかかるバッチ処理をたった3日で60%短縮するためにやったこと
sho_ssk_
1
240
快速入門可觀測性
blueswen
0
400
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
Featured
See All Featured
Statistics for Hackers
jakevdp
796
220k
Embracing the Ebb and Flow
colly
84
4.5k
Large-scale JavaScript Application Architecture
addyosmani
510
110k
Optimizing for Happiness
mojombo
376
70k
Site-Speed That Sticks
csswizardry
2
190
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
48
2.2k
How to train your dragon (web standard)
notwaldorf
88
5.7k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
32
2.7k
Speed Design
sergeychernyshev
25
670
Measuring & Analyzing Core Web Vitals
bluesmoon
4
170
ReactJS: Keep Simple. Everything can be a component!
pedronauck
665
120k
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