角度ng-bind-htmlとその中のディレクティブ


96

プランカーリンク

HTMLをバインドしたい要素があります。

<div ng-bind-html="details" upper></div>

うまくいきます。これで、バインドされたhtmlにバインドされたディレクティブもあります。

$scope.details = 'Success! <a href="#/details/12" upper>details</a>'

ただし、upperdivとanchorを含むディレクティブは評価されません。どうすれば機能しますか?


3
ここに私の答えを見てみると、stackoverflow.com/questions/17343696/...
Chandermani

@Chandermaniはng-bind-html-unsafe内でディレクティブを正確に使用していませんが、フィルターを使用しています。しかし、それで十分です。フィルターを作成し、ディレクティブに渡しました。ありがとう!
アミタバ2013

@SamSeriousは、あなたがフィルターに対して何をしたかを示すことができますか?
CMCDragonkai 2013

上記のソリューションは、値の複数の変更を処理しない優れたソリューションであるstackoverflow.com/a/25516311/3343425
fghibellini '26

回答:


188

私もこの問題に直面しており、インターネットを何時間も検索した後、@ Chandermaniのコメントを読みました。これが解決策であることがわかりました。次のパターンで「コンパイル」ディレクティブを呼び出す必要があります。

HTML:

<div compile="details"></div>

JS:

.directive('compile', ['$compile', function ($compile) {
    return function(scope, element, attrs) {
        scope.$watch(
            function(scope) {
                // watch the 'compile' expression for changes
                return scope.$eval(attrs.compile);
            },
            function(value) {
                // when the 'compile' expression changes
                // assign it into the current DOM
                element.html(value);

                // compile the new DOM and link it to the current
                // scope.
                // NOTE: we only compile .childNodes so that
                // we don't get into infinite loop compiling ourselves
                $compile(element.contents())(scope);
            }
        );
    };
}])

あなたはそれの実際のフィドルをここで見ることができます


1
行#2、すなわち。function(scope, element, attrs)、これらの3つの引数、scopeelement、およびattrsからどこで取得しましたか?
2015

1
@spaffy- linkプロパティのAngularフレームワークの署名の一部です。それらはlink、Angularフレームワークによって呼び出されるたびに自動的に渡されます。いつでも利用できます。
ベン、

1
よくやった。あなたは私と同じ時間の検索を助けてくれました。ng-repeatなどのAngularマークアップが含まれているSharePointビューREST APIからコンテンツを取得しています。あなたの指令はそれをすべて機能させました。ありがとう!
Phil Nicholas、

あなたの指示をありがとう、それは私が抱えていた問題を修正しました。今度は角度コードがコンパイルされますが、何度も実行されます。3つのオブジェクトを持つng-repeatは、それぞれ3倍の同じ値になります。ここで何が問題になっていますか?
Jason

2
$sce.trustAsHtmlこのディレクティブで「コンパイル」されるHTMLを作成するために別の関数から使用している場合は、削除する必要があります。@apoplexyに感謝
Burak Tokak

36

素晴らしい回答vkammererをありがとう。私がお勧めする最適化の1つは、コンパイルが1回実行された後に監視しないことです。ウォッチ式内の$ evalは、パフォーマンスに影響を与える可能性があります。

    angular.module('vkApp')
  .directive('compile', ['$compile', function ($compile) {
      return function(scope, element, attrs) {
          var ensureCompileRunsOnce = scope.$watch(
            function(scope) {
               // watch the 'compile' expression for changes
              return scope.$eval(attrs.compile);
            },
            function(value) {
              // when the 'compile' expression changes
              // assign it into the current DOM
              element.html(value);

              // compile the new DOM and link it to the current
              // scope.
              // NOTE: we only compile .childNodes so that
              // we don't get into infinite loop compiling ourselves
              $compile(element.contents())(scope);

              // Use un-watch feature to ensure compilation happens only once.
              ensureCompileRunsOnce();
            }
        );
    };
}]);

フォークと更新されたフィドルです。


その逆も可能ですか?
Sanyam Jain

これはajaxの応答では機能しませんが、受け入れられた応答機能
foozhan

1
警告:この回答のフィドルは機能.directive()しますが、回答に投稿されたコードのコードは機能しません。
Phil Nicholas

これは私のために働いた。選択された答えは「エラー:$ rootScope:infdig Infinite $ digest Loop」をトリガーします
ガブリエルアンドレイ

明示は必要ありません$eval- attrs.compile監視される無名関数の代わりに直接使用できます。文字列式を指定しただけの場合、angularは$evalとにかくそれを呼び出します。
Dan King

28

このディレクティブangular-bind-html-compileを追加します

.directive('bindHtmlCompile', ['$compile', function ($compile) {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      scope.$watch(function () {
        return scope.$eval(attrs.bindHtmlCompile);
      }, function (value) {
        // Incase value is a TrustedValueHolderType, sometimes it
        // needs to be explicitly called into a string in order to
        // get the HTML string.
        element.html(value && value.toString());
        // If scope is provided use it, otherwise use parent scope
        var compileScope = scope;
        if (attrs.bindHtmlScope) {
          compileScope = scope.$eval(attrs.bindHtmlScope);
        }
        $compile(element.contents())(compileScope);
      });
    }
  };
}]);

次のように使用します。

<div bind-html-compile="data.content"></div>

本当に簡単です:)


1
「$ scope.loadContent = function(){return $ sce.trustAsHtml(require( 'html / main-content.html'));};」のようなものを渡す場合は注意してください。それに無限のダイジェストループを得ることができます。trustAsHtmlがなくても機能します。
Lakatos Gyula、2015

13

残念ながら、コメントするのに十分な評判がありません。

私はこれを長年にわたって働かせることができませんでした。ng-bind-htmlこのカスタムディレクティブを使用するようにコードを変更$scope.html = $sce.trustAsHtml($scope.html)しましたが、ng-bind-htmlが機能するために必要なものを削除できませんでした。これを削除するとすぐに、コンパイル機能が動作し始めました。


6

すでに$sce.trustAsHtmlここで実行されたコンテンツを扱う人にとっては、私が異なってしなければならなかったことです

function(scope, element, attrs) {
    var ensureCompileRunsOnce = scope.$watch(function(scope) {
            return $sce.parseAsHtml(attrs.compile)(scope);
        },
        function(value) {
            // when the parsed expression changes assign it into the current DOM
            element.html(value);

            // compile the new DOM and link it to the current scope.
            $compile(element.contents())(scope);

            // Use un-watch feature to ensure compilation happens only once.
            ensureCompileRunsOnce();
        });
}

link別のレイアウトを使用しているため、これはディレクティブの一部にすぎません。$sceだけでなく、サービスを注入する必要があり$compileます。


-2

私が見つけた最善の解決策!私はそれをコピーしました、そしてそれは私が必要とするのと全く同じです。ありがとう、ありがとう、ありがとう...

私が持っているディレクティブリンク機能で

app.directive('element',function($compile){
  .
  .
     var addXml = function(){
     var el = $compile('<xml-definitions definitions="definitions" />')($scope);
     $scope.renderingElement = el.html();
     }
  .
  .

ディレクティブテンプレート:

<span compile="renderingElement"></span>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.