filtro de nueva línea angularjs sin otro html

86

Estoy tratando de convertir caracteres de nueva línea ( \n) a html br.
Según esta discusión en el Grupo de Google , esto es lo que tengo:

myApp.filter('newlines', function () {
    return function(text) {
        return text.replace(/\n/g, '<br/>');
    }
});

La discusión allí también aconseja utilizar lo siguiente en la vista:

{{ dataFromModel | newline | html }}

Esto parece estar usando el htmlfiltro antiguo , mientras que ahora se supone que debemos usar el ng-bind-htmlatributo.


Independientemente, esto plantea un problema: no quiero que ningún HTML de la cadena original ( dataFromModel) se represente como HTML; solo los br's.

Por ejemplo, dada la siguiente cadena:

Mientras que 7> 5
todavía no quiero HTML y otras cosas aquí ...

Me gustaría que saliera:

While 7 &gt; 5<br>I still don't want html &amp; stuff in here...

¿Hay alguna forma de lograr esto?

MegaHit
fuente

Respuestas:

279

Tal vez puedas lograr esto solo con html, ¿de alguna <preformated text>manera? Evitará utilizar filtros o realizar cualquier tipo de procesamiento.

Todo lo que tienes que hacer es mostrar el texto dentro de un elemento que tiene este CSS:

<p style="white-space: pre;">{{ MyMultiLineText}}</p>

Esto analizará y mostrará \ n como nuevas líneas. Funciona muy bien para mi.

Aquí, un ejemplo de jsFiddle .

Devin Spikowski
fuente
79
pre-line, fue una mejor opción para mí.
Pepijn
7
+1, esta es, con mucho, la solución más simple y parece adecuada para muchas necesidades. De hecho, pre-linees probablemente mejor en general, ya que las filas largas se ajustarán (como lo haría con cualquier <br>solución basada).
tuomassalo
13
style = "espacio en blanco: pre-línea;" es una mejor opción para usar dentro de <div>, en mi opinión
Dmitri Algazin
7
pre-wrapparece ser lo que la mayoría de la gente quiere (no pre-line): "El navegador conserva los espacios
qwertzguy
2
Descubrí que necesitaba usar ng-bind = "MyMultiLineText" en <p> para evitar que Chrome agregue líneas adicionales delante de mi texto
Scott Warren
33

En lugar de jugar con nuevas directivas, decidí usar solo 2 filtros:

App.filter('newlines', function () {
    return function(text) {
        return text.replace(/\n/g, '<br/>');
    }
})
.filter('noHTML', function () {
    return function(text) {
        return text
                .replace(/&/g, '&amp;')
                .replace(/>/g, '&gt;')
                .replace(/</g, '&lt;');
    }
});

Luego, en mi opinión, canalizo uno en el otro:

<span ng-bind-html-unsafe="dataFromModel | noHTML | newlines"></span>
MegaHit
fuente
Su expresión regular para nuevas líneas no funcionará. Necesitas: text.replace(/\\n/g, '<br />')o incluso mejortext.replace(/(\\r)?\\n/g, '<br />')
Bartłomiej Zalewski
2
@BarthZalewski: solo necesita `\` al compilar una expresión regular a partir de una cadena. Cuando usa un literal de expresión regular, no tiene que escapar de las barras diagonales.
MegaHit
2
Este código ya no funciona porque ng-bind-html-unsafe está obsoleto.
Abhi
1
Ahora puede omitir el filtro noHtml si lo desea y simplemente agregar el filtro newLines a ng-bind-html. ngSanitize se encargará del resto.
Dave Merwin
26

Una forma más sencilla de hacer esto es hacer un filtro que divida el texto en cada uno \nen una lista, y luego usar `ng-repeat.

El filtro:

App.filter('newlines', function() {
  return function(text) {
    return text.split(/\n/g);
  };
});

y en el html:

<span ng-repeat="line in (text | newlines) track by $index">
    <p> {{line}}</p>
    <br>
</span>
JJW5432
fuente
4
Me gusta esta solución, pero iría con HTML más simple:<p ng-repeat="line in (line.message | newlines)">{{line}}</p>
Thomas Fankhauser
2
Buena respuesta, pero un mejor uso track byen el caso de las líneas duplicadas, lo que plantearía un error: line in (text | newlines) track by $index.
JellicleCat
11

Si no desea destruir el diseño con cadenas infinitas, use pre-line:

<p style="white-space: pre-line;">{{ MyMultiLineText}}</p>
Sebastián Viereck
fuente
6

No sé si Angular tiene un servicio para eliminar html, pero parece que necesita eliminar html antes de pasar su newlinesfiltro personalizado. La forma en que lo haría es a través de una no-htmldirectiva personalizada , a la que se le pasaría una propiedad de alcance y el nombre de un filtro para aplicar después de eliminar elhtml

<div no-html="data" post-filter="newlines"></div>

Aquí está la implementación

app.directive('noHtml', function($filter){
  return function(scope, element, attrs){
    var html = scope[attrs.noHtml];
    var text = angular.element("<div>").html(html).text();

    // post filter
    var filter = attrs.postFilter;
    var result = $filter(filter)(text);

    // apending html
    element.html(result);
  };
});

Lo importante es la textvariable. Aquí creo un elemento DOM intermedio y le agrego el HTML usando el htmlmétodo y luego recupero solo el texto con el textmétodo. Ambos métodos son proporcionados por la versión lite de jQuery de Angular .

La siguiente parte es la aplicación del newlinefiltro, que se realiza mediante el $filterservicio.

Compruebe el plunker aquí: http://plnkr.co/edit/SEtHH5eUgFEtC92Czq7T?p=preview

jaime
fuente
2

Una actualización del filtro con ng-bind-html actualmente sería:

myApp.filter('newlines', function () {
  return function(text) {
    return text.replace(/(&#13;)?&#10;/g, '<br/>');
  }
});

y el filtro noHTML ya no es necesario.

La solución de espacios en blanco tiene poca compatibilidad con el navegador: http://caniuse.com/#search=tab-size

Alex Mounir
fuente
0

Un poco tarde para la fiesta en esto, pero sugeriría una pequeña mejora para verificar cadenas nulas / indefinidas.

Algo como:

.filter('newlines', function () {
    return function(text) {
        return (text) ? text.replace(/(&#13;)?&#10;/g, '<br/>') : text;
    };
})

O (un poco más apretado)

.filter('newlines', function () {
    return function(text) {
        return (text instanceof String || typeof text === "string") ? text.replace(/(&#13;)?&#10;/g, '<br/>') : text;
    };
})
Ben Edge
fuente