Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

neeravp's avatar
Level 18

Component methods inheritance with Vue

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

//main.js
    import Vue from 'vue';

    new Vue({
        el:'#app',
        components:{
            DataComponent,
            Quotation
         }
    });  

    //data-component.js
    import Vue from 'vue';

    export default Vue.extend({

            data() {
                  return {
                        saved: false
                  }
             },

              methods: {

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

                }
            }
     });  

    //quotation.js

import DataComponent from './data-component';

export default DataComponent.extend({  
    data(){
            return{
                id:0,
                date:'',
                remarks:'',
                terms:'',
                 quote:{},
                dbTextFields:['to', 'org', 'address', 'items', 'description', 'quoted_by'],
                dbIntFields:['quote_ref', 'quantity', 'amount', 'discount', 'total'],
                 dbObjFields:['inquiry', 'booking']
            }   
     },

    methods:{
            setDbData(){
                let entity = this.quote;
                this.getDbData(entity);
  
                //getDbData gives error as "this" in getDbData does not refer to this
                // child component and so this.dbTextFields becomes undefined.
  
                }
     }

});    

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

0 likes
7 replies
neeravp's avatar
Level 18

@topvillas Do you mean that I should move all such methods in a mixin and then it will work? I will definitely give it a try now and will update here.

neeravp's avatar
Level 18

I created a mixin as under

//data-mixin.js  
var dataMixin = {
    methods:{
            getDbData(entity){
                if (entity) {
                    this.dbTextFields.forEach(field => {
                        this[field] = entity[field.camelToSnake()];
                    });
                    this.dbIntFields.forEach(field => {
                        this[field] = entity[field.camelToSnake()];
                    });
                    this.dbObjFields.forEach(field => {
                        this[field] = entity[field.camelToSnake()];
                    });
                    this.dbAppendedFields.forEach(field => {
                        this[field] = entity[field.camelToSnake()]
                    });
                    this.saved = true;
                    }
            }
    }
};
export default dataMixin;  

Then in quotation.js

import DataComponent from './data-component';
    import dataMixin from './data-mixin.js';

export default DataComponent.extend({  
    mixins:[dataMixin],

        data(){
                return{
                    id:0,
                    date:'',
                    remarks:'',
                    terms:'',
                    quote:{},
                    dbTextFields:['to', 'org', 'address', 'items', 'description', 'quoted_by'],
                    dbIntFields:['quote_ref', 'quantity', 'amount', 'discount', 'total'],
                    dbObjFields:['inquiry', 'booking']
                }   
        },

     methods:{
                setDbData(){
                    let entity = this.quote;
                    this.getDbData(entity);   // Here it throws an error getDbData is not a function

                    

                }
        }
});    
neeravp's avatar
Level 18

If I change the signature of the methods in the parent DataComponent to accept the inheriting instance ("this" as vm) as a parameter and change all calls to vm.variable instead of this.variable, it works.

//revised data-component.js  
import Vue from 'vue';

export default Vue.extend({

  data() {
      return {
        saved: false
      }
    },

    methods: {

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

          }
        }
    });  

And pass the instance from the inheriting component as under

//revised quotation.js  
import DataComponent from './data-component';

export default DataComponent.extend({

data(){
    return{
    id:0,
    date:'',
    remarks:'',
     terms:'',
    quote:{},
     dbTextFields:['to', 'org', 'address', 'items', 'description', 'quoted_by'],
    dbIntFields:['quote_ref', 'quantity', 'amount', 'discount', 'total'],
    dbObjFields:['inquiry', 'booking']
    }
},

methods:{
    setDbData(){
    let entity = this.quote;
     this.getDbData(entity, this);
  
    //passing this (instance) as a parameter
  
  
 }
}

});  

Passing the instance ("this") to the methods as vm, it works as I want.

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?

topvillas's avatar

If you want inheritance you'll need to start using ES2015 classes. But really, mixins are the easier way to go.

neeravp's avatar
Level 18

What I am doing wrong while trying the mixin way as in my previous reply? I am still not able to reference the instance of the component using the mixin and am getting an error "getDbData" method does not exist. Can you throw some light as to what am I doing wrong? Another thing which I want to ask is, passing the component instance as parameter to the method of parent component, does it have any performance issue?

@topvillas Thanks for taking out time to help me out.

neeravp's avatar
Level 18

Okay I got it working, there were two causes for the errors, first I was writing mixin:[dataMixin]instead of mixins:[dataMixin] and second within the getDbData() function I was not binding this to the functions within forEach loops. I updated the mixin code snippet above with the working one for anyone viewing this.

Please or to participate in this conversation.