Home » Angularjs » Angularjs isolated scope for directives without own template

Angularjs isolated scope for directives without own template

Posted by: admin November 30, 2017 Leave a comment

Questions:

I want to create reusable directive in AngularJS without own template. I also want to have isolated scope for that directive. What is the best practices for my approach?
Why my example doesn’t work as I expect?

I expected that I could edit obj1 and obj2 from directives separately.

HTML:

<div ng-controller="MyCtrl">
  X1: {{ obj1.x }}, Y1: {{ obj1.y }}
  X2: {{ obj2.x }}, Y2: {{ obj2.y }}
  <hr>
  Edit obj1: 
  <div draggable target="obj1">
    <input type="text" ng-model="target.x">
    <input type="text" ng-model="target.y">
  </div>
  Edit obj2:
  <div draggable target="obj2">
    <input type="text" ng-model="target.x">
    <input type="text" ng-model="target.y">
  </div>
</div>

JS:

angular.module("App", [])
  .controller("MyCtrl", function($scope) {
    $scope.obj1 = {
      x: 10,
      y: 20
    };
    $scope.obj2 = {
      x: 30,
      y: 40
    };
  })
  .directive("draggable", function() {
    return {
      scope: {
        target: "="
      },
      link: function(scope, el, attrs) {
        console.log("scope: ", scope);
      }
    }
  });

PLUNKR:
http://plnkr.co/edit/Dw8IiFVSOZGjSTFGRMzZ

Answers:

The way your code is working now, is that the contents of each directive is bound to the parent scope, and not the isolated scope of the directive, so each target is a reference to the same variable.

What you’ll need to do is to transclude the contents of the directive. The usual use for this is that you want the contents to be in the parent scope of the directive, and not in the isolated scope. However, you want the content to be in the isolated scope of the directive. So you’ll have to call the transclude function manually, and bind the contents to the isolated scope of the directive:

.directive("draggable", function($compile) {
  return {
    transclude: true,
    scope: {
      target: "="
    },
    link: function(scope, element, attrs, ctrl, transclude) {
      transclude(scope, function(clone) {
       element.append(clone);
      });
    }
  }
})

You can see this in this Plunker. One thing it doesn’t do is $watch the contents of the ‘target’ so I suspect it won’t react to changes in the “target” attribute on the directive. This might be best left to another question.

Edit: the use of transclude was incorrect / overcomplicated. You can pass the scope in as the first parameter to properly bind the clone to the correct scope.

Questions:
Answers:

Came here facing the same confusion. Apparently, the case is as follows.

Transclusion aside, only elements in a template for the directive will be bound to the isolated scope created by that directive. If you don’t use a template – content of the element, on which the directive is declared, will bind as if isolated scope was not there.

Here is a modified plunker from above that showcases this.
http://plnkr.co/edit/WqEKkNAj4p2Rly51LBzC?p=preview