Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Aurelia have an AngularJS $watch alternative?

I'm trying to migrate my current Angular.js project to Aurelia.js. I'm trying to do something like that:

report.js

export class Report {
       list = [];

       //TODO
       listChanged(newList, oldList){
             enter code here
       }
}

report.html

<template>
    <require from="component"></require>
    <component list.bind="list"></component>
</template>

So the question is: how to detect when is the list changed?

In Angular.js I can do

$scope.$watchCollection('list', (newVal, oldVal)=>{ my code });

Maybe Aurelia have something similar?

like image 831
Egor Malkevich Avatar asked Nov 18 '15 18:11

Egor Malkevich


People also ask

Is Aurelia similar to Angular?

Angular and Aurelia are fierce competitors developed and released at approximately the same time. They have a similar philosophy, but they differ in a number of key ways.

Is Aurelia a good framework?

It offers great rendering speed and memory efficiency: Aurelia implements batch rendering and observable object pooling, which allows it to render faster than any other framework. Aurelia also utilizes less memory and causes less GC churn than other frameworks.

What is the angular equivalent to an AngularJS watch?

You can use getter function or get accessor to act as watch on angular 2.

What is not recommended in Angular JS?

It is tempting to do too much work in the AngularJS controller. After all, the controller is where the view first has access to JavaScript via $scope functions. However, doing this will cause you to miss out on code sharing across the site and is not recommended by AngularJS documentation.


2 Answers

For @bindable fields the listChanged(newValue, oldValue) would be called whenever the list value is updated. Please take a look Aurelia docs

@customAttribute('if')
@templateController
export class If {
  constructor(viewFactory, viewSlot){
    //
  }

  valueChanged(newValue, oldValue){
    //
  }
}

You can also use ObserveLocator as described in Aurelia author's blogpost here:

import {ObserverLocator} from 'aurelia-binding';  // or 'aurelia-framework'

@inject(ObserverLocator)
class Foo {  
  constructor(observerLocator) {
    // the property we'll observe:
    this.bar = 'baz';

    // subscribe to the "bar" property's changes:
    var subscription = this.observerLocator
      .getObserver(this, 'bar')
      .subscribe(this.onChange);
  }

  onChange(newValue, oldValue) {
    alert(`bar changed from ${oldValue} to ${newValue}`);
  }
}

UPD

As mentioned in this question by Jeremy Danyow:

The ObserverLocator is Aurelia's internal "bare metal" API. There's now a public API for the binding engine that could be used:

import {BindingEngine} from 'aurelia-binding'; // or from 'aurelia-framework'

@inject(BindingEngine)
export class ViewModel {
  constructor(bindingEngine) {
    this.obj = { foo: 'bar' };

    // subscribe
    let subscription = bindingEngine.propertyObserver(this.obj, 'foo')
      .subscribe((newValue, oldValue) => console.log(newValue));

    // unsubscribe
    subscription.dispose();
  }
}

Best regards, Alexander

like image 86
Alexander Mikhalchenko Avatar answered Oct 29 '22 15:10

Alexander Mikhalchenko


Your original code will work with one small tweak:

report.js

import {bindable} from 'aurelia-framework'; // or 'aurelia-binding'

export class Report {
       @bindable list;  // decorate the list property with "bindable"

       // Aurelia will call this automatically
       listChanged(newList, oldList){
             enter code here
       }
}

report.html

<template>
    <require from="component"></require>
    <component list.bind="list"></component>
</template>

Aurelia has a convention that will look for a [propertyName]Changed method on your viewmodel and call it automatically. This convention is used with all properties decorated with @bindable. More info here

like image 45
Jeremy Danyow Avatar answered Oct 29 '22 14:10

Jeremy Danyow