web-dev-qa-db-fra.com

Echappement &> caractères dans ng-bind dans AngularJs

J'ai un cas d'utilisation, où nous pouvons avoir des caractères '&' et '>' dans une chaîne. par exemple. Johnson & Johnson, value > 3. Ainsi, alors que la réponse du serveur est codée, la valeur devient alors 'value & ampgt; 3 '.

ng-bind ne prend pas en charge les éléments suivants:

value > 3 sera rendu pour ngBind, alors que le navigateur affichera le même contenu que value > 3.

http://jsfiddle.net/HKahG/2/

Ng:bind <div ng-bind="model"></div> 
Ng:bind-html <div ng-bind-html="model"></div>
<div> From Div: value &gt; </div>

Pourquoi ce comportement de navigateur par défaut n'est-il pas présent dans ng-bind?. Je ne veux pas utiliser ng-bind-html (a des problèmes avec la valeur < et ce n'est pas un code HTML) ou ng-bind-unsafe-html.

Mon application possède des champs clé-valeur dynamiques qui seront affichés dans différentes parties de l'application. Donc, il faudra plus de temps pour utiliser une directive ou un décorateur distinct pour afficher tous les champs de chaîne que pour utiliser ngBind.

Des questions:

1) Existe-t-il un autre moyen de faire de même sans utiliser de directive supplémentaire ou est-ce la bonne façon de traiter des données codées?

2) Puis-je remplacer le comportement de ng-bind ou le décorer par défaut?

17
DarkKnight

EDIT: allez directement au bas de la réponse pour obtenir la meilleure version; la réponse est en ordre chronologique; J'ai obtenu le code optimal après quelques itérations, à la fin. Je vous remercie.

  • Puis-je remplacer le comportement de ng-bind ou le décorer par défaut?

Oui. J'ai réalisé une implémentation très simple qui permet à ng-bind de se comporter comme vous le souhaitez. Eh bien ... Je ne sais pas si c'est exactement ce que vous voulez, mais au moins, il fait ce que je vous ai compris.

Violon de travail: http://jsfiddle.net/93QQM/

Et voici le code:

module.directive('ngBind', function() {
    return {
        compile: function(tElement, tAttrs) {
            tAttrs.ngBind = 'myBind(' + tAttrs.ngBind + ')';
            return { 
                pre: function(scope) {
                    scope.myBind = function(text) {
                        return angular.element('<div>' + text + '</div>').text();
                    }
                }
            };
        }
    }
});

Ce n'est pas exactement une "directive additionnelle" - c'est le moyen de "remplacer le comportement de ng-bind". Il n’ajoute pas de nouvelle directive, il étend simplement le comportement de la directive ngBind existante.

À la fonction compile, nous modifions la valeur de l'attribut ng-bind en l'enveloppant dans un appel de fonction. Avec cela, nous avons accès à la valeur du modèle d'origine et la possibilité de la renvoyer modifiée.

Nous rendons la fonction disponible via la portée lors de la phase de pré-liaison, car si nous le faisons lors de la phase de post-liaison, la fonction sera disponible uniquement après la directive ngBind d'origine a récupéré la valeur de l'attribut ( qui sera une chaîne vide, car la fonction ne sera pas trouvée).

La fonction myBind est simple et intelligente: elle crée un élément et le texte est utilisé - inchangé - en tant que corps d’élément, mais il est immédiatement récupéré via la fonction text - qui renvoie le contenu de la même manière que "le navigateur le rend".

De cette façon, vous pouvez utiliser ngBind comme d'habitude, comme <div ng-bind="model.content" />, mais modifier ce comportement.


Version améliorée

Au lieu d'attacher la fonction myBind à chaque portée où ngBind est appliqué, à chaque phase de pré-liaison, nous ne pouvons l'attacher qu'une seule fois au $rootScope, le rendant immédiatement disponible pour toutes les étendues.

Nouveau violon de travail: http://jsfiddle.net/EUqP9/

Nouveau code:

module.directive('ngBind', ['$rootScope', function($rootScope) {
    $rootScope.myBind = function(text) {
        return angular.element('<div>' + text + '</div>').text();
    };
    return {
        compile: function(tElement, tAttrs) {
            tAttrs.ngBind = 'myBind(' + tAttrs.ngBind + ')';
        }
    };
}]);

Beaucoup plus propre que la version précédente! Bien sûr, vous pouvez remplacer le nom de la fonction myBind par tout autre nom de votre choix. Le "coût" de la fonctionnalité est la suivante: ajoutez cette fonction simple à la portée racine: c'est à vous de décider si elle en vaut la peine.


Encore une autre version

Influencé par la réponse de Chemiv ... pourquoi ne pas supprimer la fonction de n'importe quelle portée et en faire un filtre? Cela fonctionne aussi.

Encore un autre nouveau violon en marche: http://jsfiddle.net/hQJaZ/

Et le nouveau code:

module.filter('decode', function() {
    return function(text) {
        return angular.element('<div>' + text + '</div>').text();
    };
}).directive('ngBind', function() {
    return {
        compile: function(tElement, tAttrs) {
            tAttrs.ngBind += '|decode';
        }
    };
});

Vous avez maintenant trois options à choisir dans le menu.

13
J. Bruni

Ce est HTML:

&gt;

Il ne peut pas avoir de balises HTML, mais c'est quand même du HTML. Si vous souhaitez utiliser ng-bind, votre serveur doit renvoyer du texte non codé. Ie, > au lieu de &gt;.

Utilisez ng-bind-html ou modifiez votre serveur pour renvoyer un texte brut sans le coder au préalable en HTML.

Edit: Démo rapide illustrant l'utilisation de &gt; et > en JavaScript:

div1.innerHTML = "&gt;";  // write HTML
div2.textContent = ">";   // write plain text
console.log(div1.innerHTML === div2.innerHTML);
console.log(div1.textContent === div2.textContent);

http://jsfiddle.net/XhEcV/

12
gilly3

ng-bind utilise la méthode .text () pour remplacer le texte. Bien que votre code contienne &gt; qui est un balisage HTML, il n'est pas correctement rendu par ng-bind. Vous devez utiliser ng-bind-html à cet endroit, car vous entrez du contenu HTML. Sinon, vous pouvez remplacer> par regex en '>'.

ex: - model = model.replace(/&gt;/g, '>');

Mais dans ce cas, vous devez remplacer tous les balises HTML, ce qui n'est pas nécessaire, car ng-bind-html fonctionne déjà très bien dans votre cas.

6
Shreyance Jain

Oui, décorons-le avec un filtre:

.filter("decode",function(){
    return function(str){         
      var el = document.createElement("div");
      el.innerHTML = str;
      str =   el.textContent || el.innerText;
      return str;        
    }
});

Et utilisez-le comme: <div ng-bind="model|decode"></div>

Exemple de travail: http://jsfiddle.net/HKahG/5/

Inspiré par cette réponse: https://stackoverflow.com/a/784698/1206613

5
Cherniv

Je me souviens d'une directive appelée ngBindHtmlUnsafe disponible pour de tels cas d'utilisation.

http://code.angularjs.org/1.0.8/docs/api/ng.directive:ngBindHtmlUnsafe

S'il vous plaît se référer à cela. Je ne sais pas si cela est disponible dans les dernières versions instables . C'est un lien vers la dernière version stable disponible.

1
Arshabh Agarwal

Pourquoi ne pas simplement utiliser $ sce.trustAsHtml?

0
Bob Barker