How to replace an element in AngularJS directive linking function?

后端 未结 2 1809
一向
一向 2021-01-30 13:28

I\'m creating a AngularJS directive that needs to replace itself (the tag must not be present in the DOM after execution) with

相关标签:
2条回答
  • 2021-01-30 13:40

    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: "="
            }
        };
    });
    
    0 讨论(0)
  • 2021-01-30 13:58

    Your fiddle seems pretty basic but you should be able to just use outerHTML

    element[0].outerHTML ='<div>I should not be red</div>';
    

    Updated fiddle

    If you have to deal with ng-repeat you can bind your items to a scope property and reference them in your template that you compile. Once it is compiled you can use jQuery replaceWith()

    html

    <row items="items">***</row>
    

    directive

    .directive('row', function ($compile) {
        return {
            restrict: 'E',
            scope: {
                items: "="
            },
            link: function (scope, element, attrs) {
                var html ='<div ng-repeat="item in items">I should not be red</div>';
                var e =$compile(html)(scope);
                element.replaceWith(e);
            }
        };
    });
    

    ng-repeat example

    0 讨论(0)
提交回复
热议问题