Component Inheritance with vue js
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
//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_
//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_
//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
//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
//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
Disclaimer: This content is shared under creative common license cc-by-sa 3.0. It is generated from StackExchange Website Network.