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?


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


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.


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 :)


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.


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.


-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>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.