angularjs filtr nowej linii bez żadnego innego html

86

Próbuję przekonwertować znaki nowej linii ( \n) na html br.
Zgodnie z tą dyskusją w Grupie Google , oto co mam:

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

Dyskusja tam również radzi używać w widoku:

{{ dataFromModel | newline | html }}

Wygląda na to, że używany jest stary htmlfiltr, podczas gdy teraz powinniśmy użyć ng-bind-htmlatrybutu.


Niemniej jednak stanowi to problem: nie chcę, aby jakikolwiek kod HTML z oryginalnego ciągu ( dataFromModel) był renderowany jako HTML; tylko br's.

Na przykład, biorąc pod uwagę następujący ciąg:

Chociaż 7> 5
nadal nie chcę tutaj html i innych rzeczy ...

Chciałbym, żeby wypisał:

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

Czy jest jakiś sposób, aby to osiągnąć?

MegaHit
źródło

Odpowiedzi:

279

Może da się to osiągnąć tylko w html, <preformated text>sposób? Uniknie używania filtrów lub jakiegokolwiek przetwarzania.

Wszystko, co musisz zrobić, to wyświetlić tekst w elemencie, który ma ten CSS:

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

Spowoduje to przeanalizowanie i wyświetlenie \ n jako nowych wierszy. U mnie działa świetnie.

Tutaj przykład jsFiddle .

Devin Spikowski
źródło
79
pre-line, było dla mnie lepszą opcją.
Pepijn,
7
+1, jest to zdecydowanie najprostsze rozwiązanie i wydaje się być odpowiednie dla wielu potrzeb. Rzeczywiście, pre-linejest prawdopodobnie ogólnie lepsze, ponieważ długie rzędy zostaną zawinięte (tak jak w przypadku wszelkich <br>rozwiązań bazowych).
tuomassalo
13
style = "white-space: pre-line;" jest lepszą opcją do użycia wewnątrz <div>, moim zdaniem
Dmitri Algazin
7
pre-wrapwydaje się być tym, czego chce większość ludzi (nie przed wierszem): "Spacja jest zachowywana przez przeglądarkę. Tekst będzie zawijany, gdy będzie to konieczne, i łamanie linii" z w3schools
qwertzguy
2
Zauważyłem, że muszę użyć ng-bind = "MyMultiLineText" na <p>, aby zatrzymać dodawanie przez Chrome dodatkowych linii przed moim tekstem
Scott Warren,
33

Zamiast bawić się nowymi dyrektywami, zdecydowałem się po prostu użyć 2 filtrów:

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

Następnie, moim zdaniem, łączę jeden w drugi:

<span ng-bind-html-unsafe="dataFromModel | noHTML | newlines"></span>
MegaHit
źródło
Twoje wyrażenie regularne dla nowych linii nie będzie działać. Potrzebujesz: text.replace(/\\n/g, '<br />')a nawet lepiejtext.replace(/(\\r)?\\n/g, '<br />')
Bartłomiej Zalewski
2
@BarthZalewski - Potrzebujesz tylko `\` podczas kompilowania wyrażenia regularnego z łańcucha. Używając dosłownego wyrażenia regularnego, nie musisz zmieniać ukośników.
MegaHit
2
Ten kod już nie działa, ponieważ ng-bind-html-unsafe jest przestarzały.
Abhi,
1
Jeśli chcesz, możesz teraz pominąć filtr noHtml i po prostu dodać filtr newLines do pliku ng-bind-html. ngSanitize zajmie się resztą.
Dave Merwin
26

Prostszym sposobem na zrobienie tego jest utworzenie filtru, który dzieli każdy tekst na \nlistę, a następnie użycie `ng-repeat.

Filtr:

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

aw html:

<span ng-repeat="line in (text | newlines) track by $index">
    <p> {{line}}</p>
    <br>
</span>
JJW5432
źródło
4
Podoba mi się to rozwiązanie, ale korzystałoby z prostszego HTML:<p ng-repeat="line in (line.message | newlines)">{{line}}</p>
Thomas Fankhauser
2
Dobra odpowiedź, ale lepsze wykorzystanie track byw przypadku podwójnych linii, która zgłasza błąd: line in (text | newlines) track by $index.
JellicleCat
11

Jeśli nie chcesz niszczyć układu niekończącymi się ciągami, użyj pre-line:

<p style="white-space: pre-line;">{{ MyMultiLineText}}</p>
Sebastian Viereck
źródło
6

Nie wiem, czy Angular ma usługę usuwania html, ale wygląda na to, że musisz usunąć HTML przed przekazaniem newlineswłasnego filtra. Sposób, w jaki bym to zrobił, to poprzez niestandardową no-htmldyrektywę, do której zostanie przekazana właściwość zakresu i nazwa filtru do zastosowania po usunięciuhtml

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

Oto implementacja

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

Ważnym bitem jest textzmienna. Tutaj tworzę pośredni element DOM i dołączam do niego kod HTML za pomocą htmlmetody, a następnie pobieram tylko tekst za pomocą textmetody. Obie metody są dostarczane przez lite wersję jQuery w Angular .

Następna część to zastosowanie newlinefiltra, które odbywa się za pomocą $filterusługi.

Sprawdź plunker tutaj: http://plnkr.co/edit/SEtHH5eUgFEtC92Czq7T?p=preview

jaime
źródło
2

Aktualizacja filtru z użyciem ng-bind-html wyglądałaby obecnie:

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

a filtr noHTML nie jest już wymagany.

rozwiązanie z pustymi przestrzeniami ma niską obsługę przeglądarki: http://caniuse.com/#search=tab-size

Alex Mounir
źródło
0

Trochę za późno na imprezę w tej sprawie, ale sugerowałbym niewielką poprawę, aby sprawdzić ciągi niezdefiniowane / zerowe.

Coś jak:

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

Lub (trochę mocniej)

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