Inserte HTML en la vista desde el controlador AngularJS


800

¿Es posible crear un fragmento HTML en un controlador AngularJS y mostrar este HTML en la vista?

Esto proviene de un requisito para convertir un blob JSON inconsistente en una lista anidada de id: valuepares. Por lo tanto, el HTML se crea en el controlador y ahora estoy buscando mostrarlo.

He creado una propiedad de modelo, pero no puedo representarla en la vista sin que solo imprima el HTML .


Actualizar

Parece que el problema surge de la representación angular del HTML creado como una cadena entre comillas. Intentará encontrar una forma de evitar esto.

Controlador de ejemplo:

var SomeController = function () {

    this.customHtml = '<ul><li>render me please</li></ul>';
}

Vista de ejemplo:

<div ng:bind="customHtml"></div>

Da :

<div>
    "<ul><li>render me please</li></ul>"
</div>

1
También vea esta pregunta , preguntando si es posible obtener scripts en HTML insertado para ejecutar.
enigment

¿Es posible tener múltiples objetos unidos al mismo ng-bind? como `` `ng-bind =" site.address_1 site.address_2 site.zip "
fauverism

si tiene muchas cosas en su página, deberá modificar la línea 15046 de angular.js (locura) de function htmlSanitizer(html) {.... Angular dev's decidió que deberías poder encontrar cualquier enlace html revisando lentamente todos los elementos ocultos de tus páginas uno por uno para encontrar esa ÚNICA pieza de html que falta. !!! muy enojado con tal suposición !!!
user3338098

Lo sentimos, la respuesta elegida por Luke puede no ser la respuesta correcta. La respuesta correcta se puede encontrar en otra pregunta aquí . Básicamente, "ng-bind-html-unfefe solo representa el contenido como HTML. No vincula el alcance angular al DOM resultante. Debe usar el servicio de compilación $ para ese propósito".
gm2008

ng-bind elimina todo el html interno. que no es cómo funcionaría el filtro, está bien cuando el filtro es el único valor
Muhammad Umer

Respuestas:


1120

Para Angular 1.x, use ng-bind-htmlen el HTML:

<div ng-bind-html="thisCanBeusedInsideNgBindHtml"></div>

En este punto, obtendría un attempting to use an unsafe value in a safe contexterror, por lo que debe usar ngSanitize o $ sce para resolverlo.

$ sce

Use $sce.trustAsHtml()en el controlador para convertir la cadena html.

 $scope.thisCanBeusedInsideNgBindHtml = $sce.trustAsHtml(someHtmlVar);

ngSanitize

Hay 2 pasos:

  1. incluya el recurso angular-sanitize.min.js, es decir:
    <script src="lib/angular/angular-sanitize.min.js"></script>

  2. En un archivo js (controlador o generalmente app.js), incluya ngSanitize, es decir:
    angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ngSanitize'])


30
En Angular 1.2, ng-bind-html-unsafese eliminó y las dos directivas se combinaron. Ver: github.com/angular/angular.js/blob/master/…
Sasha Chedygov

6060
Sin usar ngSanitize, se puede hacer ahora usando $sce. Inyecte en el controlador y pase el html a través de él. $scope.thisCanBeusedInsideNgBindHtml = $sce.trustAsHtml(someHtmlVar);De lo contrario, seguía recibiendoattempting to use an unsafe value in a safe context
Matsemann

3
Necesitamos un poco de limpieza aquí, que es la forma correcta en que nada parece estar funcionando para mí.
aterrizó el

99
stackoverflow.com/questions/21829275/… <- funcionó para mí :) ninguna de las opciones en las respuestas aquí funcionó desafortunadamente
anpatel

77
Solo para que la gente no se desanime, la última actualización de esta respuesta, junto con el requisito ngSanitize en la parte inferior de la respuesta, de hecho funciona.
Ben Cull

312

También puede crear un filtro así:

var app = angular.module("demoApp", ['ngResource']);

app.filter("trust", ['$sce', function($sce) {
  return function(htmlCode){
    return $sce.trustAsHtml(htmlCode);
  }
}]);

Entonces en la vista

<div ng-bind-html="trusted_html_variable | trust"></div>

Nota : Este filtro confía en todos y cada uno de los html que se le pasan y podría presentar una vulnerabilidad XSS si se le pasan variables con la entrada del usuario.


@ Katie Astrauskas, ¡gracias por la respuesta! Muy limpio. Por cierto, la ngResourcedependencia no es necesaria.
Athlan

28
Solo use esto cuando confíe completamente en el HTML. Esto no desinfecta el HTML de ninguna manera, sino que solo permite que Angular lo inyecte en la página. HTML malicioso puede provocar ataques XSS.
jan.vdbergh

Si el rendimiento es importante, debe evitar el uso de filtros. Un filtro activará dos resúmenes cada vez.
Tantelope

14
¿Por qué se llama el filtro sanitize? Esto es tan engañoso ya que en realidad no desinfecta nada. En cambio, debería llamarse trust, trustSafeo algo similar.
Denis Pshenov

1
Maravillosa respuesta. rawHtmles mi nombre para el filtro en lugar de sanitize.
Wumms

119

Angular JS muestra HTML dentro de la etiqueta

La solución proporcionada en el enlace anterior funcionó para mí, ninguna de las opciones en este hilo lo hizo. Para cualquiera que busque lo mismo con AngularJS versión 1.2.9

Aquí hay una copia:

Ok, encontré una solución para esto:

JS:

$scope.renderHtml = function(html_code)
{
    return $sce.trustAsHtml(html_code);
};

HTML:

<p ng-bind-html="renderHtml(value.button)"></p>

EDITAR:

Aquí está la configuración:

Archivo JS:

angular.module('MyModule').controller('MyController', ['$scope', '$http', '$sce',
    function ($scope, $http, $sce) {
        $scope.renderHtml = function (htmlCode) {
            return $sce.trustAsHtml(htmlCode);
        };

        $scope.body = '<div style="width:200px; height:200px; border:1px solid blue;"></div>'; 

    }]);

Archivo HTML:

<div ng-controller="MyController">
    <div ng-bind-html="renderHtml(body)"></div>
</div>

77
Tenga en cuenta que debe estar absolutamente seguro de que se puede confiar en el html. De lo contrario, la puerta está abierta para ataques XSS.
jan.vdbergh

Esta solución, que utiliza una función para representar el HTML, es la única que funcionó para mí.
MarceloBarbosa

¿Para qué sirve el '$ http'?
Soldeplata Saketos

@SoldeplataSaketos nada en particular, creo que lo estaba intentando localmente en ese momento y terminé copiando la dependencia.
anpatel

La misma respuesta actualizada aquí. stackoverflow.com/questions/21829275/…
Surya R Praveen

65

Afortunadamente, no necesita filtros sofisticados o métodos inseguros para evitar ese mensaje de error. Esta es la implementación completa para generar correctamente el marcado HTML en una vista de la manera prevista y segura.

El módulo de desinfección debe incluirse después de Angular:

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-sanitize.js"></script>

Luego, el módulo debe cargarse:

angular.module('app', [
  'ngSanitize'
]);

Esto le permitirá incluir marcas en una cadena desde un controlador, directiva, etc.

scope.message = "<strong>42</strong> is the <em>answer</em>.";

Finalmente, en una plantilla, se debe generar así:

<p ng-bind-html="message"></p>

Lo que producirá el resultado esperado: 42 es la respuesta .


1
Pruebe algunos html como <div><label>Why My Input Element Missing</label><input /></div>... Si le sorprende, actualice su respuesta por favor ... Porque probé las 10 + soluciones de voto ... Su solución no funcionó para mí para ver mis etiquetas de entrada ... bien de lo contrario ... Tuve uso$sce.trustAsHtml(html)
Sami

Esta solución funciona, ¿quieres publicar un jsfiddle o plunkr?
Pier-Luc Gendreau

Esta realmente debería ser la respuesta si se usa el último angular
Sandeep

61

Lo he intentado hoy, la única forma en que encontré fue esto

<div ng-bind-html-unsafe="expression"></div>


66
Esta solución debe usarse solo si la fuente es confiable para evitar ataques de secuencias de comandos entre sitios.
Bertrand

3
A partir de Angular 1.0.2, esto funciona para mí, sin necesidad de otros archivos o conexiones.
enigment el

1
Usando Angular 1.0.8 y esto funcionó para mí. Sin embargo, preste atención a la advertencia de @ Bertrand, asegúrese de confiar en la fuente.
Jack Slingerland el

12
Para futuras referencias, ng-bind-html-unsafe se eliminó en la versión 1.2. Ahora necesita el módulo ngSanitize y para enlazar html inseguro, debe usar el método $ sce.trustAsHtml.
Lucas Lazaro

53

ng-bind-html-unsafe Ya no funciona.

Este es el camino más corto:

Crea un filtro:

myApp.filter('unsafe', function($sce) { return $sce.trustAsHtml; });

Y en tu opinión:

<div ng-bind-html="customHtml | unsafe"></div>

PD: este método no requiere que incluyas el ngSanitizemódulo.


3
Esta es la mejor solución que he visto aquí para Angular 1.2. La solución que se usa $sceen la respuesta aceptada no funcionó para mí y no quería incluir una dependencia adicional para algo tan trivial.
Daniel Bonnell

La solución de Bidhan Bhattarai funcionó para mí. Angular 1.6.1
mediaguru

25

en html

<div ng-controller="myAppController as myCtrl">

<div ng-bind-html-unsafe="myCtrl.comment.msg"></div>

O

<div ng-bind-html="myCtrl.comment.msg"></div

en el controlador

mySceApp.controller("myAppController", function myAppController( $sce) {

this.myCtrl.comment.msg = $sce.trustAsHtml(html);

trabaja también con $scope.comment.msg = $sce.trustAsHtml(html);


1
$sceestá ordenado, pero ¿no podría un usuario simplemente agregar un punto de interrupción aquí y restaurar cualquier código malicioso para this.myCtrl.comment.msgusar un depurador?
BradGreens

Por otra parte, BradGreens, ¿podrías hacer lo mismo con ng-bind-html-inseguro también?
CodeOverRide

44
Si alguien quiere hackear su propio navegador, puede hacerlo, a quién le importa. No afectará a otros usuarios. @BradGreens ¿Esa es la pregunta?
Chris Stephens

@ChrisStephens tienes razón. Supongo que eso responde a mi pregunta, pero mi opinión es que estas características están más cerca de la seguridad percibida que la seguridad real. ¿Quizás protege contra algún tipo de ataques automáticos? Nunca he entendido claramente por qué hacer esto realmente ayuda a la aplicación. Mi aplicación tiene que agregar un filtro a CADA instancia de renderizar wysiwyg HTML porque podría tener CSS en línea, que se ng-bind-htmlelimina.
BradGreens

1
Bueno, estas características ayudan a reducir los errores de codificación segura. En particular, el problema con el marcado / inyección de código. Por defecto, todos los datos enlazados están codificados para su visualización. Básicamente, si desea generar un marcado, esto lo obliga a pensar en lo que está tratando de hacer. Sin estas características, puede hacer mucho solo con la seguridad del lado del servidor, pero para separar las preocupaciones, la aplicación cliente debería encargarse de manejar los datos correctamente para su visualización.
Chris Stephens

9

Descubrí que usar ng-sanitize no me permitía agregar ng-click en el html.

Para resolver esto, agregué una directiva. Me gusta esto:

app.directive('htmldiv', function($compile, $parse) {
return {
  restrict: 'E',
  link: function(scope, element, attr) {
    scope.$watch(attr.content, function() {
      element.html($parse(attr.content)(scope));
      $compile(element.contents())(scope);
    }, true);
  }
}
});

Y este es el HTML:

<htmldiv content="theContent"></htmldiv>

Buena suerte.


6

Acabo de hacer esto usando ngBindHtml siguiendo los documentos angulares (v1.4) ,

<div ng-bind-html="expression"></div> 
and expression can be "<ul><li>render me please</li></ul>"

Asegúrese de incluir ngSanitize en las dependencias del módulo. Entonces debería funcionar bien.


4

Otra solución, muy similar a la de blrbr, excepto que usa un atributo de ámbito es:

angular.module('app')
.directive('renderHtml', ['$compile', function ($compile) {
    return {
      restrict: 'E',
      scope: {
        html: '='
      },
      link: function postLink(scope, element, attrs) {

          function appendHtml() {
              if(scope.html) {
                  var newElement = angular.element(scope.html);
                  $compile(newElement)(scope);
                  element.append(newElement);
              }
          }

          scope.$watch(function() { return scope.html }, appendHtml);
      }
    };
  }]);

Y entonces

<render-html html="htmlAsString"></render-html>

Tenga en cuenta que puede reemplazar element.append()conelement.replaceWith()


3

Hay una solución más para este problema mediante la creación de nuevos atributos o directivas en angular.

especificaciones del producto.html

 <h4>Specs</h4>
        <ul class="list-unstyled">
          <li>
            <strong>Shine</strong>
            : {{product.shine}}</li>
          <li>
            <strong>Faces</strong>
            : {{product.faces}}</li>
          <li>
            <strong>Rarity</strong>
            : {{product.rarity}}</li>
          <li>
            <strong>Color</strong>
            : {{product.color}}</li>
        </ul>

app.js

 (function() {
var app = angular.module('gemStore', []);    
app.directive("     <div ng-show="tab.isSet(2)" product-specs>", function() {
return {
  restrict: 'E',
  templateUrl: "product-specs.html"
};
});

index.html

 <div>
 <product-specs>  </product-specs>//it will load product-specs.html file here.
 </div>

o

<div  product-specs>//it will add product-specs.html file 

o

<div ng-include="product-description.html"></div>

https://docs.angularjs.org/guide/directive


3

También puedes usar ng-include .

<div class="col-sm-9 TabContent_container" ng-include="template/custom.html">
</div>

puede usar "ng-show" para mostrar ocultar los datos de esta plantilla.


¿Estás seguro de que esto es todo lo que necesitas hacer para usar ng-include?
fauverismo

Sí, lo he probado. y si está usando una plantilla, úsela de la siguiente manera: <script type = "text / ng-template" id = "custom.html">
Vikash Sharma

2

aquí está la solución hacer un filtro como este

.filter('trusted',
   function($sce) {
     return function(ss) {
       return $sce.trustAsHtml(ss)
     };
   }
)

y aplique esto como filtro al ng-bind-html como

<div ng-bind-html="code | trusted">

y gracias a Ruben Decrop


1

Utilizar

<div ng-bind-html="customHtml"></div>

y

angular.module('MyApp', ['ngSanitize']);

Para eso, debe incluir angular-sanitize.js, por ejemplo, en su archivo html con

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-sanitize.js"></script>

0

Aquí hay una bind-as-htmldirectiva simple (e insegura) , sin la necesidad de ngSanitize:

myModule.directive('bindAsHtml', function () {
    return {
        link: function (scope, element, attributes) {
            element.html(scope.$eval(attributes.bindAsHtml));
        }
    };
});

Tenga en cuenta que esto se abrirá para problemas de seguridad, si vincula contenido no confiable.

Use así:

<div bind-as-html="someHtmlInScope"></div>

-1

Ejemplo de trabajo con tubería para mostrar html en plantilla con Angular 4.

1.Crate Pipe escape-html.pipe.ts

``

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({name : 'keepHtml', pure : false})
export class EscapeHtmlPipe implements PipeTransform{
 constructor(private sanitizer : DomSanitizer){
 }
 transform(content){
  return this.sanitizer.bypassSecurityTrustHtml(content);
 }
}

`2. Registre la tubería en app.module.ts

 import {EscapeHtmlPipe} from './components/pipes/escape-html.pipe';
    declarations: [...,EscapeHtmlPipe]
  1. Úselo en su plantilla

        <div class="demoPipe"  [innerHtml]="getDivHtml(obj.header) | keepHtml">

  2. getDivHtml() { //can return html as per requirement}

    Agregue la implementación adecuada para getDivHtml en el archivo component.ts asociado.


1
Creo que está trabajando con AngularJS, no con la versión más nueva.
Lepra

-1

Solo uso simple [innerHTML], como a continuación:

<div [innerHTML]="htmlString"></div>

Antes de que necesitaras usar ng-bind-html...


Esto solo está disponible dentro de Angular (Angular versión 2+), no AngularJS (Angular versión 1).
ste2425

-1

En Angular 7 + ionic 4, los contenidos HTML se pueden mostrar usando "[innerHTML]":

<div [innerHTML]="htmlContent"></div>

Espero que esto también te ayude. Gracias.


amablemente dígame qué hay de malo en este código, lo que hace que se rechace esta publicación. He probado este código en mi aplicación 2. Funciona. Por favor comparte tu experiencia. Muchas gracias.
Kamlesh

1
AngularJS es igual a Angular 1.x. Angular 7 es un marco completamente diferente
Aw Snap
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.