Могу ли я в Aurelia связать функцию из моей содержащей модели представления для вызова моим пользовательским элементом?
У меня есть пользовательский элемент, который будет принимать пользовательский ввод, и по нажатию кнопки [сохранить] я хочу передать информацию в родительскую модель представления, чтобы я мог отправить ее на сервер и перейти к следующему разделу. Я собираюсь упростить это, например, ради:
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 представляют parent-view-model.js и parent-view-model.html):
https://gist.run/?id=96b203e9ca03b62dfb202626c2202989
Оно работает! Вид. К несчастью, this
кажется связано с my-element
вместо parent-view-model
в этом примере выводится на консоль: parent property: undefined
, Это не будет работать.
Я знаю, что могу использовать EventAggregator, чтобы облегчить некоторую связь между пользовательским элементом и моделью представления, но если я могу помочь, я бы хотел избежать дополнительной сложности.
4 ответа
У вас есть два варианта для этого. Вы можете справиться с этим с помощью пользовательских событий, или вы можете сделать это с помощью call
обязательный, что Анж упомянул в своем ответе. Какой из них вы используете, зависит от вашего фактического варианта использования.
Если вы хотите, чтобы пользовательский элемент мог вызывать метод на вашей родительской виртуальной машине и передавать данные из пользовательского элемента, то вам следует использовать пользовательское событие, как показано в этом списке: 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
в качестве параметра функции, а затем проверьте detail
свойство $event в вашем обработчике событий (вы также можете просто передать $event.detail
если ты хотел).
Если вы хотите, чтобы пользовательский элемент мог вызывать метод на вашей родительской виртуальной машине и получать данные от родительской виртуальной машины (или от другого пользовательского элемента или чего-то еще), то вам следует использовать call
связывание. Вы можете указать аргументы, которые будут переданы методу, указав их в объявлении привязки (foo.call="myMethod(myProperty)"
, Эти аргументы берутся из контекста ВМ, где объявляется привязка, а не из ВМ пользовательского элемента).
Я смог решить эту проблему после небольшого троллинга через концентратор aurelia docs. Я не знаю всех нюансов, которые могут быть связаны, но для этого простого примера я смог исправить это, выполнив следующие простые изменения:
В parent-view-model.html (или app.html в примере gist-run) измените save.bind="parentMethod"
в save.call="parentMethod()"
Однако я до сих пор не уверен, как передать данные из пользовательского элемента в метод родительской модели представления.
Чтобы передать параметризованные функции пользовательским дочерним компонентам, напишите следующее (согласно документации http://aurelia.io/docs/binding/basics#function-references).
Родительский ViewModel
private _generate(myParam:string) {
return myParam + " world";
}
Родительский вид
<custom-comp generator.call="_generate(myParam)"></custom-comp>
Детский вид
<template bindable="generator">
${generator({myParam:"hello"})}
</template>
Это было обновлено для aurelia v2:
Привязка вызова больше не присваивает свойства первого аргумента, передаваемого вызову, контексту переопределения вызова. Это необоснованно динамично и может привести к трудным для понимания шаблонам. В 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)">