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>
Swaff
fuente
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'])

Luke Madera
fuente
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
fuente
@ 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>
anpatel
fuente
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 .

Pier-Luc Gendreau
fuente
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>

Damax
fuente
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.

Bidhan Bhattarai
fuente
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);

Sotos
fuente
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.

Mate
fuente
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.

Henry Neo
fuente
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()

abbaf33f
fuente
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

yugi
fuente
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.

Vikash Sharma
fuente
¿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

bahri noredine
fuente
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>
Patricia Heimfarth
fuente
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>

fuente
-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.

Sagar Misal
fuente
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...

Alireza
fuente
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.

Kamlesh
fuente
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