Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can an Angular directive compile() function access an isolated scope?

I have the following directive:

angular.module("example_module", [])
.directive("mydirective", function() {
  return {
    scope: { data: "@mydirective" }
    compile: function(element) {
      element.html('{{example}}');
      return function($scope) {
        $scope.example = $scope.data + "!";
      };
    }
  };
});

and the following HTML code:

<!DOCTYPE html>
<html ng-app="example_module">
  <head>
    <meta charset="utf-8">
    <title>Example title</title>
    <script src="lib/angular/angular.min.js"></script>
    <script src="js/example.js"></script>
  </head>
  <body>
    <div mydirective="Hello world"></div>
  </body>
</html>

I would expect the directive to compile to Hello world!, but it compiles to an empty string instead. scope creates an isolated scope which seems impossible to reach for {{example}}.

I would like to know how the new HTML code created by compile() can access the link function $scope.

like image 322
ehmicky Avatar asked Feb 25 '15 19:02

ehmicky


People also ask

How do I isolate the scope of a component in angular?

Isolated Scope In AngularJS. It can access its parent scope through the $parent property. So, Directive has three options for isolating its scope from parent scope. The following are the three options: scope: false - It is default in Directive. It lets to reuse the scope from the place where the component is being used.

What is the scope of a directive in AngularJS?

This scope object is used for accessing the variables and functions defined in the AngularJS controllers, and the controller and link functions of the directive. By default, directives do not create their own scope; instead they use the scope of their parent, generally a controller (within the scope of which the directive is defined).

How do I isolate the scope of a directive?

Isolating the scope in a directive is a simple process. Start by adding a scope property into the directive, as shown next. It automatically isolates the directive’s scope from any parent scope (s). The @ local scope property is used to access string values that are defined outside the directive.

What is compiling in AngularJS?

For AngularJS, "compilation" means attaching directives to the HTML to make it interactive. The reason we use the term "compile" is that the recursive process of attaching directives mirrors the process of compiling source code in compiled programming languages. Matching Directives


1 Answers

This doesn't work because {{example}} is being evaluated against the parent scope, which makes sense, since you are essentially changing the element before compilation to:

<div>{{example}}<div>

You can verify by replacing '$scope.example =' with '$scope.$parent.example =' (for demonstration purposes only - it's not a best practice to use $parent).

What you are really trying to do is something similar to transclusion, but there are very easier ways to do it. For instance:

angular.module("example_module", [])
.directive("mydirective", function() {
  return {
    restrict: 'A',
    scope: { data: "@mydirective" },
    template: '{{example}}',
    compile: function(element) {
      return function($scope) {
        console.log($scope.data);
        $scope.example = $scope.data + "!";
        console.log($scope.example);
      };
    }
  };
});

When you use a template, it replaces the content of the element the directive is applied to (unless you use replace: true, in which case it replaces the entire element), and the contents of the template are evaluated against the directive scope.

You could do what you are trying to do using the transclude parameter passed to compile (see the docs), but this has been deprecated so I wouldn't recommend going down that road.

Here's a Plunk where you can play with some variations.

like image 152
Joe Enzminger Avatar answered Oct 18 '22 00:10

Joe Enzminger