Dor Cohen
Dor Cohen

Reputation: 17080

How to watch component binding change using Angular component

How can I listen to angular component binding change and perform actions?

angular.module('myapp')
    .component('myComponent', {
        templateUrl: 'some.html',
        controller: MyController,
        controllerAs: 'myCtrl',
        bindings: {
            items: '<'
        }
    });

now when items changes I want to perform another action using this value,
How can I do it?

Upvotes: 41

Views: 40123

Answers (6)

Slavik Meltser
Slavik Meltser

Reputation: 10371

This approach might help:

import { Input } from '@angular/core';

class MyComponent {
  @Input set items(value) {
    if (this._items !== value) {
      console.log(`The value has been changed from "${this._items}" to "${value}"`);
      this._items = value;
    }
  }

  private _items;  
  
  get items() {
    return this._items;
  }
}

Upvotes: -1

david-err
david-err

Reputation: 1077

You can add the $onChanges method to the controller

$onChanges(changesObj) is called whenever one-way bindings are updated. The changesObj is a hash whose keys are the names of the bound properties that have changed, and the values are an object of the form.

Following example handles canChange change event.

angular.module('app.components', [])
.component('changeHandler', {
  controller: function ChangeHandlerController() {
    this.$onChanges = function (changes) {
      if (changes.canChange) 
       this.performActionWithValueOf(changes.canChange);
    };
  },
  bindings: {
    canChange: '<'
  },
  templateUrl: 'change-handler.html'
});

Requires AngularJS >= 1.5.3 and works only with one-way data-binding (as in the example above).

Docs: https://docs.angularjs.org/guide/component

Reference: http://blog.thoughtram.io/angularjs/2016/03/29/exploring-angular-1.5-lifecycle-hooks.html

Upvotes: 68

jfrej
jfrej

Reputation: 4648

Here's an ES5.1 version of basarat's answer:

function MyController() {
  var items = [];

  Object.defineProperty(this, 'items', {
    get: function() {
      return items;
    },

    set: function(newVal) {
      items = newVal;
      console.log('Items changed:', newVal);
    }
  });
}

Using Object.defineProperty(). Supported by all major browsers and IE9+.

Upvotes: 7

basarat
basarat

Reputation: 275847

now when items changes I want to perform another action using this value, How can I do it?

But I want to avoid using the dying $scope

If you don't want to use $scope you can use a property setter to detect any changes e.g. :

class MyController {
    private _items: string[] = []
    set items(value:string[]){
        this._items = value;
        console.log('Items changed:',value);
    }
    get items():string[]{
        return this._items;
    }
}

const ctrl = new MyController();
ctrl.items = ['hello','world']; // will also log to the console

Please note that you shouldn't use it for complex logic (reasons : https://basarat.gitbooks.io/typescript/content/docs/tips/propertySetters.html) 🌹

Upvotes: 30

m1gu3l
m1gu3l

Reputation: 773

Currently you can't use angular watchers without $scope as change detection is based around $scope. Even if you use expressions in HTML it would delegate watch functionality to $scope.

Even if you create some other mechanism to watch you will need to remember to unwatch manually - and with $scope it's done automatically.

Upvotes: 0

Chris
Chris

Reputation: 1428

I've discovered a way but not sure it's the most efficient. First bring in $scope as a dependency and set it to this._scope or the like in your constructor. I have the following then in my $onInit function:

this._scope.$watch(() => {
    return this.items;
  },
  (newVal, oldVal) => {
    // Do what you have to here
  });

It's highly inspired by the answer here: Angularjs: 'controller as syntax' and $watch

Hope it helps, it's what I'm going to use until I'm told otherwise.

Upvotes: 3

Related Questions