Warren
Warren

Reputation: 755

Isolate Scope "=" binding and doted notation AngularJS

How do you create a 2 way binding with a nested property in an isolate scope with dotted notation. I thought 'myObject.data': "=data" would work, but it does not. I don't want to link everything in the myObject object. I know I could do some sort of watch, but 'myObject.data' seems cleaner.

.directive("myDirective", [function() {
    return {
        restrict: "E",
        scope: {
            'myObject.data': "=data"
        },
        link: function (scope, element, attrs) {

            scope.myObject = {
                 data: "myValue"
            };
        }
     };
 }])

Upvotes: 6

Views: 2310

Answers (2)

david
david

Reputation: 944

What I use in these cases is the following:

.directive("myDirective", [function() {
    return {
        restrict: "E",
        scope: {
            data: "="
        },
        controller: function($scope){
           $scope.dot = $scope //<--- here is the trick
        } 
     };
 }])

Then you can always change data in the directive's scope from an inherited scope through dot.data = 'whatever' without setting watchers.

Not very elegant but it works jsut fine in cases where you are not using the controller as syntax and don't want a $parent nightmare.

Upvotes: 0

mortalapeman
mortalapeman

Reputation: 1425

Isolated scopes are generally useful only with templates, they should not be used as a way to declare how you want your directive attributes to be interpreted. This is because most directives that don't have a template usually need the semantics of either a child scope or the direct scope of their environment.

In your case, you probably don't even need a $watch, because object references are what enable 2 way data binding, but without your full code I cannot be sure.

In case you want to know the translations for an isolated scope semantics to just a normal one:

@name -> attrs.name
=name -> $scope.$eval(attrs.name);
&name -> function() { return $scope.$eval(attrs.name); } 

EDIT 2:

After your comment, I came up with this plunker. To preserve two way data binding you have to use a "." in your ng-model declaration. This is because two way data binding does not work for value types, since they are immutable. You can't change the value of 100 for example. You need to pass around a reference type object and hang the values you are changing off of it. Your desire to specify the full path to the value in the isolated scope definition is not possible based on the principles that two way data binding is made possible by.

Javascript:

angular.module('plunker', [])

.directive('twoWay', function() {
  return {
    restrict: 'E',
    template: '<div><input ng-model="thing.name" type="text" /></div>',
    scope: {
      thing: "="
    }, 
    link: function(scope, element, attrs) {
    }
  };
})

.controller('MainCtrl', function($scope) {
  $scope.data = {
    name: "World"
  };
});

HTML:

  <body ng-controller="MainCtrl">
    <p>Hello {{data.name}}!</p>
    <two-way thing="data"></two-way>
  </body>

Upvotes: 8

Related Questions