web-dev-qa-db-ja.com

AngularJSディレクティブリンク機能の要素を置き換える方法は?

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

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

だから私は成功せずに、リンク関数の要素を置き換える方法を見つけようとしています。

JQueryの.replaceWith()を使用すると、不明な理由でngRepeatが壊れます。

ヒントはありますか?

これが fiddle です

40
Antonio Madonna

あなたのフィドルはかなり基本的に見えますが、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_例

52
Mark Coleman

Markの答えは機能しますが、その例は全体を表示するには限定的です。一般的なシンプルなUIコンポーネントではMarkのディレクティブで十分ですが、より複雑な操作ではそのパターンを避ける必要があります。以下に、詳細に説明しますこの背後にある理由。実際、Angularalreadyは、ディレクティブ要素をテンプレートで置き換えるはるかに簡単な方法を提供します。この答えの最後に。

以下は、ディレクティブが舞台裏でどのように見えるかを示しています。

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

それから何ができるのでしょうか?同じDOMレイアウトtwiceに対して手動で$compileを呼び出すことは冗長であり、パフォーマンスに悪いことand歯にも悪い。代わりに何をすべきですか? DOMをshouldコンパイルする場所でコンパイルします。

.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 Directive Reference と呼ぶのが好きです

ここでその頭で終わったら: 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: "="
        }
    };
});
99
pilau