Two-Way binding in an Aurelia Custom Attribute

2019-04-06 15:56发布

问题:

UPDATE: It looks like this is a known bug: https://github.com/aurelia/templating/issues/253
I am leaving it here for reference / searchability purposes.

The Code:

input-mask.ts (Full code can be seen here)

@customAttribute('input-mask')
@inject(Element)
export class InputMaskCustomAttribute {

    @bindable({ defaultBindingMode: bindingMode.twoWay,
                changeHandler: 'onUnmaskedValueChanged'  })
    unmaskedValue: any;

    onUnmaskedValueChanged(newValue, oldValue) {
        console.log('unmaskedValue updated from inside the custom attribute');
    }

    @bindable
    mask: string;

    attached() {

          this.eventTarget.on('focusout', (e: any) => {
             this.unmaskedValue = (<any>$(this.element)).cleanVal()
             this.fireEvent(e.target, 'input');
          });
    }

  // Code for constructor, fireEvent and to setup the mask...
}

carrier.html

<input input-mask="mask.bind: carrier.airbillMask; unmasked-value.bind: airbill" 
       value.bind="formattedAirbill"/>

UPDATE: To work around this bug, change to unmasked-value.two-way and the binding will work.

carrier.ts

@bindable({ defaultBindingMode: bindingMode.twoWay})
carrier: EntityInterfaces.ICarrier;

@bindable({ defaultBindingMode: bindingMode.twoWay })
formattedAirbill: string;

@bindable({ defaultBindingMode: bindingMode.twoWay, changeHandler: 'onAirbillChanged' })
airbill: string;

onAirbillChanged() {
    console.log('Airbill was set!');
}

The Problem:

The data seems to flow into the @bindable variable just fine. As the mask changes, the value in the custom attribute is changed.

But it does not seem to flow out if changes are made inside the custom-attribute.

Example Scenario: After I edit the value in the input box, and exit the input, the focusout event fires and the console statement that indicates that the unmasked Value was updated from inside the custom attribute prints:

unmaskedValue updated from inside the custom attribute

But (when the input looses focus) the console statement saying that the airbill on the carrier.ts file was updated does not fire when I exit the input box:

This does not fire:
console.log('Airbill was set!');

This seems to show to me that the binding is not really two-way.

The Question:

How can I make this binding two-way? So that when I update unmaskedValue inside the custom-attribute it will update the bound value in the view model?

Note: As a workaround, I was able change unmasked-value.bind to be a method call (on-unmasked-value-changed.call="onUnmaskedValueChanged($event)) and update the value in that method. So I don't NEED this to work. But I would like to know if it is possible for future use.

回答1:

This known bug have been fixed and closed on Mar 15, 2016 https://github.com/aurelia/templating/issues/253#issuecomment-189394955



回答2:

Try to initialize the variable unmaskedValue with default value. Try null, undefined, '' and so on. I have done this before but I don`t remember in which version (certainly it was beta)