17

I have a two-way data binding that is not altering the value of the variable sent to the directive.

My directive watches for a trigger and gives focus to the associates element (based on code found here at SO):

app.directive('focusMe', function ($timeout) {
  return {
    scope: {
      trigger: '=focusMe'
    },
    link: function (scope, element, attrs) {
      scope.$watch('trigger', function(value) {
        console.log("directive value: " + value);
        console.log("directive start: " + scope.trigger);
        if (value === true) {
          $timeout(function () {
            element[0].focus();
            scope.trigger = false;
            console.log("directive end: " + scope.trigger);
          });
        }
      });
    }
  }
});

In the HTML I call it as follows:

<input type="text" ng-model="item.value" focus-me="focusInput" />

When I trigger it for the first time, it works -- because the focusInput variable switches its value. But focusInput in the controllers scope (outside the directive) does not switch back to false when the directive completes.

This switch back to false should happen when I call scope.trigger = false, assuming I understand what should be happening.

What is missing that would cause the two-way binding to not push the value back to the variable passed into the directive?

UPDATE 01:

For posting the question I removed a small bit of code. The HTML actually looks like this:

<input type="text" ng-model="item.value" focus-me="focusInput" ng-if="item.condition != 'matches' && item.condition != 'does not match'" />

If the input fields hides and then is re-shown (based on the ng-if) the directive will properly give focus the first time focusInput changes. It will stop working again after that... unless the hide/show process is repeated.

Nicholas Pappas
  • 10,439
  • 12
  • 54
  • 87

3 Answers3

37

The problem you are experiencing is a common problem when dealing with primitive values (boolean, int, etc..) within scopes.

I strongly suggest reading Understanding Scopes article. (short answer: primitives are changed in the directive's isolated scope, and are not seeked up the chain for the parent scope, i.e., your controller scope).

As to how to solve your situation, I suggest to use dot notation and store your primitive inside an object, and bind this object to your directive:

scope: {
   triggerObj: '=focusMe'
},

And make sure your trigger references in the directive are now scope.triggerObj.trigger.

And in your controller have:

$scope.triggerObj = {};
$scope.triggerObj.trigger = true; //or false, what have you

Having an object will make sure the two way binding will work. And read the article above when you have time :)

Omri Aharon
  • 16,959
  • 5
  • 40
  • 58
5

Directive create a scope. when you pass parameter to scope, object passed by reference and boolean (and number, string...) passed by value.

For example:

function changeToFalse(bool) {
    bool= false;
    console.log(bool);  // false
}


function changeObjToFalse(obj) {
    obj.bool= false;
    console.log(obj.bool);  // false
}

var obj = {bool : true};

changeToFalse(obj.bool);
console.log(obj.bool);  // true
changeObjToFalse(obj);
console.log(obj.bool); // false

See also same question - two way binding not working with ng-repeat.

Community
  • 1
  • 1
Elad
  • 1,114
  • 8
  • 15
0

My scenario was the following:

parentCtrl  
-> directive1  
--> directive2  

and I was trying to pass a parentCtrl.Model.variable through to directive2 with two-way-bindings.

The update was not working from directive1 back to the parentCtrl because of said issue. Using a dummy object in directive1, I would have also needed a watch to pass on the value to parentCtrl.

I ended up trying the following trick in directive1:
$scope.scp = $scope;
and binding directive2 to scp.variable.

The bindings works like this, but I do not know about possible downsides of this hack. Input welcome!

Chris
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 10 '22 at 19:20