Map event listening


#1

Hi everybody,

Is it possible, with CanV4 to listen to changes for all keys in a Map or a List that includes nested Maps?

For instance:
const Coordinates = can.Map.extend({ latitude: "number", longitude:"number"});
const Address = can.Map.extend({ addr:"string", num:"string", city:"string", coordinates:{ Default: Coordinates} });
const People = can.Map.extend({ name: "string", lastName: "string", address: { Default: Address });

let John = new People( { name:"John", lastName:"Doe", address:{ addr:"Avenur Str.", num:22, city:"Dover", coordinates: { latitude: 51.133914, longitude: 1.3198505});

If i want to listen any changes in “John” i should do something like:

John.on("name", ()=>{ ... });
John.on("lastName", ()=>{ ... });
John.on("address.addr", ()=>{ ... });
John.on("address.num", ()=>{ ... });
// etc...

Or use a function that will iterate on each key (recursively).

Is there something quicker and also usable for nested object like, for instance:
John.on("change", ()=>{...})

Thank you for the support.


#2

Generally what I do is create a compute that returns .get() of the object you want to observe changes on …

DefineMap.extend({
  nestedThing: {
    default(){ 
      return { 
        name:"John", lastName:"Doe", address:{ addr:"Avenur Str.", num:22, city:"Dover", coordinates: { latitude: 51.133914, longitude: 1.3198505} 
      };
    } 
  },
  get nestedThingData(){ 
    return this.nestedThing.get();
  },
  connectedCallback(){
    this.listenTo("nestedThingData", function(){ /*called when anything changes */ }
  }
})

#3

Than you! I tried this approach and it works like a charm!!! :grinning:

I also tried set the “nestedThing” with any customized extended map and catch also changing events of properties that are not defined by default (a not sealed map).

Thank a lot!


#4

:+1: for this technique.

We used it on a DefineList containing DefineMaps, like this:

items: {
    default() {
      return [{name:'a', type: 'atype'}, {name:'b', type: 'btype'}, {name:'c', type: 'ctype'}]
    }
  },
  get itemsWatcher() {
    return this.items.reduce((watcher, item) => {
      watcher.set(item.type, item.name);
      return watcher;
    }, new can.DefineMap()).get()
  }
  connectedCallback() {
    this.listenTo('itemsWatcher', (ev, newVal) => {
      console.log('itemChanged', newVal);
    });
  }