Aurelia动态创建自定义元素,无需编写

Aurelia动态创建自定义元素,无需编写,aurelia,aurelia-templating,Aurelia,Aurelia Templating,我了解Aurelia的定制元素与相比的优缺点;杰里米·丹约的帮助。但是,我愿意 我想创建自定义元素,我也可以动态组合。由于需要不同的实例化,使用它意味着我需要为每个元素创建两个并行版本——一个用于,另一个用于静态调用。例如,考虑以下用例: <template> <h1>Welcome to the Data Entry Screen</h1> <!-- Static controls --> <my-textbox label=

我了解Aurelia的定制元素与
相比的优缺点;杰里米·丹约的帮助。但是,我愿意

我想创建自定义元素,我也可以动态组合。由于
需要不同的实例化,使用它意味着我需要为每个元素创建两个并行版本——一个用于
,另一个用于静态调用。例如,考虑以下用例:

<template>
  <h1>Welcome to the Data Entry Screen</h1>

  <!-- Static controls -->
  <my-textbox label="Your name:" value.bind="entry_name"></my-textbox>
  <my-datepicker label="Current date:" value.bind="entry_date"></my-datepicker>

  <!-- Loop through dynamic form controls -->
  <div class="form-group" repeat.for="control of controls" if.bind="control.type !== 'hidden'">
    <label class="control-label">${control.label}</label>
    <div>
      <compose containerless class="form-control"
        view-model="resources/elements/${control.type}/${control.type}" 
        model.bind="{'control': control, 'model': model, 'readonly': readonly}">
        </compose>
    </div>
  </div>
</template>

如您所见,我希望静态和动态地使用
。自定义元素显然是最好的方法。但是,如果不创建两个并行组件(一个设计为自定义元素,另一个设计为可组合视图/视图模型),我看不到如何实现这一点。

为了实现自定义元素的动态创建,我已经实现了一个元自定义元素,它使用
if.bind
动态实例化正确的自定义元素(一般思想如下)

元视图模型:

import {bindable} from 'aurelia-framework';

export class MyMetaElement {

  @bindable control;                // control definition object
  @bindable model;                  // data for binding
  @bindable readonly = false;       // flag to make controls view-only

}
<template>

  <my-textbox if.bind="control.type == 'my-textbox" label.bind="control.label" value.bind="model[control.bind]" readonly.bind="readonly"></my-textbox>
  <my-datepicker if.bind="control.type == 'my-datepicker" label.bind="control.label" value.bind="model[control.bind]" readonly.bind="readonly"></my-datepicker>
  <my-textarea if.bind="control.type == 'my-textarea" label.bind="control.label" value.bind="model[control.bind]" rows.bind="control.rows" readonly.bind="readonly"></my-textarea>
  <my-dropdown if.bind="control.type == 'my-dropdown" label.bind="control.label" value.bind="model[control.bind]" enum.bind="control.enum" readonly.bind="readonly"></my-dropdown>

</template>
元视图:

import {bindable} from 'aurelia-framework';

export class MyMetaElement {

  @bindable control;                // control definition object
  @bindable model;                  // data for binding
  @bindable readonly = false;       // flag to make controls view-only

}
<template>

  <my-textbox if.bind="control.type == 'my-textbox" label.bind="control.label" value.bind="model[control.bind]" readonly.bind="readonly"></my-textbox>
  <my-datepicker if.bind="control.type == 'my-datepicker" label.bind="control.label" value.bind="model[control.bind]" readonly.bind="readonly"></my-datepicker>
  <my-textarea if.bind="control.type == 'my-textarea" label.bind="control.label" value.bind="model[control.bind]" rows.bind="control.rows" readonly.bind="readonly"></my-textarea>
  <my-dropdown if.bind="control.type == 'my-dropdown" label.bind="control.label" value.bind="model[control.bind]" enum.bind="control.enum" readonly.bind="readonly"></my-dropdown>

</template>


虽然动态创建控件似乎需要做很多额外的工作,但与使用
相比,它有很多优点,特别是因为自定义元素控件也可以在独立设置(静态实例化)中使用。

对于解决方案,这一点如何?在我的解决方案中,两个控件基本上是相同的,但在实际解决方案中,它们的行为会有所不同,但这是一个很好的起点

这里有一个例子:

app.html


文本框
日期拾取器
重置控件
动态控制:
${control.label}
control.model.value=${control.model.value}
更改文本框上的model.value
更改文本框中的model.value,然后复制模型
app.js

导出类应用程序{
text='这是一些文本';
日期='2017-02-28';
controls=getDefaultControls();
重置(){
this.controls=getDefaultControls();
}
changeModelContextBox(){
此。控件[1]。模型={
值:“我将模型更改为其他类型!”
};
}
changeModelDotValueOnTextBox(){
this.controls[1].model.value='I更改了模型!';
}
}
函数getDefaultControls(){
返回[
{标签:'Entry Date',类型:'Date picker',型号:{value:'2017-01-01'},
{label:'Code',type:'text box',model:{value:'This some other text'}
];
}
日期选择器.html


日期选择器.js

import{inject,bindable,bindingMode,TaskQueue}来自'aurelia framework';
从'aurelia binding'导入{ObserverLocator};
@注入(元素、任务队列、ObserverLocator)
导出类日期选择器{
@bindable({defaultBindingMode:bindingMode.twoWay})值;
model=null;
observerSubscription=null;
构造函数(el、taskQueue、observerLocator){
this.el=el;
this.taskQueue=taskQueue;
this.observer定位器=observer定位器;
}
激活(模型){
if(此.observer订阅){
此.observerSubscription.dispose();
}
this.model=模型;
this.observerSubscription=this.observerLocator.getObserver(this.model,'value')
.subscribe(()=>this.modelValueChanged());
this.hasModel=true;
此.modelValueChanged();
}
分离的(){
if(此.observer订阅){
此.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


text box.js

import{inject,bindable,bindingMode,TaskQueue}来自'aurelia framework';
从'aurelia binding'导入{ObserverLocator};
@注入(元素、任务队列、ObserverLocator)
导出类文本框{
@bindable({defaultBindingMode:bindingMode.twoWay})值;
model=null;
observerSubscription=null;
构造函数(el、taskQueue、observerLocator){
this.el=el;
this.taskQueue=taskQueue;
this.observer定位器=observer定位器;
}
激活(模型){
if(此.observer订阅){
此.observerSubscription.dispose();
}
this.model=模型;
this.observerSubscription=this.observerLocator.getObserver(this.model,'value')
.subscribe(()=>this.modelValueChanged());
this.hasModel=true;
此.modelValueChanged();
}
分离的(){
if(此.observer订阅){
此.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;
}
}
}

还有另一种策略,不确定是否更好。您可以创建一个
自定义组合
,其行为符合您的要求。例如:

import { 
  bindable, 
  inlineView, 
  noView, 
  inject, 
  TemplatingEngine,
  bindingMode } from 'aurelia-framework';

@noView
@inject(Element, TemplatingEngine)
export class DynamicElement {

  @bindable type;
  @bindable({ defaultBindingMode: bindingMode.twoWay }) model;

  constructor(element, templatingEngine) {
    this.element = element;
    this.templatingEngine = templatingEngine;
  }

  bind(bindingContext, overrideContext) {
    this.element.innerHTML = `<${this.type} value.bind="model"></${this.type}>`;
    this.templatingEngine.enhance({ element: this.element, bindingContext: this });
  }

  detached() {
    this.element.firstChild.remove();
    this.view.detached();
    this.view.unbind();
    this.view = null;
  }
}
import{
可装订的,
inlineView,
诺维,
注射
TemplatingEngine,
来自“aurelia框架”的bindingMode};
@小说
@注入(元素,模板引擎)
出口级动态加速{
@可装订型;
@可绑定({defaultBindingMode:bindingMode.twoWay})模型;
构造函数(元素,模板引擎){
this.element=元素;
this.templatingEngine=templatingEngine;
}
绑定(bindingContext,overrideContext){
this.element.innerHTML=`;
enhance({element:this.element,bindingContext:this});
}
分离的(){
这是.element.f