0đź‘Ť
Another question on StackOverflow (pointed out to me by @Lawless) was asking the same question I started off with (namely, how to access the event data in a binding for an enumerated element rather than one associated with a top-level vue.js object), providing another, more direct (but imho even more arcane) approach to accomplishing the same.
To recap, starting with an HTML element generated by vue.js bound to a vuejs object obtained via enumeration
<div class="card pickup" v-for="pickup in pickups">
<select v-on:change="locationChanged">
...
</select>
</div>
How do you access both the backing object (here, pickup
) and a reference to the select
element so you can query its new value and act accordingly.
My approach was to take advantage of the fact that vuejs passes in the event by default and work around the fact that vuejs suppresses the event parameter if you explicitly provide a local object as the parameter in the callback by using a lambda:
<div class="card pickup" v-for="pickup in pickups">
<select v-on:change="e => locationChanged(e, pickup)">
...
</select>
</div>
Explicitly adding the element I’m interested in to the callback, at the cost of an extra function call/layer of indirection.
The previous answer provided a solution that takes advantage of the explicitly defined vuejs $event
variable, which is always translated to the native browser event, which can be directly used in addition to whatever other variables you wish to capture, making the solution look like this:
<div class="card pickup" v-for="pickup in pickups">
<select v-on:change="locationChanged($event, pickup)">
...
</select>
</div>
Which requires more intimate knowledge of vuejs, but avoids the closure.
However, I kept searching because it did not feel like this solution was in line with the vuejs ethos (and all I ever heard was everyone raving about how awesome the vuejs docs are, but this answer wasn’t explicitly there but rather had to be pieced together).
It seems that I was grappling with a common case of knowing what I want but not how to get there.. and my previous domain knowledge that precluded vuejs led me to the non-idiomatic approach in my question rather than how I would have solved it if I started off learning frontend development with vue.js in the first place.
In the end, I found the obvious answer I was looking for, an answer that felt like it was the correct “vuejs way” of doing it and the proper idiomatic solution to my original question:
The problem is that I was intermingling standard JS/DOM introspection with the vuejs model, and the friction arose in the transition between the two (leaky abstractions and all). I wanted a native handle to the select
element along with a vuejs object (pickup
), when what I should have been doing was using vuejs exclusively to accomplish what I needed, ultimately by binding the select
element to a vuejs object/property, and referencing that directly in my bound callback:
<div class="card pickup" v-for="pickup in pickups">
<select v-model:pickup.location v-on:change="locationChanged(pickup)">
...
</select>
</div>
With the select
element now bound to the location
property of my vuejs model, I can directly query its state/value in my locationChanged
handler and pass in my pickup
object without needing to use either $event
or a closure:
let vuePickup = new Vue({
el: '#pickups',
data: {
pickups: pickups,
},
methods: {
locationChanged: (pickup) => {
pickup.newLocation = pickup.location == -1;
}
},
});