Угловое связывание 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

См. Рабочий пример stackblitz здесь

Мы всегда можем передать 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.

  1. Установить библиотеку с помощью

            npm i angular-html-recompile
    
  2. Добавьте приведенный ниже код в файл app.component.html.

            <pk-angular-html-recompile *ngIf="template !== ''" 
                               [stringTemplate]="template" 
                               [data]="dataObject"> 
    </pk-angular-html-recompile>
    
  3. Используйте приведенный ниже код в файле 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;
        }
    }
    
  4. Добавьте модуль в файл 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 { }
    
  5. Эта библиотека поддерживает базовый 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;

Привязка недвижимости

Javascript DOM Внешний HTML

Просто чтобы опубликовать небольшое дополнение ко всем отличным ответам на данный момент: если вы используете [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

This works for me:

       <div innerHTML = "{{ myVal }}"></div>

Сначала создайте трубу.

      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>
Другие вопросы по тегам