Vue.js inheritance call parent method

26,094

Solution 1

No, vue doesn't work with a direct inheritance model. You can't A.extend an component, as far as I know. It's parent-child relationships work mainly through props and events.

There are however three solutions:

1. Passing props (parent-child)

var SomeComponentA = Vue.extend({
    methods: {
        someFunction: function () {
            // ClassA some stuff
        }
    }
});

var SomeComponentB = Vue.extend({
   props: [ 'someFunctionParent' ],
   methods: {
       someFunction: function () {
           // Do your stuff
           this.someFunctionParent();
       }
   }
});

and in the template of SomeComponentA:

<some-component-b someFunctionParent="someFunction"></some-component-b>

2. Mixins

If this is common functionality that you want to use in other places, using a mixin might be more idiomatic:

var mixin = {
    methods: {
        someFunction: function() {
            // ...
        }
    }
};

var SomeComponentA = Vue.extend({
    mixins: [ mixin ],
    methods: {
    }
});

var SomeComponentB = Vue.extend({
   methods: {
       someFunctionExtended: function () {
           // Do your stuff
           this.someFunction();
       }
   }
});

3. Calling parent props (parent-child, ugly)

// In someComponentB's 'someFunction':
this.$parent.$options.methods.someFunction(...);

Solution 2

In case someone's interested in a JustWorksTM solution:

var FooComponent = {
  template: '<button @click="fooMethod()" v-text="buttonLabel"></button>',

  data: function () {
   return {
     foo: 1,
     bar: 'lorem',
     buttonLabel: 'Click me',
   }
  },

  methods: {
    fooMethod: function () {
      alert('called from FooComponent');
    },
    
    barMethod: function () {
      alert('called from FooComponent');
    },
  }
}

var FooComponentSpecialised = {
  extends: FooComponent,

  data: function () {
   return {
     buttonLabel: 'Specialised click me',
     zar: 'ipsum',
   }
  },

  methods: {
    fooMethod: function () {
      FooComponent.methods.fooMethod.call(this);
    
      alert('called from FooComponentSpecialised');
    },
  }
}

jsfiddle: https://jsfiddle.net/7b3tx0aw/2/


More info:

  1. This solution is for devs that can't use TypeScript for some reason (which I think allows defining vue components as classes, which in turn allows full inheritance feature-set).
  2. Further elaboration about the solution (whys and hows): https://github.com/vuejs/vue/issues/2977
  3. This ain't that ugly, considering that no rocket science is used here (calling anonymous functions with the this pointer replaced should be no magic for any decent js dev).

How to use Function.prototype.call()

Reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call

Sample code:

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

console.log(new Food('cheese', 5).name);
// expected output: "cheese"

Solution 3

In case someone asks for a solution here is mine and works fine :

var SomeClassA = {
    methods: {
        someFunction: function () {
            this.defaultSomeFunction();
        },
        // defaultSomeFunction acts like parent.someFunction() so call it in inheritance
        defaultSomeFunction: function () {
            // ClassA some stuff
        },
    },
};

var SomeClassB = {
    extends: SomeClassA,
    methods: {
        someFunction: function () {
            // Replace the wanted SomeClassA::someFunction()
            this.defaultSomeFunction();
            // Add custom code here
        },
    },
};

using juste extends from https://vuejs.org/v2/api/#extends replaces the usage of Vue.extends()

Share:
26,094
MyFantasy512
Author by

MyFantasy512

Updated on July 10, 2022

Comments

  • MyFantasy512
    MyFantasy512 almost 2 years

    Is it possible to use method overriding in Vue.js?

    var SomeClassA = Vue.extend({
      methods: {
        someFunction: function() {
          // ClassA some stuff
        }
      }
    });
    
    var SomeClassB = SomeClassA.extend({
      methods: {
        someFunction: function() {
          // CALL SomeClassA.someFunction
        }
      }
    });
    

    I want to call ClassA someFunction from ClassB someFunction. Is it even possible?

  • MyFantasy512
    MyFantasy512 about 8 years
    1. It's pretty good solution when it comes to last resort, but it's not very extensible. 2. I've thought about using Mixins here, but necessity of changing function names is not extensible either. 3. Can u even get this working!? jsfiddle.net/9s146cdr/1 . This would be best bet, if only it was true :)
  • nils
    nils about 8 years
    I really don't recommend using #3 and I only included it for reference. The other two are much more idiomatic for vue (inheritance generally doesn't make too much sense, since componentA is not an abstract class but a parent component in the DOM with different responsibilities than componentB). It probably helps if you think less about extensibility and more about component responsibilities.
  • MyFantasy512
    MyFantasy512 about 8 years
    You can't use #3 because it's not working :) I cannot agree with since componentA is not an abstract class but a parent component in the DOM with different responsibilities than componentB because I miss-named classes, it should be SomeAbstractComponentA. I come to Vue from Ember, and in my opinion inheritance in components isn't anything wrong.
  • nils
    nils about 8 years
    Also, your example of using vue is not correct. You shouldn't call new on a component. I'll prepare an example... This is not Ember ;)
  • MyFantasy512
    MyFantasy512 about 8 years
    Of course this fiddle was just to prove that #3 option is not working. I am instancing components in templates.
  • MyFantasy512
    MyFantasy512 about 8 years
    Stepping aside component responsibilities, you cannot say that extensibility using simple concept like overriding methods, is too much abstraction for any framework.
  • nils
    nils about 8 years
    Well, option 3 only works in parent-child relationships of components. As I said, you can't do A.extend. If you want to extend from an independent component (not in a parent-child relationship), mixins are the only options at the moment. Actual method overriding was only introduced in ES6 classes in JavaScript, it was not native to the language before.
  • nils
    nils about 8 years
    If you really need direct extensibility, you could always write a plugin
  • MyFantasy512
    MyFantasy512 about 8 years
    Thanks for clarification, as I see Vue extend functionallity doesn't provide inheritance functionallity. In that case, Mixins are best solutions. Not what I expected, but thanks for giving the right direction in Vue, thanks
  • MyFantasy512
    MyFantasy512 about 8 years
    So I will just post some quick super call implementation, maybe someone would find this useful one day :) jsfiddle.net/dtq6obLp
  • akousmata
    akousmata over 4 years
    Late to the party and newer Vue dev, but everything I've read thus far in blogs and official documentation discourages option 1 in favor of using $emit in the child and handling the event in the parent.
  • Hamish
    Hamish almost 4 years
    I don't know if something has changed since this post but I needed FooComponent.options.methods.fooMethod.call(this);