filtro de nova linha angularjs sem outro html

86

Estou tentando converter caracteres de nova linha ( \n) em html br.
De acordo com esta discussão no Grupo do Google , aqui está o que tenho:

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

A discussão lá também recomenda usar o seguinte na visualização:

{{ dataFromModel | newline | html }}

Parece htmlque estamos usando o filtro antigo , mas agora devemos usar o ng-bind-htmlatributo.


Independentemente disso, isso representa um problema: não quero que nenhum HTML da string original ( dataFromModel) seja renderizado como HTML; apenas o br's.

Por exemplo, dada a seguinte string:

Enquanto 7> 5
eu ainda não quero html e outras coisas aqui ...

Eu gostaria que ele gerasse:

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

Existe alguma maneira de conseguir isso?

MegaHit
fonte

Respostas:

278

Talvez você consiga fazer isso apenas com html, uma <preformated text>maneira? Isso evitará o uso de filtros ou qualquer tipo de processamento.

Tudo que você precisa fazer é exibir o texto dentro de um elemento que tenha este CSS:

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

Isso analisará e exibirá \ n como novas linhas. Funciona muito bem para mim.

Aqui, um exemplo do jsFiddle .

Devin Spikowski
fonte
79
pré-linha, foi a melhor opção para mim.
Pepijn
7
+1, esta é de longe a solução mais simples e parece ser adequada para muitas necessidades. Na verdade, pre-lineé provavelmente melhor em geral, uma vez que linhas longas serão quebradas (como fariam com qualquer <br>solução baseada).
tuomassalo
13
estilo = "espaço em branco: pré-linha;" é a melhor opção para usar dentro de <div>, na minha opinião
Dmitri Algazin
7
pre-wrapparece ser o que a maioria das pessoas deseja (não pré-linha): "O espaço em branco é preservado pelo navegador. O texto será quebrado quando necessário e quebras de linha" de w3schools
qwertzguy
2
Descobri que precisava usar ng-bind = "MyMultiLineText" no <p> para parar o Chrome de adicionar linhas extras na frente do meu texto
Scott Warren
33

Em vez de mexer com novas diretivas, decidi usar apenas 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;');
    }
});

Então, na minha opinião, eu canalizo um no outro:

<span ng-bind-html-unsafe="dataFromModel | noHTML | newlines"></span>
MegaHit
fonte
Seu regex para novas linhas não funcionará. Você precisa de: text.replace(/\\n/g, '<br />')ou ainda melhortext.replace(/(\\r)?\\n/g, '<br />')
Bartłomiej Zalewski
2
@BarthZalewski - Você só precisa `\` ao compilar um regex a partir de uma string. Ao usar um literal regex, você não precisa escapar de barras.
MegaHit
2
Este código não funciona mais, pois ng-bind-html-unsafe está obsoleto.
Abhi de
1
Agora você pode pular o filtro noHtml se quiser e apenas adicionar o filtro newLines ao ng-bind-html. ngSanitize cuidará do resto.
Dave Merwin
26

Uma maneira mais simples de fazer isso é criar um filtro que divida o texto de cada \num em uma lista e, em seguida, usar `ng-repeat.

O filtro:

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

e no html:

<span ng-repeat="line in (text | newlines) track by $index">
    <p> {{line}}</p>
    <br>
</span>
JJW5432
fonte
4
Gosto desta solução, mas optaria por um HTML mais simples:<p ng-repeat="line in (line.message | newlines)">{{line}}</p>
Thomas Fankhauser
2
Boa resposta, mas melhor utilização track byem caso de linhas duplicadas, o que elevaria um erro: line in (text | newlines) track by $index.
JellicleCat
11

Se você não quiser destruir o layout com strings infinitas, use pre-line:

<p style="white-space: pre-line;">{{ MyMultiLineText}}</p>
Sebastian Viereck
fonte
6

Não sei se o Angular tem um serviço para remover html, mas parece que você precisa remover o html antes de passar seu newlinesfiltro personalizado. A maneira como eu faria isso é por meio de uma no-htmldiretiva personalizada , à qual seria passada uma propriedade de escopo e o nome de um filtro a ser aplicado após a remoção dohtml

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

Aqui está a implementação

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

O que importa é a textvariável. Aqui, crio um elemento DOM intermediário e acrescento a ele o HTML usando o htmlmétodo e, em seguida, recupero apenas o texto com o textmétodo. Ambos os métodos são fornecidos pela versão lite do jQuery do Angular .

A parte seguinte é a aplicação do newlinefiltro, que é feito usando o $filterserviço.

Verifique o plunker aqui: http://plnkr.co/edit/SEtHH5eUgFEtC92Czq7T?p=preview

jaime
fonte
2

Uma atualização do filtro com ng-bind-html atualmente seria:

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

e o filtro noHTML não é mais necessário.

solução de espaço em branco está tendo baixo suporte ao navegador: http://caniuse.com/#search=tab-size

Alex Mounir
fonte
0

Um pouco tarde para a festa sobre isso, mas eu sugeriria uma pequena melhoria para verificar se há strings indefinidas / nulas.

Algo como:

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

Ou (um pouco mais apertado)

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