jQuery 如何替换 AngularJS 指令链接函数中的元素?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17090964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 18:25:30  来源:igfitidea点击:

How to replace an element in AngularJS directive linking function?

jquerydomangularjsangularjs-directive

提问by Antonio Madonna

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.

我正在创建一个<row>AngularJS 指令,该指令需要<row>用一个可以包含任何 HTML 代码的动态模板来替换自身(执行后标签不能出现在 DOM 中)。

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

使用中的问题replace: true是它不适用于表格的<tr>标签,并且模板是动态选择的。

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

所以我试图找到一种方法来替换链接函数中的元素,但没有成功。

Using jQuery's .replaceWith()breaks ngRepeatfor unknown reason.

出于未知原因使用 jQuery 的.replaceWith()中断ngRepeat

Any hints?

任何提示?

Here is the fiddle

这是小提琴

回答by pilau

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 detailthe reason behind this. In fact, Angular alreadyprovides a far simpler way to replace the directive element with a template. It can be found at the bottom of this answer.

马克的答案会起作用,但是,该示例太有限而无法显示全貌。尽管 Mark 的指令对于常见和简单的 UI 组件可能确实足够了,但对于更复杂的操作,这种模式是应该避免的。下面我详细解释一下这背后的原因。事实上,Angular已经提供了一种更简单的方法来用模板替换指令元素。它可以在这个答案的底部找到。

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 $compilefor the same DOM layout twiceis redundant, bad for performance andbad for your teeth, too. What should you do instead? Simply compile your DOM where it shouldbe compiled:

我们能从中得到什么?很明显,两次手动调用$compile相同的 DOM 布局是多余的,对性能牙齿也不利。你应该怎么做?只需在应该编译的地方编译 DOM :

.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

如果你想深入了解指令,这里是我喜欢称之为非官方AngularJS 指令参考的内容

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

一旦你完成了这个头在这里:https: //github.com/angular/angular.js/wiki/Understanding-Directives



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

现在,正如所承诺的,这是您来到这里的解决方案:

Using replace: true:

使用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: "="
        }
    };
});

回答by Mark Coleman

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

你的小提琴看起来很基本,但你应该能够使用 outerHTML

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

Updated fiddle

更新的小提琴

If you have to deal with ng-repeatyou 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()

如果您必须处理,ng-repeat您可以将您的项目绑定到范围属性并在您编译的模板中引用它们。编译完成后,您可以使用 jQueryreplaceWith()

html

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-repeatexample

ng-repeat例子