angular ng-bind-html e la direttiva al suo interno


96

Plunker Link

Ho un elemento a cui vorrei associare html.

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

Che funzioni. Ora, insieme ad esso, ho anche una direttiva che è associata all'html associato:

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

Ma la direttiva uppercon div e anchor non viene valutata. Come lo faccio funzionare?



@Chandermani non usa esattamente la direttiva all'interno di ng-bind-html-unsafe ma usa il filtro. Ma funzionerà, ho appena creato un filtro e passato alla direttiva. Grazie!
Amitava

@SamSerious riesci a mostrare come hai fatto quello che hai fatto per i filtri?
CMCDragonkai

le soluzioni di cui sopra non gestiscono più modifiche del valore di una soluzione migliore stackoverflow.com/a/25516311/3343425
fghibellini

Risposte:


188

Anch'io stavo affrontando questo problema e dopo ore di ricerca su Internet ho letto il commento di @ Chandermani, che si è rivelato la soluzione. Devi chiamare una direttiva 'compile' con questo modello:

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

Puoi vedere un violino funzionante qui


1
Nella riga # 2, cioè. function(scope, element, attrs), dove hai preso questi tre argomenti, scope , element e attrs ?
spaffy

1
@spaffy: fanno parte della firma di Angular Framework per la linkproprietà. Verranno passati automaticamente ogni volta che linkviene chiamato dal framework Angular. Saranno sempre disponibili.
Ben

1
Molto bene. Mi hai risparmiato quelle stesse ore di ricerche. Sto estraendo il contenuto dall'API REST della visualizzazione di SharePoint, che a sua volta contiene markup angolare come ng-repeat. La tua direttiva ha fatto funzionare tutto. Grazie!
Phil Nicholas,

Grazie per la tua direttiva ha risolto i problemi che stavo avendo. Ora il codice angolare viene compilato ma troppe volte. Una ripetizione con 3 oggetti si trasforma negli stessi valori solo 3 volte ciascuno. Cosa sta succedendo qui?
Jason

2
Se hai utilizzato $sce.trustAsHtmlun'altra funzione per creare l'HTML che verrà "compilato" con questa direttiva, dovresti rimuoverlo. Grazie a @apoplexy
Burak Tokak

36

Grazie per l'ottima risposta vkammerer. Un'ottimizzazione che consiglierei è l'annullamento della visualizzazione dopo che la compilazione è stata eseguita una volta. $ Eval all'interno dell'espressione watch potrebbe avere implicazioni sulle prestazioni.

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

Ecco un violino biforcuto e aggiornato.


Posso avere il viceversa per questo?
Sanyam Jain

questo non è un lavoro in risposta di ajax ma ha accettato il lavoro di risposta
foozhan il

1
Avvertenza: il violino per questa risposta funziona, ma il .directive()codice nel codice pubblicato nella risposta no.
Phil Nicholas,

questo ha funzionato per me. la risposta scelta attiverebbe "Errore: $ rootScope: infdig Infinite $ digest Loop"
Gabriel Andrei

Non dovresti aver bisogno dell'esplicito $eval: puoi semplicemente usare attrs.compiledirettamente al posto della funzione anonima guardata. Se fornisci solo un'espressione stringa, angular la chiamerà $evalcomunque.
Dan King

28

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

Usalo in questo modo:

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

Davvero facile :)


1
Fai attenzione, se passi qualcosa del genere: "$ scope.loadContent = function () {return $ sce.trustAsHtml (require ('html / main-content.html'));};" ad esso puoi ottenere un ciclo digest infinito. Senza trustAsHtml funziona.
Lakatos Gyula

13

Purtroppo non ho abbastanza reputazione per commentare.

Non sono riuscito a farlo funzionare per anni. Ho modificato il mio ng-bind-htmlcodice per utilizzare questa direttiva personalizzata, ma non sono riuscito a rimuovere $scope.html = $sce.trustAsHtml($scope.html)quello richiesto per il funzionamento di ng-bind-html. Non appena l'ho rimosso, la funzione di compilazione ha iniziato a funzionare.


6

Per chiunque si occupi di contenuti che sono già stati esaminati, $sce.trustAsHtmlecco cosa dovevo fare in modo diverso

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

Questa è solo la linkparte della direttiva poiché sto usando un layout diverso. Dovrai iniettare anche il $sceservizio $compile.


-2

La migliore soluzione quella che ho trovato! L'ho copiato e funziona esattamente come avevo bisogno. Grazie, grazie, grazie ...

nella funzione di collegamento direttiva che ho

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

e nel modello di direttiva:

<span compile="renderingElement"></span>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.