Могу ли я в 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()"

Однако я до сих пор не уверен, как передать данные из пользовательского элемента в метод родительской модели представления.

Вот документация с сайта aurelia.

Чтобы передать параметризованные функции пользовательским дочерним компонентам, напишите следующее (согласно документации 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)">
Другие вопросы по тегам