Skip to content
Fix Code Error

Component Inheritance with vue js

March 18, 2021 by Code Error
Posted By: Anonymous

I am trying to build a base DataComponent which will contain the common functionality required for many other components which deal with basic CRUD entities.
So far I have

_x000D_

_x000D_

//main.js_x000D_
import Vue from 'vue';_x000D_
_x000D_
new Vue({_x000D_
  el:'#app',_x000D_
  components:{_x000D_
    DataComponent,_x000D_
    Quotation_x000D_
  }_x000D_
});

_x000D_

_x000D_

_x000D_

_x000D_

_x000D_

//data-component.js_x000D_
import Vue from 'vue';_x000D_
_x000D_
export_x000D_
default Vue.extend({_x000D_
_x000D_
      data() {_x000D_
          return {_x000D_
            saved: false_x000D_
          }_x000D_
        },_x000D_
_x000D_
        methods: {_x000D_
_x000D_
          //This method will be used by all inheriting components to alert_x000D_
          //the user regarding any changes which need to be saved._x000D_
          _x000D_
          alertSave(entity, fields, intFields) {_x000D_
              var changeCount = 0;_x000D_
              fields.forEach(function(field) {_x000D_
                _x000D_
                var compareWith = this[field];_x000D_
                _x000D_
                //Here "this" need to refer to the child instance but it does not_x000D_
                //how can I achieve?_x000D_
                _x000D_
                if ((compareWith || entity[field.camelToSnake()]) &&_x000D_
                  entity[field.camelToSnake()] !== compareWith) {_x000D_
                  changeCount++;_x000D_
                }_x000D_
              });_x000D_
              intFields.forEach(function(field) {_x000D_
                var compareWith = parseInt(this[field]);_x000D_
                if ((compareWith || entity[field.camelToSnake()]) &&_x000D_
                  entity[field.camelToSnake()] !== compareWith) {_x000D_
                  changeCount++;_x000D_
                }_x000D_
              });_x000D_
              vm.saved = changeCount <= 0;_x000D_
            },_x000D_
          _x000D_
            //sanitizeValue method works as intended as it does not have any reference to "this"_x000D_
          _x000D_
            sanitizeValue(value) {_x000D_
              if (value) {_x000D_
                return String(value).trim();_x000D_
              } else {_x000D_
                return null;_x000D_
              }_x000D_
            },_x000D_
          _x000D_
            //In getDbData method also this needs to refer to the inheriting child instance_x000D_
            //from where this method is called - how can I achieve it?_x000D_
          _x000D_
            getDbData(entity) {_x000D_
              if (entity) {_x000D_
                this.dbTextFields.forEach(function(field) {_x000D_
                  this[field] = entity[field.camelToSnake()];_x000D_
                });_x000D_
                this.dbIntFields.forEach(function(field) {_x000D_
                  this[field] = entity[field.camelToSnake()];_x000D_
                });_x000D_
                this.dbObjFields.forEach(function(field) {_x000D_
                  this[field] = entity[field.camelToSnake()];_x000D_
                });_x000D_
                this.dbAppendedFields.forEach(function(field) {_x000D_
                  this[field] = entity[field.camelToSnake()]_x000D_
                });_x000D_
                this.saved = true;_x000D_
_x000D_
              }_x000D_
            }_x000D_
        });

_x000D_

_x000D_

_x000D_

_x000D_

_x000D_

//quotation.js_x000D_
_x000D_
import DataComponent from './data-component';_x000D_
_x000D_
export default DataComponent.extend({_x000D_
  _x000D_
  data(){_x000D_
    return{_x000D_
      id:0,_x000D_
      date:'',_x000D_
      remarks:'',_x000D_
      terms:'',_x000D_
      quote:{},_x000D_
      dbTextFields:['to', 'org', 'address', 'items', 'description', 'quoted_by'],_x000D_
      dbIntFields:['quote_ref', 'quantity', 'amount', 'discount', 'total'],_x000D_
      dbObjFields:['inquiry', 'booking']_x000D_
    }_x000D_
  },_x000D_
  _x000D_
  methods:{_x000D_
    setDbData(){_x000D_
      let entity = this.quote;_x000D_
      this.getDbData(entity);_x000D_
      _x000D_
      //getDbData gives error as "this" in getDbData does not refer to this_x000D_
      // child component and so this.dbTextFields becomes undefined._x000D_
      _x000D_
    }_x000D_
  }_x000D_
  _x000D_
});

_x000D_

_x000D_

_x000D_

How to achieve method inheritance as I am trying to do? Is it possible in Vue.js?  

Edit

If I change the signature of the method in data-component.js as under, passing the instance of inheriting component (“this”) as vm , it works

_x000D_

_x000D_

//data-component.js_x000D_
import Vue from 'vue';_x000D_
_x000D_
export_x000D_
default Vue.extend({_x000D_
_x000D_
      data() {_x000D_
          return {_x000D_
            saved: false_x000D_
          }_x000D_
        },_x000D_
_x000D_
        methods: {_x000D_
_x000D_
          //This method will be used by all inheriting components to alert_x000D_
          //the user regarding any changes which need to be saved._x000D_
          _x000D_
          alertSave(entity, fields, intFields, vm) {_x000D_
              var changeCount = 0;_x000D_
              fields.forEach(function(field) {_x000D_
                //var compareWith = this[field];_x000D_
                var compareWith = vm[field];_x000D_
                _x000D_
                //Changed "this" to vm (passed as a parameter) _x000D_
                //how can I achieve?_x000D_
                _x000D_
                if ((compareWith || entity[field.camelToSnake()]) &&_x000D_
                  entity[field.camelToSnake()] !== compareWith) {_x000D_
                  changeCount++;_x000D_
                }_x000D_
              });_x000D_
              intFields.forEach(function(field) {_x000D_
                //var compareWith = parseInt(this[field]);_x000D_
                var compareWith = parseInt(vm[field]);_x000D_
                if ((compareWith || entity[field.camelToSnake()]) &&_x000D_
                  entity[field.camelToSnake()] !== compareWith) {_x000D_
                  changeCount++;_x000D_
                }_x000D_
              });_x000D_
              vm.saved = changeCount <= 0;_x000D_
            },_x000D_
          _x000D_
            //sanitizeValue method works as intended as it does not have any reference to "this"_x000D_
          _x000D_
            sanitizeValue(value) {_x000D_
              if (value) {_x000D_
                return String(value).trim();_x000D_
              } else {_x000D_
                return null;_x000D_
              }_x000D_
            },_x000D_
          _x000D_
            //In getDbData method also this needs to refer to the inheriting child instance_x000D_
            //from where this method is called - how can I achieve it?_x000D_
          _x000D_
            getDbData(entity, vm) { //instance as "vm" parameter_x000D_
            //change all this to vm_x000D_
              if (entity) {_x000D_
                vm.dbTextFields.forEach(function(field) {_x000D_
                  vm[field] = entity[field.camelToSnake()];_x000D_
                });_x000D_
                vm.dbIntFields.forEach(function(field) {_x000D_
                  vm[field] = entity[field.camelToSnake()];_x000D_
                });_x000D_
                vm.dbObjFields.forEach(function(field) {_x000D_
                  vm[field] = entity[field.camelToSnake()];_x000D_
                });_x000D_
                vm.dbAppendedFields.forEach(function(field) {_x000D_
                  vm[field] = entity[field.camelToSnake()]_x000D_
                });_x000D_
                vm.saved = true;_x000D_
_x000D_
              }_x000D_
            }_x000D_
        });

_x000D_

_x000D_

_x000D_

And then in the inheriting component

_x000D_

_x000D_

//quotation.js_x000D_
_x000D_
import DataComponent from './data-component';_x000D_
_x000D_
export default DataComponent.extend({_x000D_
  _x000D_
  data(){_x000D_
    return{_x000D_
      id:0,_x000D_
      date:'',_x000D_
      remarks:'',_x000D_
      terms:'',_x000D_
      quote:{},_x000D_
      dbTextFields:['to', 'org', 'address', 'items', 'description', 'quoted_by'],_x000D_
      dbIntFields:['quote_ref', 'quantity', 'amount', 'discount', 'total'],_x000D_
      dbObjFields:['inquiry', 'booking']_x000D_
    }_x000D_
  },_x000D_
  _x000D_
  methods:{_x000D_
    setDbData(){_x000D_
      let entity = this.quote;_x000D_
      this.getDbData(entity, this);_x000D_
      _x000D_
      //passing this (instance) as a parameter_x000D_
      _x000D_
      _x000D_
    }_x000D_
  }_x000D_
  _x000D_
});

_x000D_

_x000D_

_x000D_

Passing the instance (“this”) to the methods as vm, it works as expected.

I am not sure if this is the best way to do it. But then it surely is not inheritance.
How to use inheritance to achieve what I am trying to do?

Solution

You should use Mixins to add common functionality to multiple (or all of your) components: https://vuejs.org/guide/mixins.html

This will let you add the same functions to any or all of your components, so you can automatically add this.foobar() to your components.

If you want to add functionality to all of your components without polluting your component namespace, you can use a custom plugin: https://vuejs.org/guide/plugins.html

This will let you add a service to all of your components so you can use it everywhere like this.$service.foobar().

If you want to work with CRUD functionality, you should create a resource using VueResource: https://github.com/vuejs/vue-resource/blob/master/docs/resource.md

This will let you easily create/delete/edit resources using FoobarService.create({foo: 'bar'}) or FoobarService.delete({id: 1})

Edit: to create a plugin, it will look something like this:

var MyPlugin = {};

MyPlugin.install = function (Vue, options) {

  var service = {
    foo: function(bar) {
      //do something
    }
  }

  Vue.prototype.$service = service;
}

Vue.use(MyPlugin); //this runs the install function

//Then when you have any Vue instance
this.$service.foo(bar);
Answered By: Anonymous

Related Articles

  • TLS 1.3 server socket with Java 11 and self-signed…
  • TypeScript metadata reflection references other classes…
  • How to set HTML5 required attribute in Javascript?
  • The 'compilation' argument must be an instance of…
  • Create the perfect JPA entity
  • There is already an object named in the database
  • Entity Framework Provider type could not be loaded?
  • How can I use/create dynamic template to compile dynamic…
  • What are the nuances of scope prototypal / prototypical…
  • EntityMetadataNotFound: No metadata for…

Disclaimer: This content is shared under creative common license cc-by-sa 3.0. It is generated from StackExchange Website Network.

Post navigation

Previous Post:

Backbone.js – Adding keydown events when view is active?

Next Post:

How to represent arrays within ember-data models?

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • Get code errors & solutions at akashmittal.com
© 2022 Fix Code Error