Winkel ng-bind-html und Direktive darin

96

Plunker Link

Ich habe ein Element, an das ich HTML binden möchte.

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

Das funktioniert. Jetzt habe ich auch eine Direktive, die an das gebundene HTML gebunden ist:

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

Aber die Direktive uppermit dem Div und dem Anker wird nicht bewertet. Wie bringe ich es zum Laufen?

Amitava
quelle
3
Schauen Sie sich meine Antwort hier an stackoverflow.com/questions/17343696/…
Chandermani
@Chandermani verwendet nicht genau die Direktive in ng-bind-html-unsafe, sondern den Filter. Aber es wird reichen, ich habe gerade einen Filter erstellt und an die Direktive übergeben. Vielen Dank!
Amitava
@SamSerious Können Sie zeigen, wie Sie das getan haben, was Sie für die Filter getan haben?
CMCDragonkai
Die oben genannten Lösungen behandeln nicht mehrere Änderungen des Werts eine bessere Lösung stackoverflow.com/a/25516311/3343425
fghibellini

Antworten:

188

Ich war auch mit diesem Problem konfrontiert und nach stundenlangem Durchsuchen des Internets las ich @ Chandermanis Kommentar, der sich als Lösung erwies. Sie müssen eine 'compile'-Direktive mit diesem Muster aufrufen:

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

Sie können hier eine funktionierende Geige davon sehen

vkammerer
quelle
1
In Zeile 2, dh. function(scope, element, attrs), woher haben Sie diese drei Argumente, Umfang , Element und Attribute ?
Spaffy
1
@spaffy - Sie sind Teil der Signatur des Angular-Frameworks für die linkEigenschaft. Sie werden jedes Mal automatisch übergeben, wenn linksie vom Angular-Framework aufgerufen werden. Sie werden immer verfügbar sein.
Ben
1
Gut gemacht. Du hast mir die gleichen Stunden der Suche erspart. Ich rufe Inhalte aus der REST-API der SharePoint-Ansicht ab, die selbst Angular-Markups wie ng-repeat enthält. Ihre Richtlinie hat alles zum Laufen gebracht. Vielen Dank!
Phil Nicholas
Vielen Dank für Ihre Anweisung, die die Probleme behoben hat, die ich hatte. Jetzt wird der Winkelcode aber zu oft kompiliert. Eine ng-Wiederholung mit 3 Objekten führt zu jeweils nur 3x gleichen Werten. Was läuft hier falsch?
Jason
2
Wenn Sie eine $sce.trustAsHtmlandere Funktion zum Erstellen des HTML-Codes verwendet haben, der mit dieser Anweisung "kompiliert" wird, sollten Sie ihn entfernen. Vielen Dank an @apoplexy
Burak Tokak
36

Danke für die tolle Antwort vkammerer. Eine Optimierung, die ich empfehlen würde, ist das Aufheben der Wiedergabe, nachdem die Kompilierung einmal ausgeführt wurde. Das $ eval innerhalb des Watch-Ausdrucks kann Auswirkungen auf die Leistung haben.

    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();
            }
        );
    };
}]);

Hier ist eine gegabelte und aktualisierte Geige.

user3075469
quelle
Kann ich das Gegenteil dafür haben?
Sanyam Jain
Dies ist keine Arbeit als Antwort von Ajax, sondern akzeptierte Antwort Arbeit
Foozhan
1
Warnung: Die Geige für diese Antwort funktioniert, der .directive()Code in dem in der Antwort angegebenen Code jedoch nicht.
Phil Nicholas
Dieser hat für mich gearbeitet. Die gewählte Antwort würde "Fehler: $ rootScope: infdig Infinite $ Digest Loop" auslösen
Gabriel Andrei
Sie sollten das Explict nicht benötigen $eval- Sie können es einfach attrs.compiledirekt anstelle der beobachteten anonymen Funktion verwenden. Wenn Sie nur einen Zeichenfolgenausdruck angeben, wird Angle $evalihn trotzdem aufrufen .
Dan King
28

Fügen Sie diese Direktive angle-bind-html-compile hinzu

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

Verwenden Sie es so:

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

Wirklich einfach :)

Joël
quelle
1
Seien Sie vorsichtig, wenn Sie Folgendes übergeben: "$ scope.loadContent = function () {return $ sce.trustAsHtml (require ('html / main-content.html'));};" dazu kann man eine unendliche verdauungsschleife bekommen. Ohne trustAsHtml funktioniert es.
Lakatos Gyula
13

Leider habe ich nicht genug Ruf, um einen Kommentar abzugeben.

Ich konnte das ewig nicht zum Laufen bringen. Ich habe meinen ng-bind-htmlCode geändert , um diese benutzerdefinierte Direktive zu verwenden, aber ich konnte den Code nicht entfernen, der $scope.html = $sce.trustAsHtml($scope.html)erforderlich war, damit ng-bind-html funktioniert. Sobald ich dies entfernt hatte, begann die Kompilierungsfunktion zu funktionieren.

Apoplexie
quelle
6

Für jeden, der sich mit Inhalten befasst, die hier bereits durchlaufen $sce.trustAsHtmlwurden, war das, was ich anders machen musste

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

Dies ist nur der linkTeil der Direktive, da ich ein anderes Layout verwende. Sie müssen den $sceService sowie injizieren $compile.

MStrutt
quelle
-2

Beste Lösung, was ich gefunden habe! Ich habe es kopiert und es funktioniert genau so, wie ich es brauchte. Danke, danke, danke ...

in richtlinie link funktion habe ich

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

und in Direktivenvorlage:

<span compile="renderingElement"></span>
yustme
quelle