Reputation: 424
I have been looking around and found that the most common solution to my problem is to set a variable with the instance of the app/component and then using this variable to change the data
(Example 1, Example 2).
My issue is that I cannot use arrow functions (I am only allowed to use ES5 comptible JS, not my call) and that my function does not have a "previous" part to set the app instance.
var theApp = new Vue({
el: '#the-app',
data: {
selectedView: 1,
myDynamicButtonsArray: [
{
text: 'Change view!!'
onClick: function () {
// here this.selectedView should be changed
this.selectedView = 2;
}
},
{
text: 'My other button'
onClick: function () {
// Here something completely unrelated should happen
}
}
]
}
});
The I loop over myDynamicButtonsArray and load a myButton
component that executes the onClick
when clicked.
<my-button v-for="button in myDynamicButtonsArray" v-bind="button"></my-button>
The problem is that when I execute this.selectedView = 2;
the this
is not refering to the app instance but the function instance where it is being executed, makes sense.
I have tried setting the value like this:
theApp._data.selectedView = 2;
But I am not sure if this is the right approach.
The reason why I am not using the $emit
is because there are many different functions to be executed, and emiting a button-clicked
and then executing a common function with a giant switch so it does one thing or another depending on what button was pressed does not seem like a viable solution:
// MyButton component template
<button @onClick="this.$emit('button-clicked', id)">
{{ text }}
</button>
// App html
<my-button
v-for="button in myDynamicButtonsArray"
v-bind="button"
@button-clicked="buttonClicked"
>
</my-button>
// App object
var theApp = new Vue({
el: '#the-app',
data: {
selectedView: 1,
myDynamicButtonsArray: [
{
text: 'Change view!!',
id: 1
},
{
text: 'My other button',
id: 2
}
]
},
methods: {
buttonClicked: function(id) {
switch(id) {
case 1:
this.selectedView = 2;
// I am not even sure if I can use 'this' the way I want here;
break;
case 2:
// And so on for all my buttons
}
}
}
});
And emitting a different event per button does also not seem viable:
// MyButton component template
<button @onClick="this.$emit(customEventString)">
{{ text }}
</button>
// App html
<my-button
v-for="button in myDynamicButtonsArray"
v-bind="button"
@custom-event-1="customEvent1"
@custom-event-2="customEvent2"
>
</my-button>
// App object
var theApp = new Vue({
el: '#the-app',
data: {
selectedView: 1,
myDynamicButtonsArray: [
{
text: 'Change view!!',
customEventString: 'custom-event-1'
},
{
text: 'My other button',
customEventString: 'custom-event-2'
}
]
},
methods: {
customEvent1: function() {
this.selectedView = 2;
// I am not even sure if I can use 'this' the way I want here;
},
customEvent2: function() {
// Do other things
}
}
});
My question is, which is the right approach:
myApp._data
switch
insideUpvotes: 1
Views: 2114
Reputation: 3343
First you need to return a function off your data
property and second bind the this
keyword to the function
Example:
const MyButton = Vue.component('my-button', {
template: '<button v-text="text" @click="onClick"></button>',
props: ['text', 'onClick']
});
new Vue({
el: '#the-app',
components: { MyButton },
data: function() {
return {
selectedView: 1,
buttons: [
{
text: 'Change view!!',
onClick: function () {
console.log('btn 1 clicked')
// here this.selectedView should be changed
this.selectedView = 2;
}.bind(this)
},
{
text: 'My other button',
onClick: function () {
console.log('btn 2 clicked')
// Here something completely unrelated should happen
}
}
]
}
}
});
<div id="the-app">
{{ selectedView }}
<my-button v-for="(button, index) in buttons" :key="index" v-bind="button" />
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
Upvotes: 2
Reputation: 37763
You can change what this
means for any function using bind()
<button
v-for="button in myDynamicButtonsArray"
@click="bindToMe(button.onClick)()"
:key="button.text"
>{{ button.text }}</button>
methods: {
bindToMe(handler) {
return handler.bind(this);
}
}
Just note about syntax inside @click
- instead of passing handler directly, we are calling a function which returns original handler but with this
bound to the current Vue instance....
Upvotes: 1