2 way databinding in Aurelia custom elements - bin

2020-04-02 08:40发布

问题:

In my application I have made a lot of "services" which I can inject in my viewmodels to save som redundancy and time.

Now I'm looking to take it 1 step further, and make those form elements (select, text, checkboxes - a select dropdown for starters) and turn them into custom elements, injecting the service in only the custom element.

I can get it working to some extent. The custom element (select in this case) is showing when I require it in the "parent" view, however when I change the selected value of the custom select element, it does not bind to the "parent" viewmodel, which is my requirement.

I want to be able to bind my selected value from the custom element to a property on the "parent" viewmodel via the bind attribute in it's template.

I'll update which a little code snippet in a few minutes.

create.js (what I refer to as parent viewmodel)

import {bindable} from 'aurelia-framework';
export class Create{
    heading = 'Create';
    @bindable myCustomElementValue = 'initial value';
}

create.html (parent view)

<template>
    <require from="shared/my-custom-element"></require>
    <my-custom selectedValue.bind="myCustomElementValue"></my-custom>
    <p>The output of ${myCustomElementValue} should ideally be shown and changed here, as the select dropdown changes</p>
</template>

my-custom.js

import { inject, bindable} from 'aurelia-framework';
import MyService from 'my-service';

@inject(MyService )
export class MyCustomCustomElement {
    @bindable selectedValue;

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

    selectedValueChanged(value) {
        alert(value);
        this.selectedValue = value;
    }

    async attached() {
        this.allSelectableValues = await this.myService.getAllValues();
    }
}

What happens is initially the create.html view outputs "initial value", and as I change the value of the custom element select, the newly selected value gets alerted out, but it does not update the bound parent variable, which is still just displaying "initial value".

回答1:

There are a couple of issues here:

  1. You need to kebab-case any property names in the DOM due to case-insensitivity

    selected-value.bind="property"

    not

    selectedValue.bind="property"

  2. You need to bind two-way. When creating a @bindable using the decorator, one of the arguments is BindingMode which you use to set the default binding mode.

    Aurelia sets some sensible defaults, e.g. the default for input value.bind=".." is two way without being explicit

    If you don't want to set a default binding mode, you can just be explicit with your binding:

    selected-value.two-way="prop"

Hope this helps :)

Edit: I think the API changed a little after this answer.

The @bindable decorator has the following sig:

bindable({
  name:'myProperty',
  attribute:'my-property',
  changeHandler:'myPropertyChanged',
  defaultBindingMode: bindingMode.oneWay,
  defaultValue: undefined
})

One of the best places to check for quick reference is the Aurelia cheat-sheet in the docs:

http://aurelia.io/docs/fundamentals/cheat-sheet



标签: aurelia