Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS directive $watch two-way binding

I'm trying to distinguish between internal change and an external change with a two-way data-bound attribute ('=').

In other words: I don't want to $watch to fire on the value if the change was internal (i.e. the scope variable was changed in the controller or in the link function).

Here some code that illustrates my problem:

HTML

 <div ng-app="myApp">         
   <div ng-controller="MainCtrl">
     <input ng-model="value"/>
     <mydemo value="value"></mydemo>
   </div>
 </div>

Javascript

app.directive('mydemo', function () {
  return {
    restrict: 'E',
    scope: {
      value: "="
    },
    template: "<div id='mydiv'>Click to change value attribute</div> Value:{{value}}",

    link: function (scope, elm) 
    {      
      scope.$watch('value', function (newVal) {
      //Don't listen if the change came from changeValue function
      //Listen if the change came from input element 
      });
      // Otherwise keep any model syncing here.

      var changeValue = function()
      {
        scope.$apply(function ()
        {
          scope.value = " from changeValue function";
        });
      }

      elm.bind('click', changeValue);
    }
  }
})

Live demo: http://jsfiddle.net/B7hT5/11/

Any idea who can I distinguish?

like image 836
cheziHoyzer Avatar asked Aug 28 '14 15:08

cheziHoyzer


People also ask

Does AngularJS support two way binding?

AngularJS creates a two way data-binding between the select element and the $ctrl.

What is $Watch in AngularJS?

What is the angular JS watch function? The angular JS $watch function is used to watch the scope object. The $watch keep an eye on the variable and as the value of the variable changes the angular JS $what runs a function. This function takes two arguments one is the new value and another parameter is the old value.

Which object is used for two way data binding in AngularJS?

Two-way data binding is achieved by using the ng-model directive. The ng-model directive transfers data from the view to the model and from the model to the view.

What are the binding directives in AngularJS?

The ng-bind directive tells AngularJS to replace the content of an HTML element with the value of a given variable, or expression. If the value of the given variable, or expression, changes, the content of the specified HTML element will be changed as well.


1 Answers

There's no option to distinguish between these two events, so you'll have to implement that behaviour yourself.

I would do it by setting a flag whenever you make a change "internally", then checking for it in the watch.

For example:

link: function (scope, elm){      

  var internal = false;

  scope.$watch('value', function (newVal) {
    if(internal) return internal = false;
    // Whatever code you want to run on external change goes here.
    console.log(newVal);
  });

  var changeValue = function(){
    scope.$apply(function (){
      internal = true; // flag internal changes
      scope.value = " from changeValue function";                              
    });
  }

  elm.bind('click', changeValue);
}

See the updated fiddle.

Your alternative (more complex) approach, is creating a custom directive that uses the ngModel API. That distinguishes between DOM -> Model (external) and Model -> DOM (internal) changes. I don't think it's necessary here, though.

like image 156
Ed_ Avatar answered Sep 19 '22 22:09

Ed_