1

Given the following Plunker: http://plnkr.co/edit/YicBDARAf5umI0PdCL8L?p=preview

Why isn't $scope.someVal being set in the directive controller?

I would expect the output of the template to show

someVal = ABC controllerVal=DEF

but instead it shows

someVal = 123 controllerVal=DEF

Html:

<html>
  <head>
    <script data-require="angular.js@1.2.25" data-semver="1.2.25" src="https://code.angularjs.org/1.2.25/angular.js"></script>
  </head>

  <body ng-app='myApp'>
    <my-test some-val="123"></my-test>

    <script>
      angular.module("myApp", [])
      .directive("myTest", function() {
        return {
          restrict: "E",
          scope: {
            someVal: "@"
          },
          template: "someVal = {{someVal}}  controllerVal={{controllerVal}}",
          controller: function($scope) {
            $scope.someVal = "ABC";
            $scope.controllerVal = "DEF";
          }
        }
      });
    </script>
  </body>
</html>
PSL
  • 123,204
  • 21
  • 253
  • 243
Scottie
  • 11,050
  • 19
  • 68
  • 109
  • This is the usual issue of passing reference vs valueType. Use `Model.someVal` ... check it here http://stackoverflow.com/a/21882900/1679310. *(Model will be passed as a reference so the value changed in the inner scope of directive will be changing the field `Model.someVal` of that reference - therefore all will work as expected)* – Radim Köhler Sep 26 '14 at 16:22
  • Also for two way binding we need `=` instead of `@`. see [here](http://stackoverflow.com/a/21807951/1679310). If we want to let the change made in directive to go to caller, we need a reference to be passed as also already [mentioned](http://stackoverflow.com/a/21882900/1679310) – Radim Köhler Sep 26 '14 at 16:31
  • 1
    http://plnkr.co/edit/zCSWDa?p=preview You dont need 2 way binding.. Only thing you need to make sure is that your scope update runs later, otherwise it will get overridden by one-time bound value. – PSL Sep 26 '14 at 16:32
  • @PSL: Copy as answer and I'll accept. Thanks! – Scottie Sep 26 '14 at 16:34
  • @Scottie Sure il add it with explanation. Thx! – PSL Sep 26 '14 at 16:36

1 Answers1

2

The reason why you don't get the updated scope.someVal (done from directive controller), which is a one way bound value (@), is because when the directive compiles it overwrites the scope.someVal with the interpolated value from one time binding (Basically it runs interpolation on attr.someVal while creating the isolated scope). So ultimately you will see the one time bound value. One workaround would be to delay your overwrite by making the call async so that it gets updated during the next digest cycle.

Example:- Wrap it in a $timeout or use push it to async queue

    controller: function($scope, $timeout) {

         $scope.$evalAsync(init);//Set up initialization

         $scope.controllerVal = "DEF";

         function init(){
            $scope.someVal = "ABC";
          }
      }

Demo

PSL
  • 123,204
  • 21
  • 253
  • 243