Vaccano
Vaccano

Reputation: 82341

Update a binding in an Aurelia custom attribute

The Code:

my-view-model.html

<input on-scan.bind="onAirbillScanned" value.bind="airbill"/>

on-scan.ts

attached() {
    var scannerOptions = { onComplete: this.onScan.bind(this), preventDefault: true };
    (<any>$(this.element)).scannerDetection(scannerOptions);

    -- Code to add a signal to the value binding.
}

onScan(scannedValue, data) {
    if (typeof (this.value) == 'function') {

        let updatedScanValue = this.value(scannedValue);
        if (updatedScanValue !== undefined)
            this.element.value = updatedScanValue;
        else
            this.element.value = scannedValue;

       -- Code to Call the Signal

    }
}

The Problem:

I have a custom attribute that allows me to detect a scan, modify the scanned-in data and set it to be the value of the input element.

However, I need to update aurelia with the updated value.

I can just fire off an 'input' event to make this happen. But I have found side effects when random 'input' events are fired.

I would rather use the signal system outlined here: http://aurelia.io/docs.html#/aurelia/binding/1.0.0-beta.1.1.3/doc/article/binding-binding-behaviors

But the problem is that I need the signal to be on the value.bind binding.

The Question:

Is there a way (using my access to the element that the binding is on) to update the value.binding to have a signal that I can call to get the binding to update?

Basically I am looking for something like this:

addSignal(element, property, signal) {...}

..

addSignal(this.element, 'value', 'scanFinished');

And it will update the input's value binding to look like this:

<input on-scan.bind="onAirbillScanned" value.bind="airbill & signal: 'scanFinished'"/>

But more than just re-writing the html, it would have to update Aurelia to know about the signal.

Or is there a signal value that Aurelia adds to all bindings for scenarios like this?

NOTE: It would be awesome if all aurelia bindings had a AureliaBinding signal defined so you could target that control and send an event that will have no side effects other than to update the binding.

Upvotes: 2

Views: 1001

Answers (1)

Jeremy Danyow
Jeremy Danyow

Reputation: 26406

I think you're having trouble because you're at the tipping point where it's time to switch from a custom attribute to an approach that uses a custom element.

You can circumvent the whole issue by doing something like this:

scanner.html

<template>
  <input ref="input" value.bind="value">
</template>

scanner.js

import {bindingMode} from 'aurelia-framework';

export class Scanner {
  @bindable({ defaultBindingMode: bindingMode.twoWay }) value;
  @bindable scanModifier = x => x;
  input: HTMLInputElement;

  attached() {
    let scannerOptions = {
      onComplete: value => this.value = this.scanModifier(value),
      preventDefault: true
    };
    (<any>$(this.input)).scannerDetection(scannerOptions);
  }

  detached() {
    (<any>$(this.input)).scannerDetection('destroy');
  }
}

usage:

<require from="./scanner"></require>

<scanner value.bind="airbill" scan-modifier.call="onAirbillScanned($event)"></scanner>

This could still be done with a custom attribute but it seems more natural to me this way. What do you think?

Upvotes: 2

Related Questions