Aurelia 动态绑定 [英] Aurelia dynamic binding
问题描述
我创建了一个生成表格数据的自定义元素.出于充分的理由,这会生成实际的 HTML 并在不使用模板的情况下插入到 DOM 中.
我需要将点击观察器附加到特定元素,以便我可以在自定义元素中运行一个函数来响应点击.如果使用模板,我会使用 click.delegate,但我不能在生成的 HTML 中使用它.
除了使用 jQuery 之外,您如何使用 Aurelia 附加事件处理程序?
我知道这个答案来晚了,但以防万一这还没有(正确)解决和/或其他人将来发现这个:>
为了使任何 aurelia 行为在动态生成的 HTML 中起作用,您需要编译该 HTML.
我开发了一个自定义元素(基于 aurelia 的 enhance
和 compose
的工作方式),它允许您传入一串 HTML,然后它会被编译,以便任何行为,如可绑定、自定义元素/属性都可以正常工作.当html改变时它也会重新编译.
示例如下:https://gist.run?id=1960218b52ba628f737745827a强>
src/app.html
<dynamic-html html.bind="dynamicHtml"></dynamic-html>模板>
src/app.ts
export class App {public dynamicHtml: string = `<button click.delegate="handleClick()">点击我</button>`;公共句柄点击():无效{警报(你好!")}}
src/dynamic-html.ts
import {自定义元素,任务队列,可绑定,视图编译器,视图槽,看法,查看资源,容器,视图工厂,内联视图,注入,DOM来自aurelia-framework";@customElement("dynamic-html")@inlineView("<template><div></div></template>")@inject(DOM.Element, TaskQueue, Container, ViewCompiler)导出类 DynamicHtml {@绑定()公共 html:字符串;公共元素:HTMLElement;私有 tq:任务队列;私有容器:容器;私有视图编译器:视图编译器;私有运行时视图:查看;私有运行时视图槽:视图槽;私有运行时视图工厂:视图工厂;私有运行时视图锚点:HTMLDivElement;构造函数(元素,tq,容器,视图编译器){this.element = 元素;这个.tq = tq;this.container = 容器;this.viewCompiler = viewCompiler;}公共绑定上下文:任何;公共覆盖上下文:任何;公共绑定(bindingContext:任何,overrideContext:任何):无效{this.bindingContext = bindingContext;this.overrideContext = overrideContext;如果(this.html){this.htmlChanged(this.html, undefined);}}公共解除绑定():无效{this.disposeView();this.bindingContext = null;this.overrideContext = null;}公共需求申请:boolean = false;公共 isAttached: boolean = false;公共附加():无效{this.runtimeViewAnchor = this.element.firstElementChild;this.isAttached = true;如果(this.needsApply){this.needsApply = false;this.apply();}}公共分离():无效{this.isAttached = false;this.runtimeViewAnchor = null;}私有 htmlChanged(newValue: string, oldValue: void): void {如果(新值){如果(this.isAttached){this.tq.queueMicroTask(() => {this.apply();});} 别的 {this.needsApply = true;}} 别的 {如果(this.isApplied){this.disposeView();}}}私有 isApplied: boolean = false;私人申请():无效{如果(this.isApplied){this.disposeView();}this.compileView();}私人处置视图():无效{如果(this.runtimeViewSlot){this.runtimeViewSlot.unbind();this.runtimeViewSlot.detached();this.runtimeViewSlot.removeAll();this.runtimeViewSlot = null;}如果(this.runtimeViewFactory){this.runtimeViewFactory = null;}如果(this.runtimeView){this.runtimeView = null;}this.isApplied = false;}私人编译视图():无效{this.runtimeViewFactory = createViewFactory(this.viewCompiler, this.container, this.html);this.runtimeView = createView(this.runtimeViewFactory, this.container);this.runtimeViewSlot = createViewSlot(this.runtimeViewAnchor);this.runtimeViewSlot.add(this.runtimeView);this.runtimeViewSlot.bind(this.bindingContext, this.overrideContext);this.runtimeViewSlot.attached();this.isApplied = true;}}函数 createViewFactory(viewCompiler: ViewCompiler, container: Container, html: string): ViewFactory {if (!html.startsWith("")) {html = `<template>${html}</template>`;}让 viewResources: ViewResources = container.get(ViewResources);让 viewFactory = viewCompiler.compile(html, viewResources);返回视图工厂;}函数创建视图(视图工厂:视图工厂,容器:容器):视图{让 childContainer = container.createChild();让视图 = viewFactory.create(childContainer);返回视图;}函数 createViewSlot(containerElement: Element): ViewSlot {让 viewSlot = new ViewSlot(containerElement, true);返回视图插槽;}
I've created a custom element that generates tabular data. For good reasons, this generates the actual HTML and inserts into the DOM without using a template.
I need to attach click observers to specific elements to I can run a function in the custom element in response to a click. If using a template, I'd use click.delegate, but I can't use that with generated HTML.
How do you attach an event handler with Aurelia other than by using jQuery?
I know this answer is late, but in case this hasn't been (properly) solved yet and/or someone else finds this in the future:
In order to make any aurelia behavior work in dynamically generated HTML, you need to compile that HTML.
I have worked on a custom element (based on how aurelia's enhance
and compose
work) that allows you to pass in a string of HTML and it will then be compiled, so that any behaviors like bindables, custom elements / attributes will just work. It will also re-compile when the html changes.
Here's an example: https://gist.run?id=1960218b52ba628f73774822aef55ad7
src/app.html
<template>
<dynamic-html html.bind="dynamicHtml"></dynamic-html>
</template>
src/app.ts
export class App {
public dynamicHtml: string = `
<button click.delegate="handleClick()">Click me</button>
`;
public handleClick(): void {
alert("Hello!")
}
}
src/dynamic-html.ts
import {
customElement,
TaskQueue,
bindable,
ViewCompiler,
ViewSlot,
View,
ViewResources,
Container,
ViewFactory,
inlineView,
inject,
DOM
} from "aurelia-framework";
@customElement("dynamic-html")
@inlineView("<template><div></div></template>")
@inject(DOM.Element, TaskQueue, Container, ViewCompiler)
export class DynamicHtml {
@bindable()
public html: string;
public element: HTMLElement;
private tq: TaskQueue;
private container: Container;
private viewCompiler: ViewCompile;
private runtimeView: View;
private runtimeViewSlot: ViewSlot;
private runtimeViewFactory: ViewFactory;
private runtimeViewAnchor: HTMLDivElement;
constructor(element, tq, container, viewCompiler) {
this.element = <HTMLElement>element;
this.tq = tq;
this.container = container;
this.viewCompiler = viewCompiler;
}
public bindingContext: any;
public overrideContext: any;
public bind(bindingContext: any, overrideContext: any): void {
this.bindingContext = bindingContext;
this.overrideContext = overrideContext;
if (this.html) {
this.htmlChanged(this.html, undefined);
}
}
public unbind(): void {
this.disposeView();
this.bindingContext = null;
this.overrideContext = null;
}
public needsApply: boolean = false;
public isAttached: boolean = false;
public attached(): void {
this.runtimeViewAnchor = this.element.firstElementChild;
this.isAttached = true;
if (this.needsApply) {
this.needsApply = false;
this.apply();
}
}
public detached(): void {
this.isAttached = false;
this.runtimeViewAnchor = null;
}
private htmlChanged(newValue: string, oldValue: void): void {
if (newValue) {
if (this.isAttached) {
this.tq.queueMicroTask(() => {
this.apply();
});
} else {
this.needsApply = true;
}
} else {
if (this.isApplied) {
this.disposeView();
}
}
}
private isApplied: boolean = false;
private apply(): void {
if (this.isApplied) {
this.disposeView();
}
this.compileView();
}
private disposeView(): void {
if (this.runtimeViewSlot) {
this.runtimeViewSlot.unbind();
this.runtimeViewSlot.detached();
this.runtimeViewSlot.removeAll();
this.runtimeViewSlot = null;
}
if (this.runtimeViewFactory) {
this.runtimeViewFactory = null;
}
if (this.runtimeView) {
this.runtimeView = null;
}
this.isApplied = false;
}
private compileView(): void {
this.runtimeViewFactory = createViewFactory(this.viewCompiler, this.container, this.html);
this.runtimeView = createView(this.runtimeViewFactory, this.container);
this.runtimeViewSlot = createViewSlot(this.runtimeViewAnchor);
this.runtimeViewSlot.add(this.runtimeView);
this.runtimeViewSlot.bind(this.bindingContext, this.overrideContext);
this.runtimeViewSlot.attached();
this.isApplied = true;
}
}
function createViewFactory(viewCompiler: ViewCompiler, container: Container, html: string): ViewFactory {
if (!html.startsWith("<template>")) {
html = `<template>${html}</template>`;
}
let viewResources: ViewResources = container.get(ViewResources);
let viewFactory = viewCompiler.compile(html, viewResources);
return viewFactory;
}
function createView(viewFactory: ViewFactory, container: Container): View {
let childContainer = container.createChild();
let view = viewFactory.create(childContainer);
return view;
}
function createViewSlot(containerElement: Element): ViewSlot {
let viewSlot = new ViewSlot(containerElement, true);
return viewSlot;
}
这篇关于Aurelia 动态绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!