Another feature Metal.js has that can be very useful is the ability to declare events inside templates, directly on the desired element. Besides being simple and intuitive, this feature allows Metal.js to handle attaching events itself, and so this can be done in the best way possible, with delegates for example, without the user having worry about that at all. These events are also automatically detached when the component is disposed.
Inline Events Guide
Inline Listeners - via Function Name
You can add DOM event listeners easily through your templates, like this:
<button onClick="close" type="button" class="close">
The above code declares that whenever the x button is clicked, the close
function from the component should be called.
Inline Listeners - via Function Reference
If you prefer though, you can also pass the actual function reference (instead of just its name) as an inline listener.
// src/Modal.soy
/**
* In the "render" template, soy params that match a
* component's function name will be that function
* (automatically bound to the component instance).
*/
{template .render}
{@param close: any}
// ...
<button onClick="{$close}" type="button" class="close">
// ...
{/template}
// src/Modal.js
<button onClick={this.close.bind(this)} type="button" class="close">
That will work exactly the same way as the previous example.
Inline Listeners - Nested Components
When using nested components it's also possible to inline events by using the events property:
// src/Modal.soy
{call Button.render}
{param events: ['click': ['selector': 'button', 'fn': 'close']] /}
{param label: 'Ok' /}
{/call}
// src/Modal.js
var events = {click: {
selector: 'button',
fn: 'close'
}};
<Button events={events} label="Ok" />
This will cause the close
function from the sub component to be called whenever a click event triggers for the elements that match the given selector.
In case you want to listen to the event with a function from the parent component, just pass the function reference instead of a string, like this:
// src/Modal.soy
{call Button.render}
{param events: ['click': ['selector': 'button', 'fn': $close]] /}
{param label: 'Ok' /}
{/call}
// src/Modal.js
var events = {click: {
selector: 'button',
fn: this.close.bind(this)
}};
<Button events={events} label="Ok" />
Besides DOM events, you can also listen to custom events from the sub component in this same way:
// src/Modal.soy
{call Button.render}
{param events: ['labelChanged': $handleLabelChanged] /}
{param label: 'Ok' /}
{/call}
// src/Modal.js
var events = {labelChanged: this.handleLabelChanged.bind(this)};
<Button events={events} label="Ok" />
Inline Listeners - Alternative Usage
Besides the on[EventName]
format you can also use data-on[eventname]
for adding inline listeners. For example:
<button data-onclick="close" type="button" class="close">
Note that this format is supported mainly to enable doing progressive enhancement, when running Soy templates via Java for example. When templates using the on[EventName]
format run in Java they will output elements with these as actual attributes, which can cause errors in the browser. In JavaScript these are used as element properties instead, so this problem doesn't occur.
So feel free to use the format you like best, or that better fits your needs.
Contribute on Github! Edit this section.