Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm creating a <row> AngularJS directive that needs to replace itself (the <row> tag must not be present in the DOM after execution) with a dynamic template that can contain any HTML code.

The problem in using replace: true is that it does not work with table's <tr> tags and that the template is dynamically chosen.

So I'm trying to find a way to replace the element in the linking function, with no success.

Using jQuery's .replaceWith() breaks ngRepeat for unknown reason.

Any hints?

Here is the fiddle

question from:https://stackoverflow.com/questions/17090964/how-to-replace-an-element-in-angularjs-directive-linking-function

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
163 views
Welcome To Ask or Share your Answers For Others

1 Answer

Mark's answer will work, however, that example is too limited to show the whole picture. Whereas Mark's directive might indeed suffice for common and simple UI components, for more complex operations, that pattern is one to be avoided. Below I explain in detail the reason behind this. In fact, Angular already provides a far simpler way to replace the directive element with a template. It can be found at the bottom of this answer.

Here is how a directive looks behind the scenes:

.directive('row', function ($compile) {
  return {
      restrict: 'E',
      scope: {
          items: "="
      },

      // Whether you define it this way or not, this is the order of
      // operation (execution) behind every AngularJS directive.
      // When you use the more simple syntax, Angular actually generates this
      // structure for you (this is done by the $compile service):

      compile: function CompilingFunction($templateElement, $templateAttributes, transcludeFn) {

        // The compile function hooks you up into the DOM before any scope is
        // applied onto the template. It allows you to read attributes from
        // the directive expression (i.e. tag name, attribute, class name or
        // comment) and manipulate the DOM (and only the DOM) as you wish.

        // When you let Angular generate this portion for you, it basically
        // appends your template into the DOM, and then some ("some" includes
        // the transclude operation, but that's out of the $scope of my answer ;) )

          return function LinkingFunction($scope, $element, $attrs) {

            // The link function is usually what we become familiar with when
            // starting to learn how to use directives. It gets fired after
            // the template has been compiled, providing you a space to
            // manipulate the directive's scope as well as DOM elements.

            var html ='<div ng-repeat="item in items">I should not be red</div>';
            var e = $compile(html)($scope);
            $element.replaceWith(e);
          };
      }
  };
});

What can we make out of that? It is obvious then, that manually calling $compile for the same DOM layout twice is redundant, bad for performance and bad for your teeth, too. What should you do instead? Simply compile your DOM where it should be compiled:

.directive('row', function ($compile) {
  return {
      restrict: 'E',
      template: '<div ng-repeat="item in items">I should not be red</div>',
      scope: {
          items: "="
      },

      compile: function CompilingFunction($templateElement, $templateAttributes) {
          $templateElement.replaceWith(this.template);

          return function LinkingFunction($scope, $element, $attrs) {
            // play with the $scope here, if you need too.
          };
      }
  };
});

If you want to dive in further under the hood of directives, here is what I like to call the Unofficial AngularJS Directive Reference

Once you're done with that head over here: https://github.com/angular/angular.js/wiki/Understanding-Directives


Now, as promised, here is the solution you came here for:

Using replace: true:

.directive('row', function ($compile) {
    return {
        restrict: 'E',
        template: '<div ng-repeat="item in items">I should not be red</div>',
        replace: true,
        scope: {
            items: "="
        }
    };
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...