-
Notifications
You must be signed in to change notification settings - Fork 6
/
vue-component.js
80 lines (68 loc) · 2.56 KB
/
vue-component.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import {_} from 'meteor/underscore';
import {EJSON} from 'meteor/ejson';
import {DataLookup} from 'meteor/peerlibrary:data-lookup';
import Vue from 'vue';
import './vue-component.html';
function removeVm(vm) {
vm.$destroy();
if (vm.$el) {
vm.$el.remove();
}
}
Template.VueComponent.onRendered(function () {
this.autorun((computation) => {
if (this.vm) {
removeVm(this.vm);
this.vm = null;
}
// Using DataLookup to depend only on "component" value from the data context.
// We do not want to recreate the whole component unnecessarily.
let component = DataLookup.get(() => Template.currentData(this.view), 'component', (a, b) => a === b) || null;
if (_.isString(component)) {
const componentName = component;
component = Vue.component(component);
if (!component) {
throw new Error(`Component '${componentName}' not found.`);
}
}
else if (component) {
component = Vue.extend(component);
} else {
throw new Error("Component not provided.");
}
// Extra arguments to be passed to the component's constructor.
// Any change in them recreate the whole component.
let args = DataLookup.get(() => Template.currentData(this.view), 'args', EJSON.equals) || {};
// It can be any element, because it gets replaced by Vue.
const el = document.createElement('div');
this.view._domrange.parentElement.insertBefore(el, this.view.lastNode());
// Initial set of non-reactive props.
let propsData = Tracker.nonreactive(() => DataLookup.lookup(Template.currentData(this.view), 'props'));
// To prevent unnecessary reruns of the autorun if constructor registers any dependency.
// The only dependency we care about is on "component" which has already been established.
this.vm = Tracker.nonreactive(() => {
return new component(_.extend({
el,
propsData,
}, args));
});
// And now observe props and update them if they change.
this.autorun((computation) => {
const props = DataLookup.get(() => Template.currentData(this.view), 'props', EJSON.equals) || {};
_.each(_.keys(this.vm._props || {}), (key, i) => {
const isDefined = !_.isUndefined(props[key]);
const isPreviouslyDefined = propsData && !_.isUndefined(propsData[key]);
if (isDefined || (!isDefined && isPreviouslyDefined)) {
this.vm._props[key] = props[key];
}
});
propsData = props;
});
});
});
Template.VueComponent.onDestroyed(function () {
if (this.vm) {
removeVm(this.vm);
this.vm = null;
}
});