Динамическое отображение элементов, содержащих HTML, с функциями (клика) Angular 2

У меня есть рекурсивная древовидная структура, содержащая узлы, каждый из которых имеет свойство htmlStringContent. Когда я отображаю дерево с помощью вложенных компонентов «узла» и пытаюсь представить содержимое html, которое я использую:

<div [innerHtml]="node.htmlStringContent"></div>

HTML отображается правильно, но для следующих элементов:

<a (click)="function()">click me</a>

Функции (щелчок) не работают. Я знаю, что это было ранее было опубликовано, но с большим количеством обновлений angular вывел в последнее время я не могу найти никаких решений. Этот ответ заставляет меня поверить, что я должен использовать директиву ngComponentOutlet, но я не уверен, как это сделать.

Как я могу заставить angular связать эту функцию щелчка?

Изменить: мне сказали использовать ComponentFactoryResolver, но я не понимаю, как я могу использовать это для правильного отображения html. Может ли кто-нибудь оказать дополнительную помощь?

Edit2: я анализирую 'htmlStringContent' через канал очистки, прежде чем отображать его на [innerHtml]

transform(v: string) : SafeHtml {
  return this._sanitizer.bypassSecurityTrustHtml(v); 
} 

Edit3: в основном этот вопрос спрашивает, возможно ли отображать HTML из свойства объекта в angular 2/ionic 2, сохраняя при этом функциональность (щелчка) на нем. Я также открыт для ответов на обходные пути.


person alsco77    schedule 25.10.2016    source источник
comment
Таким образом, событие клика не будет работать. У вас есть компонент создания, и тогда вы сможете генерировать событие клика, как уже показано в одной из ваших ссылок.   -  person micronyks    schedule 25.10.2016
comment
@micronyks, но мне все равно придется использовать [innerHtml] для представления html-контента?   -  person alsco77    schedule 25.10.2016
comment
Я понимаю это, но, как и angular1, angular2 не имеет службы $compile, поэтому вы можете сделать это, используя componentFactoryResolver.   -  person micronyks    schedule 25.10.2016
comment
@micronyks Не совсем уверен, как это использовать .. не могли бы вы быть более подробным?   -  person alsco77    schedule 25.10.2016
comment
С древовидной структурой я не уверен, но когда шаблон имеет угловой контекст, вы должны использовать только CFR.   -  person micronyks    schedule 25.10.2016
comment
@micronyks Я не могу найти документацию по CFR, которая помогла бы мне решить эту проблему.   -  person alsco77    schedule 26.10.2016
comment
Вы можете использовать stackoverflow.com /вопросы/34784778/   -  person Günter Zöchbauer    schedule 26.10.2016


Ответы (2)



Если я правильно понимаю, вам нужно использовать динамические шаблоны и компилировать их во время выполнения. Если это так, вам нужно использовать компилятор angular:

@Component({
    selector: 'my-app',
    template: `
      <h1>Angular 2 Dynamic Component</h1>
      <template #container></template>
    `
})
export class AppComponent implements AfterContentInit, OnDestroy {
  private dynamicComponentRefs: ComponentRef[] = [];

  @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;

  constructor(private resolver: ComponentFactoryResolver,
              private compiler: Compiler) {}

  ngAfterContentInit() {
    let html = `
      <div>Always Visible</div>
      <div [hidden]="clause1">Hidden because of clause1 = true</div>
      <div [hidden]="clause2">Visible because of clause2 = false</div>
      <button type="button" (click)="buttonClicked()">Click me!</button>
      <div *ngIf="clicked">You clicked the button!</div>
    `;

    this.compiler.compileModuleAndAllComponentsAsync(createDynamicComponent(html))
        .then((mwcf: ModuleWithComponentFactories) => {
          let factory: ComponentFactory = mwcf.componentFactories.find(cf => 
            cf.componentType.name === 'DynamicComponent');
            this.dynamicComponentRefs
              .push(this.container.createComponent(factory));
        });
  }

  ngOnDestroy() {
    /* Make sure you destroy all dynamically created components to avoid leaks */
    this.dynamicComponentRefs.forEach(dcr => {
      dcr.destroy();
    });
  }

}

export function createDynamicComponent(html: string): Type<NgModule> {
  @Component({
    template: html,
  })
  class DynamicComponent {
    private clause1: boolean = true;
    private clause2: boolean = false;
    private clicked = false;

    buttonClicked() {
      this.clicked = true;
    }
  }

  @NgModule({
    imports: [CommonModule],
    declarations: [DynamicComponent],
  })
  class DynamicComponentModule {}

  return DynamicComponentModule;
}

В основном вам нужно динамически создать компонент и модуль, который его объявляет (например, через функцию) и передать ему шаблон в качестве аргумента. Затем вы можете вызвать compileModuleAndAllComponentsAsync() на модуле и получить нужную вам фабрику компонентов. Затем нужно отобразить его в DOM с помощью метода ViewContainerRef.createComponent().

Вот рабочий плункер: компонент динамического шаблона

Однако имейте в виду, что на данный момент этот подход можно использовать только с JIT-компиляцией. В компиляции AOT компилятор angular недоступен, и попытка его использования вызовет ошибку.

person Siri0S    schedule 04.11.2016