kątowy ng-bind-html i dyrektywę w nim

96

Plunker Link

Mam element, z którym chciałbym powiązać HTML.

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

To działa. Teraz razem z nim mam również dyrektywę, która jest związana z powiązanym html:

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

Ale dyrektywa upperz elementami div i anchor nie jest oceniana. Jak to działa?

Amitava
źródło
3
Spójrz na moją odpowiedź tutaj stackoverflow.com/questions/17343696/ ...
Chandermani
@Chandermani nie do końca używa dyrektywy wewnątrz ng-bind-html-unsafe, ale używa filtra. Ale to wystarczy, właśnie utworzyłem filtr i przekazałem do dyrektywy. Dzięki!
Amitava,
@SamSerious, czy jesteś w stanie pokazać, jak zrobiłeś to, co zrobiłeś dla filtrów?
CMCDragonkai
powyższe rozwiązania nie obsługują wielu zmian wartości lepsze rozwiązanie stackoverflow.com/a/25516311/3343425
fghibellini

Odpowiedzi:

188

Ja też borykałem się z tym problemem i po godzinach przeszukiwania internetu przeczytałem komentarz @ Chandermani, który okazał się rozwiązaniem. Musisz wywołać dyrektywę 'compile' z tym wzorcem:

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

Możesz zobaczyć tutaj działające skrzypce

vkammerer
źródło
1
W linii nr 2 tj. function(scope, element, attrs), skąd masz te trzy argumenty, zakres , element i atrybuty ?
spaffy
1
@spaffy - są częścią podpisu platformy Angular dla linkwłaściwości. Będą przekazywane automatycznie za każdym razem, gdy linkzostaną wywołane przez platformę Angular. Zawsze będą dostępne.
Ben
1
Dobra robota. Zaoszczędziłeś mi tych samych godzin poszukiwań. Pobieram zawartość z interfejsu API REST widoku SharePoint, który sam zawiera znaczniki Angular, takie jak ng-repeat. Twoja dyrektywa sprawiła, że ​​wszystko zadziałało. Dzięki!
Phil Nicholas
Dziękuję za twoją dyrektywę, która rozwiązała problemy, które miałem. Teraz kod kątowy jest kompilowany, ale zbyt wiele razy. Powtórzenie ng z 3 obiektami zamienia się w te same wartości tylko 3x każdy. Co tu się dzieje?
Jason,
2
Jeśli korzystałeś $sce.trustAsHtmlz innej funkcji do tworzenia kodu HTML, który zostanie „skompilowany” z tą dyrektywą, powinieneś ją usunąć. Dzięki @apoplexy
Burak Tokak
36

Dzięki za świetną odpowiedź vkammerer. Jedną z optymalizacji, którą poleciłbym, jest cofnięcie oglądania po jednokrotnym uruchomieniu kompilacji. Znak $ eval w wyrażeniu obserwującym może mieć wpływ na wydajność.

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

Oto rozwidlone i zaktualizowane skrzypce.

user3075469
źródło
Czy mogę mieć na to odwrotnie?
Sanyam Jain
to nie działa w odpowiedzi na
Ajax,
1
Ostrzeżenie: Skrzypce dla tej odpowiedzi działają, ale .directive()kod w kodzie zamieszczonym w odpowiedzi nie.
Phil Nicholas
ten pracował dla mnie. wybrana odpowiedź wywoła „Error: $ rootScope: infdig Infinite $ Digest Loop”
Gabriel Andrei
Nie powinieneś potrzebować wyjaśnienia $eval- możesz po prostu użyć attrs.compilebezpośrednio zamiast obserwowanej funkcji anonimowej. Jeśli podasz tylko wyrażenie tekstowe, angular i $evaltak je wywoła .
Dan King
28

Dodaj tę dyrektywę 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);
      });
    }
  };
}]);

Użyj tego w ten sposób:

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

Naprawdę proste :)

Joël
źródło
1
Uważaj, jeśli przekazujesz coś takiego: "$ scope.loadContent = function () {return $ sce.trustAsHtml (require ('html / main-content.html'));};" do niego możesz uzyskać nieskończoną pętlę trawienia. Bez trustAsHtml działa.
Lakatos Gyula
13

Niestety nie mam wystarczającej reputacji, aby komentować.

Nie mogłem zmusić tego do pracy przez wieki. Zmodyfikowałem swój ng-bind-htmlkod, aby używać tej niestandardowej dyrektywy, ale nie udało mi się usunąć tego, $scope.html = $sce.trustAsHtml($scope.html)co było wymagane do działania ng-bind-html. Jak tylko to usunąłem, funkcja kompilacji zaczęła działać.

apopleksja
źródło
6

Dla każdego, kto ma do czynienia z treściami, które zostały już $sce.trustAsHtmltutaj omówione, muszę zrobić inaczej

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

To tylko linkczęść dyrektywy, ponieważ używam innego układu. Będziesz musiał również wstrzyknąć $sceusługę $compile.

MStrutt
źródło
-2

Najlepsze rozwiązanie, jakie znalazłem! Skopiowałem to i działa dokładnie tak, jak potrzebowałem. Dzięki, dzięki, dzięki ...

w funkcji linku dyrektywy mam

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

aw szablonie dyrektywy:

<span compile="renderingElement"></span>
yustme
źródło