I want do something like
<div onclick={handler('world')}>Say hello</div>
<script>
handler(a) {
console.log('Hello ' + a); // Hello world
}
</script>
<div onclick={ handler('world') }>Say hello</div>
<script>
handler(a) {
return function(e) {
console.log('Hello ' + a); // Hello world
}
}
</script>
Seems a bit hackish, thanks for the tip
It would be quite sweet if somehow the arguments could be attached to the event
Yes something like
<div onclick={handler('world')}>Say hello</div>
<script>
handler(e, a) {
console.log('Hello ' + a); // Hello world
}
</script>
or
<script>
handler(e) {
console.log('Hello ' + e.args[0); // Hello world
}
</script>
We can use dataset attributes, too.
http://jsfiddle.net/cognitom/38yg4Ld6/
<div data-message="world" onclick={ handler }>Say hello</div>
<script>
handler (e) {
console.log('Hello ' + e.target.dataset.message); // Hello world
}
</script>
:+1:
@cognitom - that's cute.
I've actually found what you're asking for to be a bit of an anti-pattern, at least when using React. Whatever data you need to pass along should be passed down to this tag as opts or calculated by script in the lifecycle methods. It's way easier to access the data directly from the tag instance rather than pass it through the event.
@swese44 thanks for point it, please could you expand the explanation with a example how to avoid this anti-pattern?
<div onclick={handler()}>Say hello</div>
<script>
this.worldText = 'world';
var self = this;
handler(event) {
// Get worldText from the option passed into this tag from the parent:
console.log('Hello ' + self.opts.worldText);
// Or get worldText from the tag's current state
console.log('Hello ' + self.worldText);
}
</script>
It's more difficult to thread data through the event to the handler, I've found it easier to just grab the data when you need it within the handler method.
I think the use case is when there's no custom tags, e.g.
<custom-select>
<button onclick={ click() } dir=-1>left></button>
<button onclick={ click() } dir=1>right></button>
</custom-select>
In this case we need to lookup the "dir" attribute on the root.
var dir = parseInt(e.root.attributes.dir.value)
I think @swese44's point is true when making the stateless components. But sometimes, a kind of "root component" could be more complex and needs common methods in the tag as @weepy mentioned. It depends on the readability, too. Here's other example I've encountered before:
// Multiple methods
<my-tag>
<button onclick={ goProducsts }>Products</button>
<button onclick={ goUsers }>Users</button>
</my-tag>
// Single method with attributes
<my-tag>
<button onclick={ go } data-page="products">Products</button>
<button onclick={ go } data-page="users">Users</button>
</my-tag>
In this case, go method is so common, I chose the other way like this:
// Extract it as a child tag
<my-tag>
<btn href="products">Products</btn>
<btn href="users">Users</btn>
</my-tag>
<btn>
<button onclick={ click }><yield /></button>
click (e) {
location.href = opts.href
}
</btn>
Anyway, this thread is a good discussion. Some may need this information on the docs :)
For the other reader's information: inside the loop, we could grab the data directly via event.item fortunately. See this article:
http://riotjs.com/guide/#event-handlers-with-looped-items
handler.bind(this, arg1, arg2)
handler.bind(this, arg1, arg2) is awesome
@cognitom @swese44 yeah, looped items are a very good usage example, thanks @cognitom
@cognitom the link does not work anymore
@brauliobo oops, document was moved to the new repo. I've updated the link above. Thank for letting me know.
So is there any non-hackish way to do this?
data- isn't really an option if you have elements inside the element you're clicking...
i.e
<button data-id="123"><i class="icon-save"></i> Save</button>
If you click the i then dataset is undefined since it belongs to the button. Then you have to find the parent... and its all too complicated.
@pitaj’s suggestion is non-hackish IMHO. Ie using .bind to prefill arguments
@pitaj could you please provide an example
@rkmax this is the example I am closing this question because you got many different solutions to handle it
Mb consider adding to the docs as it a FAQ
On Tue, 15 Dec 2015 23:02 Gianluca Guarini [email protected] wrote:
Closed #1001 https://github.com/riot/riot/issues/1001.
—
Reply to this email directly or view it on GitHub
https://github.com/riot/riot/issues/1001#event-492824957.
I compared 3 ways of using event handler, _use event.item_ is tedious and not intuitionally,
Maybe consider adding _use closure_ and/or _use bind_ to the docs or FAQ.
http://riotjs.com/guide/#event-handlers-with-looped-items
<todo>
<div each={ items }>
<h3>{ title }</h3>
<a onclick={ parent.remove }>Remove</a>
</div>
this.items = [ { title: 'First' }, { title: 'Second' } ]
remove(event) {
// looped item
var item = event.item
// index on the collection
var index = this.items.indexOf(item)
// remove from collection
this.items.splice(index, 1)
}
</todo>
use closure
<todo>
<div each={ todo, i in items }>
<h3>{ todo.title }</h3>
<a onclick={ remove(i) }>Remove</a>
</div>
this.items = [ { title: 'First' }, { title: 'Second' } ]
remove(index) {
return () => {
this.items.splice(index, 1)
}
}
</todo>
use bind
<todo>
<div each={ todo, i in items }>
<h3>{ todo.title }</h3>
<a onclick={ remove.bind(this, i) }>Remove</a>
</div>
this.items = [ { title: 'First' }, { title: 'Second' } ]
remove(index) {
this.items.splice(index, 1)
}
</todo>
For what it's worth I ended up using data-id="..." attributes.
I figured out you can get the correct element from the sub element click events by using currentTarget
<todo>
<div each={ todo, i in items }>
<h3>{ todo.title }</h3>
<a onclick={ remove } data-index={ i }><i class="icon icon-trash"></i> Remove</a>
</div>
this.items = [ { title: 'First' }, { title: 'Second' } ]
remove(e) {
var index = parseInt(e.currentTarget.getAttribute('data-index'));
this.items.splice(index, 1)
}
</todo>
This means the attributes are available when the target element is the <i>
I prefer the following, it's the most straightforward
<div onClick={() => this.setFilter('price')}>
<h4>Price</h4>
</div>
setFilter(value) {
console.log(value);
}
@matthlavacka it also worked without this. just shorter version.
<div onClick={() =>setFilter('price')}>
<h4>Price</h4>
</div>
I prefer the following, it's the most straightforward
<div onClick={() => this.setFilter('price')}> <h4>Price</h4> </div>setFilter(value) { console.log(value); }
Yep this is the way to go..arrow functions to the rescue!
If you're using the es6 syntax, this worked for me, 👍
<my-tag>
<button onclick={ sayHello('world') }>Say Hello</button>
<script>
this.sayHello = (a) => (e) => { console.log('hello ' + a); }
</script>
</my-tag>
NOTE: It's the same thing as @cognitom's first response, just a little more compact. 😃
@rkmax @guyskk @riot @cognitom I needed little help on the same topic discussed above:
Most helpful comment