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
110
0
Share
EmberJS Amsterdam - Closure Actions
Marten
March 10, 2016
More Decks by Marten
See All by Marten
Ember Service Worker - EmberFest Edition
martndemus
5
610
Ember.Object
martndemus
0
80
Other Decks in Programming
See All in Programming
ドメインイベントでビジネスロジックを解きほぐす #phpcon_odawara
kajitack
3
780
forteeの改修から振り返るPHPerKaigi 2026
muno92
PRO
3
290
ルールルルルルRubyの中身の予備知識 ── RubyKaigiの前に予習しなイカ?
ydah
1
180
The Monolith Strikes Back: Why AI Agents ❤️ Rails Monoliths
serradura
0
340
Swift Concurrency Type System
inamiy
0
530
SREに優しいTerraform構成 modulesとstateの組み方
hiyanger
2
130
感情を設計する
ichimichi
5
1.5k
AI-DLC Deep Dive
yuukiyo
9
4.2k
実践ハーネスエンジニアリング #MOSHTech
kajitack
7
6.5k
ローカルで稼働するAI エージェントを超えて / beyond-local-ai-agents
gawa
3
280
NakouPAY説明用
annouim0
0
170
iOS機能開発のAI環境と起きた変化
ryunakayama
0
180
Featured
See All Featured
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.2k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
160
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
110
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
100
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
680
Leo the Paperboy
mayatellez
7
1.7k
AI: The stuff that nobody shows you
jnunemaker
PRO
6
570
KATA
mclloyd
PRO
35
15k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
490
How to make the Groovebox
asonas
2
2.1k
Into the Great Unknown - MozCon
thekraken
41
2.4k
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