1

I have a Vue(2.5+) component where I'm setting a data property to a new Foo object. Using foo.bar() in the click handler calls the method correctly, but throws Uncaught TypeError: cannot set property 'someVariable' of null when trying to modify properties inside the Foo class. Setting it up so that Foo is an object literal instead of a class also does not resolve the error.

I suspect something weird is happening with this, between the component and the class?

Vue component

import Foo from './foo.js'
export default {
    template: `<div @click="foo.bar"></div>`,
    data() {
        return {
            foo: new Foo()
        }
    },
    created() {
        console.log(foo); // foo is not null here
    }
}

Foo class

export default class Foo
{
    constructor()
    {
        this.someVariable = 0;
    }

    bar(e)
    {
        // modify this.someVariable
    }
}

but if I change the vue component to reference the external method through it's own "methods" property, it works.

Vue component (working)

import Foo from './foo.js'
export default {
    template: `<div @click="bar"></div>`,
    data() {
        return {
            foo: new Foo()
        }
    },
    methods: {
        bar(e) {
            this.foo.bar(e);
        }
    }
}
4
  • 1
    foo.bar is a function without any context attached to it, either bind the context or delegate as shown in your question Commented Nov 5, 2018 at 22:51
  • Wouldn't the context be the component? Commented Nov 6, 2018 at 0:07
  • Here what you intended to do was foo.bar.bind(foo). Commented Nov 6, 2018 at 10:30
  • Thank you. Will you please elaborate why this must be done and explain more of the context? If you post in the form of an answer, I could accept it. Commented Nov 7, 2018 at 18:05

1 Answer 1

1

As said in the comments, foo.bar without any context attached to it :

In JS functions are objects, just like any object they have their own this "pointer".
In the evaluation of their body, this is bound to a specific object referred to as context which is either the default context (automatically set) or user defined (manually set).

Inheritance in JS is achieved through a prototype chain and methods should be defined on/attached to the class's prototype. Because of this, when you call foo.bar() :

  • You are in a method call context, therefore foo will be bound to the method
  • bar is searched on the object first then in the prototype chain

But methods behave just like any other property : when you do foo.bar you get a reference to the actual method which is an unbound function (default behavior for methods, since it is bound when called on an object).

Therefore, what you really need to do in this situation is foo.bar.bind(foo).

I would also suggest taking a quick look into this ES6 proposal for a bind operator and its implementation as a Babel plugin which allows nice things like passing ::foo.bar instead of foo.bar.bind(foo)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.