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
88
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
Boost Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
0
330
SwiftUI Viewの責務分離
elmetal
PRO
1
240
富山発の個人開発サービスで日本中の学校の業務を改善した話
krpk1900
5
390
Pythonでもちょっとリッチな見た目のアプリを設計してみる
ueponx
1
570
Flutter × Firebase Genkit で加速する生成 AI アプリ開発
coborinai
0
160
GoとPHPのインターフェイスの違い
shimabox
2
190
ペアーズでの、Langfuseを中心とした評価ドリブンなリリースサイクルのご紹介
fukubaka0825
2
330
一休.com のログイン体験を支える技術 〜Web Components x Vue.js 活用事例と最適化について〜
atsumim
0
520
Honoのおもしろいミドルウェアをみてみよう
yusukebe
1
210
ファインディの テックブログ爆誕までの軌跡
starfish719
2
1.1k
なぜイベント駆動が必要なのか - CQRS/ESで解く複雑系システムの課題 -
j5ik2o
12
4.1k
コミュニティ駆動 AWS CDK ライブラリ「Open Constructs Library」 / community-cdk-library
gotok365
2
140
Featured
See All Featured
GitHub's CSS Performance
jonrohan
1030
460k
Build The Right Thing And Hit Your Dates
maggiecrowley
34
2.5k
Visualization
eitanlees
146
15k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
59k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.6k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
Building Your Own Lightsaber
phodgson
104
6.2k
Producing Creativity
orderedlist
PRO
344
39k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.2k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
27
1.9k
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