3. Some actions bubble
<button {{action 'save'}}></button>
Some actions don’t
{{my-button onclick=(action ‘save')}}
4. Many ways to invoke an action
called from return value?
works w/ strings
actions?
this.sendAction(
‘actionName’
);
component no yes
this.send(
‘action’
);
controller/route no n/a
this.get(
‘actionName’
)();
component yes no
5. Old actions were bad
String passing
No return values
Lazy execution-time errors about a missing action
No event
6. Closure actions are better
Function passing, closures
Return values
Render-time errors about a missing action
Event is the trigger argument
7. This is the only official public API for
attaching events to DOM
<button {{action 'save'}}></button>
8. To get consistent behavior people do this
<button {{action (action ‘save’)}}></button>
9. Attribute actions are an official public API
that has these features for DOM events
Function passing, closures
Return values
Render-time errors about a missing action
Event is trigger argument
11. <button {{better-action ‘save’ a b on=“click”}}></button>
Strawman syntax. Not a real proposal.
Always includes event name, “click”
Accepts string, which create a closure off
actions hash, or accepts a function
<button onclick={{action ‘save’ a b}}></button>
12. Behavior A
actions use addEventListener to attach to the
bubbling phase
• Web components may emit custom events. These must
be caught. Setting a handler to a property would not
catch them.
• Some events (focusin) do not call property-based
handlers
• handlers set via property (onclick=) are added to the
bubbling phase
• Merge strategy for Glimmer components is natural, both
the root element and the invocation attach listeners.
13. Dispatching events is the only way events
should send data to framework handlers
DANGER OPINIONS
• Web component and built-in elements should act similar.
Both should have an event object.
<my-wc-button {{better-action ‘bar’ on=“snap”}}> <- should
be able to expect an event regardless of if “snap” is
native. IMO.
• React has popularized “just pass a function”. WC written
this way are limited (cannot bubble, cannot be
cancelable). They couple invocation to implementation.
• We can install a convenient dispatcher. node.onsnap =
node.onsnap || (…arguments) => node.dispatchEvent(new
CustomEvent(‘snap’, {detail: arguments}))
14. Behavior B
actions are called with the event
• Devs want to access the event object
• Closure actions already have value= which is sugar to
help read properties off events
• dispatched events can only emit an event, they cannot
pass multiple arguments
16. <button onclick={{action ‘save'}}></button>
• Matches what many people do today
• no special rules for the event name (capitalization,
dashes etc)
• How does oncustom= work? All on* are treated like event
handlers (only=)? Configurable whitelist?
plain property
17. <button on-click={{action ‘save'}}></button>
• A special rule for naming. Put on- at the start
• of the event name
• Not what people do today
• If cargo-culted into glimmer components,
• annoying to this.attrs[‘on-foo’] vs this.attrs.onfoo.
kebab property