这个解决方案怎么样?在我的解决方案中,两个控件基本上是相同的,但在真正的解决方案中,它们会有不同的行为,但这是一个很好的起点。
这是一个例子:https ://gist.run?id=e6e980a88d7e33aba130ef91f55df9dd
应用程序.html
<template>
<require from="./text-box"></require>
<require from="./date-picker"></require>
<div>
Text Box
<text-box value.bind="text"></text-box>
</div>
<div>
Date Picker
<date-picker value.bind="date"></date-picker>
</div>
<button click.trigger="reset()">Reset controls</button>
<div>
Dynamic controls:
<div repeat.for="control of controls">
${control.label}
<compose view-model="./${control.type}" model.bind="control.model" ></compose>
<div>
control.model.value = ${control.model.value}
</div>
</div>
</div>
<button click.trigger="changeModelDotValueOnTextBox()">Change model.value on text box</button>
<button click.trigger="changeModelOnTextBox()">Change model.value on text box and then make a copy of the model</button>
</template>
应用程序.js
export class App {
text = 'This is some text';
date = '2017-02-28';
controls = getDefaultControls();
reset() {
this.controls = getDefaultControls();
}
changeModelOnTextBox() {
this.controls[1].model = {
value: 'I changed the model to something else!'
};
}
changeModelDotValueOnTextBox() {
this.controls[1].model.value = 'I changed the model!';
}
}
function getDefaultControls(){
return[
{label: 'Entry Date', type: 'date-picker', model: { value: '2017-01-01' }},
{label: 'Code', type: 'text-box', model: { value: 'This is some other text'}}
];
}
日期选择器.html
<template>
<input type="date" value.bind="value" />
</template>
日期选择器.js
import { inject, bindable, bindingMode, TaskQueue } from 'aurelia-framework';
import { ObserverLocator } from 'aurelia-binding';
@inject(Element, TaskQueue, ObserverLocator)
export class DatePicker {
@bindable({ defaultBindingMode: bindingMode.twoWay }) value;
model = null;
observerSubscription = null;
constructor(el, taskQueue, observerLocator) {
this.el = el;
this.taskQueue = taskQueue;
this.observerLocator = observerLocator;
}
activate(model) {
if(this.observerSubscription) {
this.observerSubscription.dispose();
}
this.model = model;
this.observerSubscription = this.observerLocator.getObserver(this.model, 'value')
.subscribe(() => this.modelValueChanged());
this.hasModel = true;
this.modelValueChanged();
}
detached() {
if(this.observerSubscription) {
this.observerSubscription.dispose();
}
}
modelValueChanged() {
this.guard = true;
this.value = this.model.value;
this.taskQueue.queueMicroTask(() => this.guard = false)
}
valueChanged() {
if(this.guard == false && this.hasModel) {
this.model.value = this.value;
}
}
}
文本框.html
<template>
<input type="text" value.bind="value" />
</template>
文本框.js
import { inject, bindable, bindingMode, TaskQueue } from 'aurelia-framework';
import { ObserverLocator } from 'aurelia-binding';
@inject(Element, TaskQueue, ObserverLocator)
export class TextBox {
@bindable({ defaultBindingMode: bindingMode.twoWay }) value;
model = null;
observerSubscription = null;
constructor(el, taskQueue, observerLocator) {
this.el = el;
this.taskQueue = taskQueue;
this.observerLocator = observerLocator;
}
activate(model) {
if(this.observerSubscription) {
this.observerSubscription.dispose();
}
this.model = model;
this.observerSubscription = this.observerLocator.getObserver(this.model, 'value')
.subscribe(() => this.modelValueChanged());
this.hasModel = true;
this.modelValueChanged();
}
detached() {
if(this.observerSubscription) {
this.observerSubscription.dispose();
}
}
modelValueChanged() {
this.guard = true;
this.value = this.model.value;
this.taskQueue.queueMicroTask(() => this.guard = false)
}
valueChanged() {
if(this.guard == false && this.hasModel) {
this.model.value = this.value;
}
}
}