Угловое связывание HTML
Я пишу угловое приложение, и у меня есть HTML
ответ я хочу отобразить.
Как я могу это сделать? Если я просто использую синтаксис привязки {{myVal}}
это кодирует все HTML
персонажи (конечно).
Мне нужно как-то связать внутренний HTML-код div
к значению переменной.
28 ответов
Правильный синтаксис следующий:
<div [innerHTML]="theHtmlString"></div>
Работает в 7.0.2
Angular 2.0.0 и Angular 4.0.0 final
Для безопасного контента просто
<div [innerHTML]="myVal"></div>
DOMSanitizer
Потенциально небезопасный HTML должен быть явно помечен как надежный с помощью средства гигиены Angulars DOM, чтобы не удалять потенциально небезопасные части содержимого
<div [innerHTML]="myVal | safeHtml"></div>
с трубкой как
@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
}
}
См. Также В RC.1 некоторые стили не могут быть добавлены с использованием синтаксиса привязки.
И документы: https://angular.io/api/platform-browser/DomSanitizer
Предупреждение безопасности
Доверие к добавленному пользователем HTML может представлять угрозу безопасности. В упомянутых выше документах говорится:
Вызов любого из
bypassSecurityTrust...
API отключает встроенную очистку Angular для переданного значения. Тщательно проверяйте и проверяйте все значения и пути кода, входящие в этот вызов. Убедитесь, что любые пользовательские данные надлежащим образом экранированы для этого контекста безопасности. Для получения более подробной информации см. Руководство по безопасности.
Угловая разметка
Что-то вроде
class FooComponent {
bar = 'bar';
foo = `<div>{{bar}}</div>
<my-comp></my-comp>
<input [(ngModel)]="bar">`;
с
<div [innerHTML]="foo"></div>
не заставит Angular обрабатывать что-либо специфичное для Angular в foo
, Angular заменяет определенную разметку Angular во время сборки на сгенерированный код. Разметка, добавленная во время выполнения , не будет обрабатываться Angular.
Чтобы добавить HTML, содержащий разметку, специфичную для Angular (привязка свойства или значения, компоненты, директивы, каналы,...), необходимо добавить динамический модуль и скомпилировать компоненты во время выполнения. Этот ответ содержит более подробную информацию. Как я могу использовать / создать динамический шаблон для компиляции динамического компонента с Angular 2.0?
[innerHtml]
Это отличный вариант в большинстве случаев, но он терпит неудачу с очень большими строками или когда вам нужно жестко запрограммировать стили в html.
Я хотел бы поделиться другим подходом:
Все, что вам нужно сделать, это создать div в вашем html-файле и присвоить ему некоторый идентификатор:
<div #dataContainer></div>
Затем в вашем компоненте Angular 2 создайте ссылку на этот объект (здесь 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;
}
}
Тогда просто используйте loadData
функция для добавления текста в элемент HTML.
Это просто способ сделать это с использованием нативного JavaScript, но в среде Angular. Я не рекомендую этого, потому что делает код более запутанным, но иногда нет другого выбора.
Смотрите также Angular 2 - innerHTML style
На angular2@2.0.0-alpha.44:
Привязка HTML не будет работать при использовании {{interpolation}}
используйте вместо этого "Выражение":
недействительным
<p [innerHTML]="{{item.anleser}}"></p>
-> выдает ошибку (интерполяция вместо ожидаемого выражения)
правильный
<p [innerHTML]="item.anleser"></p>
-> Это правильный путь.
Вы можете добавить дополнительные элементы к выражению, например:
<p [innerHTML]="'<b>'+item.anleser+'</b>'"></p>
намек
HTML добавлен с использованием [innerHTML]
(или динамически добавляется другими средствами, такими как element.appenChild()
или аналогичный) не будет обрабатываться Angular каким-либо образом, кроме очистки в целях безопасности.
Такие вещи работают только тогда, когда HTML-код статически добавляется в шаблон компонентов. Если вам это нужно, вы можете создать компонент во время выполнения, как описано в разделе Как использовать / создать динамический шаблон для компиляции динамического компонента с Angular 2.0?
Непосредственное использование [innerHTML] без использования дезинфицирующего средства DOM от Angular не подходит, если оно содержит контент, созданный пользователем. Канал safeHtml, предложенный @GünterZöchbauer в своем ответе, является одним из способов дезинфекции контента. Следующая директива является еще одной:
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);
}
}
}
Использоваться
<div [safeHtml]="myVal"></div>
Это работает для меня: <div innerHTML = "{{ myVal }}"></div>
(Angular2, Alpha 33)
Согласно другому SO: Вставка HTML с сервера в DOM с помощью angular2 (общие манипуляции с DOM в Angular2), "inner-html" эквивалентна "ng-bind-html" в Angular 1.X
Просто для полного ответа, если ваш HTML-контент находится в переменной компонента, вы также можете использовать:
<div [innerHTML]=componementVariableThatHasTheHtml></div>
Здесь уже был дан краткий ответ: используйте <div [innerHTML]="yourHtml">
привязка.
Однако остальные советы, упомянутые здесь, могут вводить в заблуждение. Angular имеет встроенный механизм очистки, когда вы привязываетесь к таким свойствам. Поскольку Angular не является специальной библиотекой для очистки, она слишком ревностно относится к подозрительному контенту, чтобы не рисковать. Например, он очищает все содержимое SVG до пустой строки.
Вы можете услышать советы по "дезинфекции" вашего контента с помощью DomSanitizer
пометить контент как безопасный с помощью bypassSecurityTrustXXX
методы. Также есть предложения использовать для этого pipe, и этот канал часто называютsafeHtml
.
Все это вводит в заблуждение, потому что на самом деле это обходится без очистки, а не санации вашего контента. Это может быть проблемой безопасности, потому что, если вы когда-либо сделаете это с пользовательским контентом или с чем-то, в чем вы не уверены, вы подвергнетесь атаке вредоносного кода.
Если Angular удаляет что-то, что вам нужно, с помощью встроенной дезинфекции - вы можете сделать вместо того, чтобы отключать ее, делегировать фактическую дезинфекцию специальной библиотеке, которая хороша для этой задачи. Например - DOMPurify.
Я сделал для него библиотеку-оболочку, чтобы ее можно было легко использовать с Angular:https://github.com/TinkoffCreditSystems/ng-dompurify
Он также имеет канал для декларативной дезинфекции HTML:
<div [innerHtml]="value | dompurify"></div>
Отличие от предложенных здесь каналов состоит в том, что они действительно выполняют дезинфекцию через DOMPurify и, следовательно, работают с SVG.
Следует иметь в виду, что DOMPurify отлично подходит для очистки HTML/SVG, но не CSS. Таким образом, вы можете предоставить дезинфицирующее средство CSS Angular для обработки CSS:
import {NgModule, ɵ_sanitizeStyle} from '@angular/core';
import {SANITIZE_STYLE} from '@tinkoff/ng-dompurify';
@NgModule({
// ...
providers: [
{
provide: SANITIZE_STYLE,
useValue: ɵ_sanitizeStyle,
},
],
// ...
})
export class AppModule {}
Это внутреннее - hense ɵ
префикс, но в любом случае команда Angular использует его в своих пакетах именно так. Эта библиотека также работает для Angular Universal и серверной среды renedring.
Я прошу прощения, если я упускаю суть здесь, но я хотел бы рекомендовать другой подход:
Я думаю, что лучше возвращать необработанные данные из вашего серверного приложения и связывать их с шаблоном на стороне клиента. Это делает более гибкие запросы, поскольку вы возвращаете только json с вашего сервера.
Мне кажется, не имеет смысла использовать Angular, если все, что вы делаете, это извлекаете html с сервера и вставляете его "как есть" в DOM.
Я знаю, что Angular 1.x имеет привязку html, но я еще не видел аналога в Angular 2.0. Они могут добавить это позже, хотя. В любом случае, я бы по-прежнему рассмотрел API данных для вашего приложения Angular 2.0.
У меня есть несколько примеров с простой привязкой данных, если вам интересно: http://www.syntaxsuccess.com/viewarticle/angular-2.0-examples
Просто используйте [innerHTML]
атрибут в вашем HTML, что-то вроде этого ниже:
<div [innerHTML]="myVal"></div>
У вас когда-нибудь были свойства в вашем компоненте, которые содержат некоторую HTML-разметку или объекты, которые вам нужно отображать в вашем шаблоне? Традиционная интерполяция не сработает, но на помощь приходит привязка свойства innerHTML.
С помощью {{myVal}}
НЕ работает, как ожидалось! Это не поднимет HTML-теги, как <p>
, <strong>
и т.д. и передать его только в виде строк...
Представьте, что у вас есть этот код в вашем компоненте:
const myVal:string ='<strong>Stackru</strong> is <em>helpful!</em>'
Если вы используете {{myVal}}
, вы получите это в виде:
<strong>Stackru</strong> is <em>helpful!</em>
но используя [innerHTML]="myVal"
делает результат, как ожидалось, вот так:
Stackru полезен!
<div [innerHTML]="HtmlPrint"></div><br>
InnerHtml это свойство HTML-элементов, что позволяет установить его HTML-содержимое программно. Также существует свойство innerText, которое определяет содержимое как простой текст.
В [attributeName]="value"
квадратная скобка, окружающая атрибут, определяет привязку ввода Angular. Это означает, что значение свойства (в вашем случае innerHtml) привязано к данному выражению, когда результат выражения изменяется, значение свойства также изменяется.
Так что в основном [innerHtml]
позволяет связывать и динамически изменять html-содержание данного HTML-элемента.
Вы можете применить несколько каналов для стиля, ссылки и HTML, как показано в.html
<div [innerHTML]="announcementContent | safeUrl| safeHtml">
</div>
и в канале.ts для дезинфицирующего средства '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);
}
}
труба для дезинфицирующего средства 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);
}
}
это будет применяться как без нарушения стиля, так и при нажатии на ссылку
Вы также можете связать свойства класса компонента angular с шаблоном, используя каноническую форму, как показано ниже:
<div bind-innerHTML="theHtmlString"></div>
Документация по Angular: https://angular.io/guide/template-syntax
Мы всегда можем передать html контент innerHTML
свойство для отображения динамического содержимого HTML, но это динамическое содержимое HTML также может быть зараженным или вредоносным. Поэтому перед передачей динамического контента innerHTML
мы всегда должны следить за тем, чтобы содержимое было продезинфицировано (используя DOMSanitizer
), чтобы мы могли избежать всего вредоносного контента.
Попробуйте ниже трубы:
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>
В Angular 2 вы можете делать 3 вида привязок:
[property]="expression"
-> Любое свойство HTML может ссылаться на
выражение. В этом случае, если выражение изменится, свойство будет обновлено, но это не сработает.(event)="expression"
-> Когда событие активирует выполнение выражения.[(ngModel)]="property"
-> Связывает свойство из js (или ts) с html. Любое обновление этого свойства будет заметно везде.
Выражение может быть значением, атрибутом или методом. Например: "4", "controller.var", "getValue()"
Пример здесь
Вы можете использовать следующие два способа.
<div [innerHTML]="myVal"></div>
или же
<div innerHTML="{{myVal}}"></div>
Angular 2+ поддерживает привязку свойства [innerHTML], которая будет отображать HTML. Если бы вы иначе использовали интерполяцию, она была бы обработана как строка.
В
.html
файл
<div [innerHTML]="theHtmlString"></div>
В
.ts
файл
theHtmlString:String = "enter your html codes here";
У меня есть встроенная ниже библиотека, которая поможет повторно связать привязки в формате html. Ниже приведены шаги по использованию этой библиотеки. Эта библиотека в основном позволяет вводить код компилятора JIT в AOT.
Установить библиотеку с помощью
npm i angular-html-recompile
Добавьте приведенный ниже код в файл app.component.html.
<pk-angular-html-recompile *ngIf="template !== ''" [stringTemplate]="template" [data]="dataObject"> </pk-angular-html-recompile>
Используйте приведенный ниже код в файле app.component.ts.
import { Component, OnInit, ViewChild } from '@angular/core'; import { AngularHtmlRecompileComponent, AngularHtmlRecompileService } from 'angular-html-recompile'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { @ViewChild(AngularHtmlRecompileComponent, { static: true }) comp !: AngularHtmlRecompileComponent; constructor( private angularHtmlRecompileService: AngularHtmlRecompileService) { } public dataObject: any; public template = `<div class="login-wrapper" fxLayout="row" fxLayoutAlign="center center"> <mat-card class="box"> <mat-card-header> <mat-card-title>Register</mat-card-title> </mat-card-header> <form class="example-form"> <mat-card-content> <mat-form-field class="example-full-width"> <input matInput placeholder="Username" [value]="Username" (keydown)="onControlEvent($event,'Username')"> </mat-form-field> <mat-form-field class="example-full-width"> <input matInput placeholder="Email" [value]="Email" (keydown)="onControlEvent($event,'Email')"> </mat-form-field> <mat-form-field *ngIf="isShow" class="example-full-width"> <input matInput placeholder="Password" [value]="Password" (keydown)="onControlEvent($event,'Password')"> </mat-form-field> <mat-form-field class="example-full-width"> <mat-label>Choose a role...</mat-label> <mat-select (selectionChange)="onControlEvent($event, 'selectedValue')"> <mat-option [value]="roles" *ngFor="let roles of Roles">{{roles}} </mat-option> </mat-select> </mat-form-field> </mat-card-content> <button mat-stroked-button color="accent" class="btn-block" (click)="buttomClickEvent('submit')" >Register</button> </form> </mat-card> </div>`; ngOnInit(): void { this.angularHtmlRecompileService.sharedData.subscribe((respose: any) => { if (respose) { switch (respose.key) { case `Username`: // Call any method on change of name break; case `Password`: //Update password from main component this.comp[`cmpRef`].instance['Password'] = "Karthik"; break; case `submit`: //Get reference of all parameters on submit click //1. respose.data OR //use this.comp[`cmpRef`].instance break; default: break; } } }); this.prepareData(); } prepareData() { //Prepare data in following format only for easy binding //Template preparation and data preparation can be done once data received from service // AngularHtmlRecompileComponent will not be rendered until you pass data this.dataObject = [ { key: 'Username', value: 'Pranay' }, { key: 'Email', value: 'abc@test.com', }, { key: 'Password', value: 'test123', }, { key: 'Roles', value: ['Admin', 'Author', 'Reader'] }, { key: 'isShow', value: this.updateView() } ]; } updateView() { //Write down logic before rendering to UI to work ngIf directive return true; } }
Добавьте модуль в файл app.module.ts
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { AngularHtmlRecompileModule } from "angular-html-recompile"; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AngularHtmlRecompileModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Эта библиотека поддерживает базовый html, материал Angular, гибкие макеты. Чтобы использовать эти функции, установите следующие зависимости
npm i -s @angular/material @angular/flex-layout
Работа в AngularJS v2.1.1
<div [innerHTML]="variable or htmlString">
</div>
Вы можете использовать несколько подходов для достижения решения. Как уже сказано в утвержденном ответе, вы можете использовать:
<div [innerHTML]="myVal"></div>
в зависимости от того, чего вы пытаетесь достичь, вы также можете попробовать другие вещи, такие как JavaScript DOM (не рекомендуется, операции DOM медленные):
презентация
<div id="test"></test>
Составная часть
var p = document.getElementsById("test");
p.outerHTML = myVal;
Просто чтобы опубликовать небольшое дополнение ко всем отличным ответам на данный момент: если вы используете [innerHTML]
для рендеринга компонентов Angular и недовольных тем, что он работает не так, как я, взгляните на библиотеку ngx-dynamic-hooks, которую я написал для решения этой самой проблемы.
С его помощью вы можете загружать компоненты из динамических строк / HTML без ущерба для безопасности. На самом деле он использует AngularDOMSanitizer
как [innerHTML]
делает то же самое, но сохраняет возможность загружать компоненты (безопасным способом).
Посмотрите на это в действии в этом Stackblitz.
Если вы хотите это в Angular 2 или Angular 4, а также хотите сохранить встроенный CSS, тогда вы можете использовать
<div [innerHTML]="theHtmlString | keepHtml"></div>
Способ динамического добавления элементов в DOM, как описано в документе Angular 2, заключается в использовании класса ViewContainerRef из @Angular/core.
Что вам нужно сделать, так это объявить директиву, которая будет реализовывать ViewContainerRef и действовать как заполнитель в вашей DOM.
директива
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appInject]'
})
export class InjectDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
Затем в шаблоне, куда вы хотите добавить компонент:
HTML
<div class="where_you_want_to_inject">
<ng-template appInject></ng-template>
</div>
Затем из введенного кода компонента вы добавите компонент, содержащий нужный 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();
}
}
Я добавил полностью работающее демо-приложение на Angular 2, динамически добавив компонент в DOM demo
Сначала создайте трубу.
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Pipe({
name: 'sanitizer',
})
export class SanitizerUrlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(value: string, args: any = 'SafeURL'): SafeUrl | SafeHtml {
if (args == 'SafeHtml') {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
}
Затем используйте канал в своем HTML-шаблоне следующим образом.
<div [innerHtml]="data | sanitizer : 'SafeHtml'"></div>
Код ниже поможет вам
Myval вы можете заменить на желаемый HTML
<div [innerHTML]="myVal"></div>
Если у вас есть шаблоны в вашем угловом (или любом другом фреймворковом) приложении, и вы возвращаете шаблоны HTML из своего бэкэнда через HTTP-запрос / ответ, вы смешиваете шаблоны между внешним интерфейсом и бэкэндом.
Почему бы просто не оставить шаблонные материалы либо во внешнем интерфейсе (я бы это предложил), либо во внутреннем интерфейсе (довольно непрозрачный imo)?
И если вы храните шаблоны во внешнем интерфейсе, почему бы просто не ответить JSON на запросы к внутреннему интерфейсу. Вам даже не нужно реализовывать структуру RESTful, но хранение шаблонов с одной стороны делает ваш код более прозрачным.
Это окупится, когда кто-то другой должен справиться с вашим кодом (или даже вы сами вводите свой собственный код через некоторое время)!
Если вы все сделаете правильно, у вас будут небольшие компоненты с небольшими шаблонами, и, что лучше всего, если ваш код imba, тот, кто не знает языков программирования, сможет понять ваши шаблоны и вашу логику! Кроме того, сохраняйте ваши функции / методы как можно меньше. В конечном итоге вы обнаружите, что обслуживание, рефакторинг, просмотр и добавление функций будет намного проще по сравнению с большими функциями / методами / классами и смешением шаблонов и логики между внешним интерфейсом и бэкендом - и сохраните столько же логики в бэкэнде если ваш внешний интерфейс должен быть более гибким (например, написание внешнего интерфейса Android или переключение на другую среду внешнего интерфейса).
Философия, мужик:)
PS: вам не нужно реализовывать 100% чистый код, потому что это очень дорого - особенно если вам нужно мотивировать членов команды;) но: вы должны найти хороший баланс между подходом к более чистому коду и тем, что у вас есть (может быть, это уже довольно чисто)
проверьте книгу, если можете, и дайте ей войти в вашу душу: https://de.wikipedia.org/wiki/Clean_Code
попробуй этот код
Ваша строка с HTML-тегом, как показано ниже
htmlString:string = "Hello<br/>Html"
Вы можете получить строку в HTML-странице
<ion-content>
<ion-item>
<div [innerHTML] = "'<p>' + htmlString + '</p>'"></div>
</ion-item>
</ion-content>