Two-way binding not working on an Aurelia Custom Attribute

Viewed 234

I'm trying to implement this solution given by Jeremy Danyow for dirty checking. I'm using TypeScript so I've adapted his code as best I can. For some reason, the isDirty flag on my VM is not being updated. Here is what I have:

agency.ts - (my vm)

export class Agency {
    public isDirty : boolean = false;
    public agency : IAgency = null;

    ...
}

agency.html - (my view)

<template>
   <require from="../resources/attributes/dirty"></require>
    ${isDirty}                                <== Always displays false
    <form dirty.two-way="isDirty">            <== have also tried dirty.bind
         <div class="input-group">
               <label>Agency Name</label>
               <input type="text" value.bind="agency.name" />
         </div>
         ... 
    </form>
    <div if.bind="isDirty">
         <button>Save Changes</button>
         <button>Undo Changes</button>
    </div>
</template>

dirty.ts - (the attribute)

import {bindable, bindingMode} from 'aurelia-framework';

export class DirtyCustomAttribute{
   private view: any;
   private bindings: any[] = [];
   @bindable({defaultBindingMode: bindingMode.twoWay }) value: any;

   static inject = [Element]
   constructor(public element : HTMLElement) {}

   created(view) {
      this.view = view;
   }

   bind() {  
    this.bindings = this.view.bindings
        .filter(b => b.mode === bindingMode.twoWay && this.element.contains(b.target));

    let i = this.bindings.length;
    let self = this;
    while (i--) {
        let binding = this.bindings[i];
        binding.dirtyTrackedUpdateSource = binding.updateSource;
        binding.updateSource = function (newValue) {
            this.dirtyTrackedUpdateSource(newValue);
            if (!self.value) {
                self.value = true;
            }
        }
    }
   }

   unbind() { // See code in referenced link }
}

So, using logging, I can see that the updateSource() code is being called and the self.value flag is being set. However, the div with the buttons in my view is never displayed and the ${isDirty} template always displays false. It would seem that the dirty.two-way="isDirty" is not two-way binding like it should.

Where am I going wrong?

Update

So it appears it might be due to compose so I'll add the extra code to show how this is being composed.

shell.ts

export class Shell
{
    public agencies : IAgency[] = []; //loaded in activate
    public tablist : any[] = [
        {title: "Detail", vm: PLATFORM.moduleName("./agency") },
         ...
    ];
    public selectedAgency : IAgency = null;
    public selectedVM : any = this.tablist[0];

}

shell.html

<template>
    ...
    <compose view-model.bind="selectedVM.vm" model.bind="selectedAgency"></compose>
</template>

agency.ts (additional)

activate(model){
    this.agency = model;
    ...
}
0 Answers
Related