Bryce Johnson Bryce Johnson - 4 months ago 16
Javascript Question

Why isn't my Vue method referring to the proper context (data)?

When

addTodo
is triggered and I inspect
this
inside of it, the context is the browser window, not the
data
object. So
todos
ends up being undefined.

Any idea what I'm missing?

HTML:

<div id="todo-list">
<input type="text" v-model="newTodo">
<button v-on:click="addTodo">Add</button>
<ul>
<li v-if="todos.length" v-for="todo in todos" class="todo-item">
{{ todo }}
</li>
</ul>
</div>


JS:

new Vue({
el: '#todo-list',
data: {
todos: [],
newTodo: ''
},
methods: {
addTodo: () => {
this.todos.push(this.newTodo);
this.clearNewTodo();
},
clearNewTodo: () => {
this.newTodo = '';
}
}
});

Answer

Quick fix: don't use arrow functions to declare your Vue methods.

So, your methods object should look like this:

methods: {
    addTodo: function() {
      this.todos.push(this.newTodo);
      this.clearNewTodo();
    },
    clearNewTodo: function() {
      this.newTodo = '';
    }

}

Why does this work?

You're expecting the ES6 arrow function () => {} syntax to set the context (this) the same as the old function declaration syntax function () {} would.

From MDN:

Until arrow functions, every new function defined its own this value (a new object in case of a constructor, undefined in strict mode function calls, the context object if the function is called as an "object method", etc.). This proved to be annoying with an object-oriented style of programming.

I don't know a ton about how Vue.js sets/handles context at this point, but it looks like your method is being called from your template/the DOM and the context is being passed from there into your method. Since the arrow function inherits its context, this refers to the window object.

Comments