Piszę aplikację Angular i mam odpowiedź HTML, którą chcę wyświetlić.
Jak mogę to zrobić? Jeśli po prostu użyję składni wiązania {{myVal}}
, koduje wszystkie znaki HTML (oczywiście).
Potrzebuję w jakiś sposób powiązać innerHTML
a div
ze zmienną.
Piszę aplikację Angular i mam odpowiedź HTML, którą chcę wyświetlić.
Jak mogę to zrobić? Jeśli po prostu użyję składni wiązania {{myVal}}
, koduje wszystkie znaki HTML (oczywiście).
Potrzebuję w jakiś sposób powiązać innerHTML
a div
ze zmienną.
Odpowiedzi:
Prawidłowa składnia jest następująca:
<div [innerHTML]="theHtmlString"></div>
Angular 2.0.0 i Angular 4.0.0 final
Tylko dla bezpiecznych treści
<div [innerHTML]="myVal"></div>
DOMSanitizer
Potencjalnie niebezpieczny kod HTML musi zostać wyraźnie oznaczony jako zaufany za pomocą sanitizera DOM Angulars, aby nie usuwał potencjalnie niebezpiecznych części treści
<div [innerHTML]="myVal | safeHtml"></div>
z rurką jak
@Pipe({name: 'safeHtml'})
export class Safe {
constructor(private sanitizer:DomSanitizer){}
transform(style) {
return this.sanitizer.bypassSecurityTrustHtml(style);
//return this.sanitizer.bypassSecurityTrustStyle(style);
// return this.sanitizer.bypassSecurityTrustXxx(style); - see docs
}
}
Zobacz też W RC.1 niektórych stylów nie można dodać przy użyciu składni wiązania
I dokumenty: https://angular.io/api/platform-browser/DomSanitizer
Ostrzeżenie bezpieczeństwa
Ufanie dodanemu użytkownikowi HTML może stanowić zagrożenie bezpieczeństwa. Wcześniej wspomniane dokumenty stwierdzają:
Wywołanie któregokolwiek z
bypassSecurityTrust...
interfejsów API wyłącza wbudowaną dezynfekcję Angulara dla przekazywanej wartości. Ostrożnie sprawdź i sprawdź wszystkie wartości i ścieżki kodu wchodzące w to wywołanie. Upewnij się, że wszelkie dane użytkownika są odpowiednio chronione przed tym kontekstem bezpieczeństwa. Aby uzyskać więcej informacji, zobacz Podręcznik bezpieczeństwa .
Znaczniki kątowe
Coś jak
class FooComponent {
bar = 'bar';
foo = `<div>{{bar}}</div>
<my-comp></my-comp>
<input [(ngModel)]="bar">`;
z
<div [innerHTML]="foo"></div>
nie spowoduje, że Angular przetworzy coś specyficznego dla Angularafoo
. Angular zastępuje znaczniki Angular w czasie kompilacji wygenerowanym kodem. Znaczniki dodane w czasie wykonywania nie będą przetwarzane przez Angular .
Aby dodać HTML, który zawiera znaczniki właściwe dla Angulara (powiązanie właściwości lub wartości, komponenty, dyrektywy, potoki, ...) wymagane jest dodanie modułu dynamicznego i kompilacja komponentów w czasie wykonywania. Ta odpowiedź zawiera więcej szczegółów Jak mogę użyć / utworzyć szablon dynamiczny do skompilowania komponentu dynamicznego z Angular 2.0?
import { BrowserModule, DomSanitizer } from '@angular/platform-browser'
import { Pipe } from '@angular/core'
[innerHtml]
jest świetną opcją w większości przypadków, ale zawodzi przy naprawdę dużych ciągach lub gdy potrzebujesz stylizacji w formacie HTML.
Chciałbym podzielić się innym podejściem:
Wszystko, co musisz zrobić, to utworzyć div w pliku html i podać mu identyfikator:
<div #dataContainer></div>
Następnie w komponencie Angular 2 utwórz odwołanie do tego obiektu (tutaj TypeScript):
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
templateUrl: "some html file"
})
export class MainPageComponent {
@ViewChild('dataContainer') dataContainer: ElementRef;
loadData(data) {
this.dataContainer.nativeElement.innerHTML = data;
}
}
Następnie po prostu użyj loadData
funkcji, aby dodać tekst do elementu HTML.
Jest to tylko sposób na zrobienie tego przy użyciu natywnego języka JavaScript, ale w środowisku Angular. Nie polecam tego, ponieważ sprawia, że kod jest bardziej niechlujny, ale czasami nie ma innej opcji.
Zobacz także Angular 2 - stylizacja innerHTML
nativeElement
bezpośredni dostęp do właściwości, co jest uważane za złą praktykę. Jestem pewien, że [innerHTML]="..."
robi to samo pod maską, ale w dobry sposób Angular2.
[innerHTML]
dużymi łańcuchami w Angular2?
[innerHtml]
usuwa stylizację zakodowaną w HTML. W celu zintegrowania edytora wysiwyg musiałem zastosować wymienione tutaj podejście.
[innerHTML]
podejście nie.
Na angular2@2.0.0-alpha.44:
Wiązanie HTML nie będzie działać podczas używania {{interpolation}}
, zamiast tego użyj „Wyrażenia”:
nieważny
<p [innerHTML]="{{item.anleser}}"></p>
-> zgłasza błąd (interpolacja zamiast oczekiwanego wyrażenia)
poprawny
<p [innerHTML]="item.anleser"></p>
-> to jest właściwy sposób.
możesz dodać dodatkowe elementy do wyrażenia, takie jak:
<p [innerHTML]="'<b>'+item.anleser+'</b>'"></p>
Wskazówka
HTML dodany przy użyciu [innerHTML]
(lub dodany dynamicznie za pomocą innych środków podobnych element.appenChild()
lub podobnych) nie będzie przetwarzany przez Angular w jakikolwiek inny sposób niż dezynfekcja ze względów bezpieczeństwa.
Takie rzeczy działają tylko wtedy, gdy HTML jest dodawany statycznie do szablonu komponentów. Jeśli potrzebujesz, możesz utworzyć komponent w czasie wykonywania, jak wyjaśniono w Jak używać / tworzyć dynamiczny szablon do kompilacji dynamicznego komponentu z Angular 2.0?
Bezpośrednie korzystanie z [innerHTML] bez użycia sanitizera DOM Angulara nie jest możliwe, jeśli zawiera treści tworzone przez użytkowników. Rura SafeHtml zasugerowana przez @ GünterZöchbauer w swojej odpowiedzi jest jednym ze sposobów odkażania zawartości. Następująca dyrektywa to kolejna:
import { Directive, ElementRef, Input, OnChanges, Sanitizer, SecurityContext,
SimpleChanges } from '@angular/core';
// Sets the element's innerHTML to a sanitized version of [safeHtml]
@Directive({ selector: '[safeHtml]' })
export class HtmlDirective implements OnChanges {
@Input() safeHtml: string;
constructor(private elementRef: ElementRef, private sanitizer: Sanitizer) {}
ngOnChanges(changes: SimpleChanges): any {
if ('safeHtml' in changes) {
this.elementRef.nativeElement.innerHTML =
this.sanitizer.sanitize(SecurityContext.HTML, this.safeHtml);
}
}
}
Być stosowane
<div [safeHtml]="myVal"></div>
Can't bind to 'safeHtml' since it isn't a known property of 'div'.
ng-wersja 2.4.4
constructor( private sanitizer: Sanitizer) {}
i powiązać wynik z tym, czego potrzebujesz, również użycie ElementRef jest zdecydowanie nie sugerowane.
Proszę odnieść się do innych, bardziej aktualnych odpowiedzi.
To działa dla mnie: <div innerHTML = "{{ myVal }}"></div>
(Angular2, Alpha 33)
Zgodnie z innym SO: Wstawianie HTML z serwera do DOM za pomocą angular2 (ogólna manipulacja DOM w Angular2) , „wewnętrzna-HTML” jest równoważna „ng-bind-HTML” w Angular 1.X
Aby uzyskać pełną odpowiedź, jeśli zawartość HTML jest w zmiennej składowej, możesz również użyć:
<div [innerHTML]=componementVariableThatHasTheHtml></div>
Przepraszam, jeśli nie rozumiem tego tutaj, ale chciałbym polecić inne podejście:
Myślę, że lepiej jest zwrócić surowe dane z aplikacji po stronie serwera i powiązać je z szablonem po stronie klienta. To sprawia, że żądania są bardziej zwinne, ponieważ zwracasz tylko json z serwera.
Dla mnie nie wydaje się sensowne korzystanie z Angulara, jeśli wszystko, co robisz, to pobieranie html z serwera i wstrzykiwanie go „tak, jak jest” do DOM.
Wiem, że Angular 1.x ma powiązanie HTML, ale nie widziałem jeszcze odpowiednika w Angular 2.0. Mogą jednak dodać to później. W każdym razie nadal rozważałbym API danych dla aplikacji Angular 2.0.
Mam tutaj kilka próbek z prostym powiązaniem danych, jeśli jesteś zainteresowany: http://www.syntaxsuccess.com/viewarticle/angular-2.0-examples
Podano już krótką odpowiedź: użyj <div [innerHTML]="yourHtml">
wiązania.
Jednak pozostałe wymienione tu porady mogą wprowadzać w błąd. Angular ma wbudowany mechanizm dezynfekujący, gdy łączysz się z takimi właściwościami. Ponieważ Angular nie jest dedykowaną biblioteką odkażającą, nadgorliwe jest podejrzane treści, aby nie ryzykować. Na przykład dezynfekuje całą zawartość SVG do pustego ciągu.
Możesz usłyszeć porady dotyczące „dezynfekcji” treści za pomocą DomSanitizer
oznaczania zawartości bypassSecurityTrustXXX
metodami jako bezpiecznymi . Istnieją również sugestie, aby użyć do tego rurki i ta rurka jest często nazywana safeHtml
.
Wszystko to jest mylące, ponieważ faktycznie omija odkażanie , a nie odkażanie treści. Może to budzić obawy związane z bezpieczeństwem, ponieważ jeśli kiedykolwiek zrobisz to na treściach dostarczonych przez użytkownika lub na czymkolwiek, czego nie jesteś pewien - narażasz się na ataki złośliwego kodu.
Jeśli Angular usunie coś, czego potrzebujesz, dzięki wbudowanemu odkażaniu - zamiast wyłączania możesz to zrobić, to deleguj rzeczywistą dezynfekcję do dedykowanej biblioteki, która jest dobra w tym zadaniu. Na przykład - DOMPurify.
Zrobiłem dla niego bibliotekę opakowań, aby można ją było łatwo używać z Angularem: https://github.com/TinkoffCreditSystems/ng-dompurify
Ma także potok do deklaratywnej dezynfekcji HTML:
<div [innerHtml]="value | dompurify"></div>
Różnica w stosunku do rur sugerowanych tutaj polega na tym, że faktycznie wykonuje dezynfekcję za pośrednictwem DOMPurify i dlatego działa dla SVG.
Należy pamiętać, że DOMPurify doskonale nadaje się do odkażania HTML / SVG, ale nie CSS. Możesz więc zapewnić odkażacz CSS Angulara do obsługi CSS:
import {NgModule, ɵ_sanitizeStyle} from '@angular/core';
import {SANITIZE_STYLE} from '@tinkoff/ng-dompurify';
@NgModule({
// ...
providers: [
{
provide: SANITIZE_STYLE,
useValue: ɵ_sanitizeStyle,
},
],
// ...
})
export class AppModule {}
To wewnętrzny - hense ɵ
prefiks, ale i tak zespół Angular używa go w swoich pakietach. Ta biblioteka działa również dla Angular Universal i środowiska redredredingu po stronie serwera.
Wystarczy użyć [innerHTML]
atrybutu w kodzie HTML , coś takiego poniżej:
<div [innerHTML]="myVal"></div>
Czy kiedykolwiek miałeś w swoim składniku właściwości, które zawierają znaczniki HTML lub elementy, które musisz wyświetlić w szablonie? Tradycyjna interpolacja nie zadziała, ale na pomoc przychodzi powiązanie właściwości innerHTML.
Korzystanie {{myVal}}
NIE działa zgodnie z oczekiwaniami! To nie będzie odebrać tagów HTML, takich jak <p>
, <strong>
etc i przekazać go wyłącznie jako ciągi ...
Wyobraź sobie, że masz ten kod w swoim komponencie:
const myVal:string ='<strong>Stackoverflow</strong> is <em>helpful!</em>'
Jeśli użyjesz {{myVal}}
, zobaczysz to w widoku:
<strong>Stackoverflow</strong> is <em>helpful!</em>
ale użycie [innerHTML]="myVal"
powoduje oczekiwany wynik:
Stackoverflow jest pomocny!
Możesz zastosować wiele potoków dla stylu, linku i HTML w następujący sposób w .html
<div [innerHTML]="announcementContent | safeUrl| safeHtml">
</div>
oraz w rurze .ts dla sanitizera „URL”
import { Component, Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({ name: 'safeUrl' })
export class SafeUrlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
potok do dezynfekatora „HTML”
import { Component, Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'safeHtml'
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {}
transform(value) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
będzie to miało zastosowanie zarówno bez zakłócania jakiegokolwiek stylu, jak i zdarzenia kliknięcia linku
<div [innerHTML]="HtmlPrint"></div><br>
InnerHTML jest właściwością elementów HTML, który pozwala ustawić to html-content programowo. Istnieje również właściwość innerText, która definiuje treść jako zwykły tekst.
[attributeName]="value"
Wspornik skrzynka otaczająca atrybut definiuje kątowym wejście wiążące. Oznacza to, że wartość właściwości (w twoim przypadku innerHtml) jest powiązana z danym wyrażeniem, gdy zmienia się wynik wyrażenia, zmienia się również wartość właściwości.
Zasadniczo [innerHtml]
pozwala więc na wiązanie i dynamiczną zmianę treści HTML danego elementu HTML.
W Angular 2 możesz wykonać 3 rodzaje powiązań:
[property]="expression"
-> Każda właściwość HTML może zawierać link do (event)="expression"
-> Gdy zdarzenie aktywuje wykonanie wyrażenia.[(ngModel)]="property"
-> Wiąże właściwość z js (lub ts) do html. Wszelkie aktualizacje tej właściwości będą widoczne wszędzie.Wyrażenie może być wartością, atrybutem lub metodą. Na przykład: „4”, „controller.var”, „getValue ()”
Przykład tutaj
Sposób dynamicznego dodawania elementów do DOM, jak wyjaśniono w Angular 2 doc, polega na użyciu klasy ViewContainerRef z @ Angular / core.
Musisz zadeklarować dyrektywę, która zaimplementuje ViewContainerRef i będzie działać jako symbol zastępczy w twoim DOM.
Dyrektywa
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appInject]'
})
export class InjectDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
Następnie w szablonie, w którym chcesz wstrzyknąć komponent:
HTML
<div class="where_you_want_to_inject">
<ng-template appInject></ng-template>
</div>
Następnie z wstrzykniętego kodu komponentu wstrzykniesz komponent zawierający żądany kod HTML:
import { Component, OnInit, ViewChild, ComponentFactoryResolver } from '@angular/core';
import { InjectDirective } from '../inject.directive';
import { InjectedComponent } from '../injected/injected.component';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
@ViewChild(InjectDirective) injectComp: InjectDirective;
constructor(private _componentFactoryResolver: ComponentFactoryResolver) {
}
ngOnInit() {
}
public addComp() {
const componentFactory = this._componentFactoryResolver.resolveComponentFactory(InjectedComponent);
const viewContainerRef = this.injectComp.viewContainerRef;
const componentRef = viewContainerRef.createComponent(componentFactory);
}
public removeComp() {
const componentFactory = this._componentFactoryResolver.resolveComponentFactory(InjectedComponent);
const viewContainerRef = this.injectComp.viewContainerRef;
const componentRef = viewContainerRef.remove();
}
}
Dodałem w pełni działającą aplikację demonstracyjną do Angular 2, dynamicznie dodając komponent do wersji demo DOM
Możesz skorzystać z kilku podejść, aby osiągnąć rozwiązanie. Jak już powiedziano w zatwierdzonej odpowiedzi, możesz użyć:
<div [innerHTML]="myVal"></div>
w zależności od tego, co próbujesz osiągnąć, możesz także wypróbować inne rzeczy, takie jak javascript DOM (niezalecane, operacje DOM są powolne):
Prezentacja
<div id="test"></test>
Składnik
var p = document.getElementsById("test");
p.outerHTML = myVal;
getElementsById
innej metody selekcji jest złe, ponieważ może przechwytywać elementy należące do zupełnie różnych komponentów, jeśli zawierają one elementy o tym samym identyfikatorze (lub innych kryteriach).
Zawsze możemy przekazać innerHTML
właściwość HTML do właściwości w celu renderowania dynamicznej treści HTML, ale ta dynamiczna treść HTML może być również zainfekowana lub złośliwa. Dlatego przed przekazaniem zawartości dynamicznej innerHTML
zawsze powinniśmy upewnić się, że jest ona zdezynfekowana (używana DOMSanitizer
), abyśmy mogli uciec od wszystkich złośliwych treści.
Wypróbuj poniżej rury:
import { Pipe, PipeTransform } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
@Pipe({name: 'safeHtml'})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {
}
transform(value: string) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
Usage:
<div [innerHTML]="content | safeHtml"></div>
style: background-color
wszystkie rzeczy można rozebrać, dlatego najlepiej zacząć od początku, bo później bardzo się zdezorientujesz.
Jeśli chcesz tego w Angular 2 lub Angular 4, a także chcesz zachować wbudowany CSS, możesz użyć
<div [innerHTML]="theHtmlString | keepHtml"></div>
Możesz również powiązać właściwości klasy elementu kątowego z szablonem, używając formy kanonicznej, jak poniżej:
<div bind-innerHTML="theHtmlString"></div>
Dokumentacja kątowa: https://angular.io/guide/template-syntax#property-binding-property
Praca w Angular v2.1.1
<div [innerHTML]="variable or htmlString">
</div>
<div _ngcontent-luf-0=""></div>
dla mnie. div
Jest pusty.
Jeśli masz szablony w aplikacji kątowej (lub dowolnej innej ramie) i zwracasz szablony HTML z backendu za pomocą żądania / odpowiedzi HTTP, mieszasz szablony między frontendem a backendem.
Dlaczego nie zostawić szablonów w interfejsie (sugerowałbym to) lub w backendzie (całkiem nieprzejrzyste imo)?
A jeśli szablony są przechowywane w interfejsie użytkownika, dlaczego po prostu nie odpowiedzieć za pomocą JSON na żądania do zaplecza. Nie musisz nawet implementować struktury RESTful, ale trzymanie szablonów po jednej stronie czyni kod bardziej przejrzystym.
To się zwróci, gdy ktoś inny będzie musiał poradzić sobie z twoim kodem (lub nawet ty sam po pewnym czasie ponownie wprowadzasz swój kod)!
Jeśli zrobisz to dobrze, będziesz mieć małe komponenty z małymi szablonami, a co najważniejsze, jeśli twój kod to imba, ktoś, kto nie zna języków kodowania, będzie w stanie zrozumieć twoje szablony i logikę! Więc dodatkowo zachowaj swoje funkcje / metody tak małe, jak to tylko możliwe. W końcu dowiesz się, że utrzymanie, refaktoryzacja, przeglądanie i dodawanie funkcji będzie znacznie łatwiejsze w porównaniu do dużych funkcji / metod / klas oraz mieszanie szablonów i logiki między frontendem a backendem - i zachowaj tyle logiki w backendie jeśli twój frontend musi być bardziej elastyczny (np. pisanie frontendu dla Androida lub przełączanie się na inną strukturę frontendu).
Filozofia, człowiek :)
ps: nie musisz implementować w 100% czystego kodu, ponieważ jest on bardzo drogi - szczególnie jeśli musisz zmotywować członków zespołu;), ale: powinieneś znaleźć równowagę między podejściem do czystszego kodu a tym, co masz (może to jest już dość czysty)
sprawdź książkę, jeśli możesz i pozwól jej wejść do twojej duszy: https://de.wikipedia.org/wiki/Clean_Code