在 Aurelia 中,我可以从我的包含视图模型中绑定一个函数以供我的自定义元素调用吗?

In Aurelia, can I bind a function from my containing view-model to be called by my custom element?

我有一个接受用户输入的自定义元素,在单击 [save] 按钮时,我想将信息传递给父视图模型,以便将其发送到服务器并转到下一部分。为了示例的缘故,我将对此进行简化:

my-element.js:

import { customElement, bindable } from 'aurelia-framework';

@customElement('my-element')
@bindable('save')
export class MyElement { }

my-element.html:

<template>
    <button click.delegate="save()">Click this</button>
</template>

parent-view-model.js:

export class ParentViewModel {
  parentProperty = 7;
  parentMethod() {
    console.log(`parent property: ${this.parentProperty}`);
  }
}

parent-view-model.html:

<template>
    <require from="./my-element"></require>
    <div class="content-panel">
        <my-element save.bind="parentMethod"></my-element>
    </div>
</template>

演示见(app.js和app.html代表父视图-model.js和父视图-model.html):

https://gist.run/?id=96b203e9ca03b62dfb202626c2202989

有效!有点儿。不幸的是,this 似乎绑定到 my-element 而不是 parent-view-model,所以在这个例子中,打印到控制台的是:parent property: undefined。那是行不通的。

我知道我可以利用 EventAggregator 来促进自定义元素和视图模型之间的某些通信,但如果我可以帮助它,我想避免增加复杂性。

我在浏览 aurelia 文档中心一段时间后解决了这个问题。我不知道可能涉及的所有细微差别,但对于这个简单的示例,我能够通过进行以下简单更改来修复它:

在父视图-model.html(或要点-运行示例中的app.html)中,将save.bind="parentMethod"更改为save.call="parentMethod()"

不过,我仍然不确定如何将数据从自定义元素传递到父视图模型的方法中。

Here is the documentation from aurelia website.

你有两个选择。您可以使用自定义事件来处理此问题,也可以使用 Anj 在他的回答中提到的 call 绑定来完成。您使用哪一个取决于您的实际用例。

如果您希望自定义元素能够调用父 VM 上的方法并传递自定义元素的数据 out,那么您应该使用自定义事件,如图所示在这个要点中:https://gist.run/?id=ec8b3b11f4aa4232455605e2ce62872c:

app.html:

<template>
    <require from="./my-element"></require>
    <div class="content-panel">
        <my-element save.delegate="parentMethod($event)"></my-element>
    </div>

    parentProperty = '${parentProperty}'
</template>

app.js:

export class App {
  parentProperty = 7;
  parentMethod($event) {
    this.parentProperty = $event.detail;
  }
}

我的-element.html:

<template>
    <input type="text" value.bind="eventDetailValue" />
    <button click.delegate="save()">Click this</button>
</template>

我的-element.js:

import { inject, customElement, bindable } from 'aurelia-framework';

@customElement('my-element')
@inject(Element)
export class MyElement {
  eventDetailValue = 'Hello';

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

  save() {
    var event = new CustomEvent('save', { 
      detail: this.eventDetailValue,
      bubbles: true
    });

    this.element.dispatchEvent(event);
  }
} 

您基本上可以附加任何需要传递给自定义事件的 detail 属性 的数据。在事件绑定声明中,您将添加 $event 作为函数的参数,然后检查事件处理程序中 $event 的 detail 属性(您也可以只传递 $event.detail 如果你愿意的话)。

如果您希望自定义元素能够调用父 VM 上的方法并从父 VM(或从另一个自定义元素或其他东西)传入数据,那么您应该使用 call 捆绑。您可以通过在绑定声明中指定参数来指定将传递给方法的参数(foo.call="myMethod(myProperty)"。这些参数来自声明绑定的 VM 上下文,而不是来自自定义元素的 VM)。

要将参数化函数传递给自定义子组件,请编写以下内容(根据文档 http://aurelia.io/docs/binding/basics#function-references)。

父视图模型

private _generate(myParam:string) {
    return myParam + " world";
}

父视图

<custom-comp generator.call="_generate(myParam)"></custom-comp>

子视图

<template bindable="generator">
${generator({myParam:"hello"})}
</template>

已为 aurelia v2 更新:

调用绑定不再将第一个参数传递的属性分配给对调用覆盖上下文的调用。这是不合理的动态,可能会导致 hard-to-understand 模板。 在 Aurelia 1 中,您会像这样使用调用绑定:

export class MyElement {
  onChange;

  onInternalButtonClick() {
    this.onChange({ value: this.value });
  }
}

<my-element on-change.call="propertyChanged(value)">

在 Aurelia 2 中,属性 名称现在位于传递给回调的 $event 属性 上。这是一个小改动,但您现在改为这样做:

<my-element on-change.call="propertyChanged($event.value)">