Like many, I have been very impressed with the work done on VueJS and TypeScript and naturally, I want to leverage the benefits of each in my projects. Unfortunately, the Vue configuration model does not facilitate binding to a class as such. Instead, Vue asks for a bag of methods & properties via its constructor:
var app = new Vue({
el: document.getElementById('app'),
data: {counter: 1},
methods: {
increment: function(){
this.counter ++;
}
}
});
But this is not the way modern JavaScript applications are written:
- JavaScript components are encapsulated in classes - now supported natively in ES6 and of course in Typescript
- Regardless of how you build your components, they should be agnostic towards any UI binding (if any) being employed against them
So, for example, the above component would be encapsulated in the following Typescript module:
export class Timer {
public counter: number = 0;
public increment(): void {
this.counter ++;
}
}
It would be nice if Vue would let you do something like:
new Vue({el: xyz, model: new Timer()})
But of course, it doesn't, and hence why you are reading this post. Well, we had this problem, but with a little determination, we wrote this method which maps any class into a Vue instance. We've been using it for a few months now and haven't noticed any departures from normal Vue behaviours. I've self-documented inline below. Please grab and use/modify as you wish:
let functions: any = {};
let fn_bindFunctions = (obj: any) => {
let fnList = Object.getOwnPropertyNames(obj);
fnList.map((propertyName: string) => {
if (typeof (propertyName) !== "string") return;
if (propertyName === "constructor") return;
if ((this as any)[propertyName] instanceof Function) {
if (typeof (functions[propertyName]) !== "undefined") return;
functions[propertyName] = (...args: any[]) => {
(this as any)[propertyName](...args);
};
}
});
if (typeof (obj.constructor) !== "undefined" &&
typeof (obj.constructor.name) === "string" &&
obj.constructor.name !== "BaseController") {
fn_bindFunctions(Object.getPrototypeOf(obj));
}
};
fn_bindFunctions(Object.getPrototypeOf(this));
var app = new Vue({
el: document.getElementById('app'),
data: this,
methods: functions
});