41

<row>HTMLコードを含むことができる動的テンプレートでそれ自体を置き換える必要があるAngularJSディレクティブを作成しています(<row>タグは実行後にDOMに存在してはなりません)。

使用上の問題はreplace: true、テーブルのタグでは機能せず<tr>、テンプレートが動的に選択されることです。

そのため、リンク関数の要素を置き換える方法を見つけようとしていますが、成功しません。

不明な理由でjQuery の.replaceWith()中断を使用しています。ngRepeat

ヒントはありますか?

ここにフィドルがあります

4

2 に答える 2

101

マークの答えは機能しますが、その例は限定的すぎて全体像を示すことができません。Mark のディレクティブは、一般的で単純な UI コンポーネントには十分かもしれませんが、より複雑な操作では、そのパターンは避けるべきものです。以下、その理由を詳しく説明します。実際、Angularはすでにディレクティブ要素をテンプレートに置き換えるはるかに簡単な方法を提供しています。この回答の下部にあります。

ディレクティブが舞台裏でどのように見えるかを次に示します。

.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);
          };
      }
  };
});

そこから何ができるでしょうか?$compileしたがって、同じ DOM レイアウトを手動で2 回呼び出すのは冗長であり、パフォーマンス歯に悪いことは明らかです。代わりに何をすべきですか?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.
          };
      }
  };
});

ディレクティブの内部をさらに掘り下げたい場合は、私が非公式のAngularJS ディレクティブ リファレンスと呼んでいるものを以下に示します。

ここでその頭を使い終わったら: https://github.com/angular/angular.js/wiki/Understanding-Directives


さて、約束通り、あなたがここに来た解決策は次のとおりです。

使用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: "="
        }
    };
});
于 2013-11-02T23:34:20.180 に答える
54

あなたのフィドルはかなり基本的なようですが、単に使用できるはずですouterHTML

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

更新されたフィドル

対処するng-repeat必要がある場合は、アイテムをスコープ プロパティにバインドし、コンパイルしたテンプレートでそれらを参照できます。コンパイルしたら、jQueryを使用できますreplaceWith()

html

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

指令

.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

于 2013-06-13T16:04:53.737 に答える