使用materialize-css,他们的select元素使用jquery来应用值更改.然而,这不会触发aurelia看到变化.使用…的技术
$( “选择”)
.change((eventObject:JQueryEventObject)=> {
fireEvent(eventObject.target,“change”);
});
我可以触发aurelia看到的事件,然而,aurelia然后导致事件再次被触发,而它正在更新它的绑定并且我最终进入无限循环…. Stack Overflow:D
什么是最可靠的方式让这两个人在这方面一起玩?
我已经与materialize-css aurelia合作了一段时间,我可以确认来自物化的选择元素是非常有问题的.我只想在这里分享我的一个解决方案,以防有人想要一些额外的例子.在这种情况下,阿什利可能更干净.我使用可绑定的选项而不是插槽.
除此之外,基本思想是相同的(使用保护变量和微任务).
我在处理第三方插件和双向数据绑定时学到的一个教训是,它有助于在处理源自绑定目标(DOM上的select元素)的更改和源自的绑定更改之间做出更明确,明确的分离.绑定源(例如包含该元素的页面的ViewModel).
我倾向于使用名称为onValueChangedByBindingSource和onValueChangedByBindingTarget的更改处理程序来处理将ViewModel与DOM同步的不同方式,从而减少代码混乱.
示例:https://gist.run?id=6ee17e333cd89dc17ac62355a4b31ea9
SRC /材料select.html
<template> <div class="input-field"> <select value.two-way="value" id="material-select"> <option repeat.for="option of options" model.bind="option"> ${option.displayName} </option> </select> </div> </template>
SRC /材料select.ts
import { customElement, bindable, bindingMode, TaskQueue, Disposable, BindingEngine, inject, DOM } from "aurelia-framework"; @customElement("material-select") @inject(DOM.Element, TaskQueue, BindingEngine) export class MaterialSelect { public element: HTMLElement; public selectElement: HTMLSelectElement; @bindable({ defaultBindingMode: bindingMode.twoWay }) public value: { name: string, value: number }; @bindable({ defaultBindingMode: bindingMode.oneWay }) public options: { displayName: string }[]; constructor( element: Element, private tq: TaskQueue, private bindingEngine: BindingEngine ) { this.element = element; } private subscription: Disposable; public isAttached: boolean = false; public attached(): void { this.selectElement = <HTMLSelectElement>this.element.querySelector("select"); this.isAttached = true; $(this.selectElement).material_select(); $(this.selectElement).on("change", this.handleChangeFromNativeSelect); this.subscription = this.bindingEngine.collectionObserver(this.options).subscribe(() => { $(this.selectElement).material_select(); }); } public detached(): void { this.isAttached = false; $(this.selectElement).off("change", this.handleChangeFromNativeSelect); $(this.selectElement).material_select("destroy"); this.subscription.dispose(); } private valueChanged(newValue, oldValue): void { this.tq.queueMicroTask(() => { this.handleChangeFromViewModel(newValue); }); } private _suspendUpdate = false; private handleChangeFromNativeSelect = () => { if (!this._suspendUpdate) { this._suspendUpdate = true; let event = new CustomEvent("change", { bubbles: true }); this.selectElement.dispatchEvent(event) this._suspendUpdate = false; } } private handleChangeFromViewModel = (newValue) => { if (!this._suspendUpdate) { $(this.selectElement).material_select(); } } }
编辑
自定义属性怎么样?
要点:https://gist.run?id=b895966489502cc4927570c0beed3123
SRC / app.html
<template> <div class="container"> <div class="row"></div> <div class="row"> <div class="col s12"> <div class="input-element" style="position: relative;"> <select md-select value.two-way="currentOption"> <option repeat.for="option of options" model.bind="option">${option.displayName}</option> </select> <label>Selected: ${currentOption.displayName}</label> </div> </div> </div> </div> </template>
SRC / app.ts
export class App { public value: string; public options: {displayName: string}[]; constructor() { this.options = new Array<any>(); this.options.push({ displayName: "Option 1" }); this.options.push({ displayName: "Option 2" }); this.options.push({ displayName: "Option 3" }); this.options.push({ displayName: "Option 4" }); } public attached(): void { this.value = this.options[1]; } }
SRC / MD-select.ts
import { customAttribute, bindable, bindingMode, TaskQueue, Disposable, BindingEngine, DOM, inject } from "aurelia-framework"; @inject(DOM.Element, TaskQueue, BindingEngine) @customAttribute("md-select") export class MdSelect { public selectElement: HTMLSelectElement; @bindable({ defaultBindingMode: bindingMode.twoWay }) public value; constructor(element: Element, private tq: TaskQueue) { this.selectElement = element; } public attached(): void { $(this.selectElement).material_select(); $(this.selectElement).on("change", this.handleChangeFromNativeSelect); } public detached(): void { $(this.selectElement).off("change", this.handleChangeFromNativeSelect); $(this.selectElement).material_select("destroy"); } private valueChanged(newValue, oldValue): void { this.tq.queueMicroTask(() => { this.handleChangeFromViewModel(newValue); }); } private _suspendUpdate = false; private handleChangeFromNativeSelect = () => { if (!this._suspendUpdate) { this._suspendUpdate = true; const event = new CustomEvent("change", { bubbles: true }); this.selectElement.dispatchEvent(event) this.tq.queueMicroTask(() => this._suspendUpdate = false); } } private handleChangeFromViewModel = (newValue) => { if (!this._suspendUpdate) { $(this.selectElement).material_select(); } } }