Multi observer property name

I’m using the multi observer pretty much the one described on the blog

filter: any = {
  pageIndex: 0,
  pageSize: 25,
  query: '',
  orderColumn: 'name',
  orderDirection: 'asc'
};

constructor(private multiObserver: MultiObserver){
    this.multiObserver.observe(this.filter, Object.getOwnPropertyNames(this.filter), () => this.filterChanged(), []);
}

filterChanged(){
 // Get propertyname here which triggered the change.
  this.getApplicationList();
}

That’s all working fine, but I would really like to know which one of the properties is changed, since I have need to have different behavior when the pageIndex is changed then when all the other properties are changed. Is there a way to get the property name inside the filterChanged function? Hope that someone can help out.

1 Like

You might want to take a look at the watch decorator Better know a framework #27: using watch decorator - #12 by bigopon

1 Like

Thanks for the suggestion. I did look at the watch decorator, but it seems it’s not supporting array changes. I know that’s not in my example :innocent:, can anybody suggest another option.

I can always create a separate observer for the page index and handle it like this for instance:

this.multiObserver.observe(this.filter, Object.getOwnPropertyNames(this.filter), () => this.filterChanged(false), [
  'pageIndex'
]);
this.multiObserver.observe(this.filter, ['pageIndex'], () => this.filterChanged(true));

But I have a lot of pages with this functionality (all of them with a different set of filters), so trying to keep it as simple as possible.

1 Like

@bigopon is Array watching perhaps a future usecase for the watch deco?

1 Like

In the example here

this.multiObserver.observe(this.filter, Object.getOwnPropertyNames(this.filter), () => this.filterChanged(false), [
  'pageIndex'
]);
this.multiObserver.observe(this.filter, ['pageIndex'], () => this.filterChanged(true));

There doesn’t seem to be any array? If that’s the case, maybe can you clarify it a bit @mark

Sure I can, I tried to kept the sample as simple as possible, that’s why I didn’t include the array. But I have pages with filters like this:

filter: ProductListFilter = {
    pageIndex: 0,
    pageSize: 25,
    query: '',
    orderColumn: 'createdDate',
    orderDirection: 'desc',
    suppliers: [],
    categories: [],
    tags:[]
};

I modified the observer to have a array of properties to exclude (which in practice at the moment is used for pageIndex only)

observe(object: any, properties: string[], callback: any, excludedProperties: string[] = []): Observer

1 Like

You can use the binding engine directly to observe an expression, so that you can automatically watch a property on an object, and optionally watch the length property of the sub object, which roughly equals to observing the array. An example here https://gist.dumber.app/?gist=d47cc594e7adf3f46548d9d1aaa8e2b2

1 Like

Thank you very much @bigopon for your example :star_struck: I implemented it like below. It also got some of your binding-ext.js sample with the taskqueue, which I also need when clearing multiple filters.

Not sure whether I should use the collectionObserver or the expressionObserver, but both options work the way I want to.

@autoinject
export class AnotherObserver {
  constructor(private bindingEngine: BindingEngine, private taskQueue: TaskQueue) {}

  observe(object: any, callback: (this: void, e: string) => void): Observer {
    let isCallbackQueued = false;

    const unmarkQueued = () => {
      isCallbackQueued = false;
    };

    const subscriptions = Object.keys(object).map((prop) => {
      const property = object[prop];
      let observer: any;
      if (Array.isArray(property)) {
        observer = this.bindingEngine.collectionObserver(object[prop]);
      } else {
        observer = this.bindingEngine.propertyObserver(object, prop);
      }

      return observer.subscribe(() => {
        if (!isCallbackQueued) {
          this.taskQueue.queueMicroTask(unmarkQueued);
          this.taskQueue.queueMicroTask(() => callback(prop));
          isCallbackQueued = true;
        }
      });
    });

    return {
      dispose: () => {
        while (subscriptions.length) {
          subscriptions.pop()();
        }
      }
    };
  }
}
1 Like