简体   繁体   English

通过Wordpress REST API渲染Angular组件

[英]Render Angular component via Wordpress REST API

I have an Angular 5 app that is using content from Wordpress via the REST API. 我有一个Angular 5应用程序,它通过REST API使用Wordpress中的内容。

What I'd like to do is insert a component tag in the Wordpress content editor and then have it appear in the app. 我想做的是在Wordpress内容编辑器中插入一个组件标签,然后将其显示在应用程序中。

For example, I created a simple component <app-some-component></app-some-component> 例如,我创建了一个简单的组件<app-some-component></app-some-component>

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-some-component',
  template: `
  <h1>I am a component!</h1>
  `
})
export class SomeComponent implements OnInit {
  constructor() {}

  ngOnInit() {}
}

and added it directly to the host component template to test it, it works. 并将其直接添加到主机组件模板进行测试,即可正常工作。

Now, this host component is also pulling content from Wordpress via the rest API. 现在,此主机组件还通过其余API从Wordpress中提取内容。 So I try adding <app-some-component></app-some-component> in the Wordpress content editor. 因此,我尝试在Wordpress内容编辑器中添加<app-some-component></app-some-component>

The tag "comes through" to the Angular app and I see the tag in the HTML when inspecting the page. 标签“通过”到Angular应用程序,在检查页面时,我在HTML中看到该标签。 But the content of the component does not render, so I guess it is not being processed by Angular. 但是组件的内容无法渲染,因此我想它不是由Angular处理的。

I am using a Safe Pipe to allow HTML in the component, as in 我正在使用安全管道来允许组件中的HTML,如下所示:

        <div class="card"
           *ngFor="let vid of videolist">
        <img class="card-img-top img-fluid"
             [src]="vid.better_featured_image.source_url"
             alt="Video Thumbnail">
        <div class="card-body">
          <h4 class="card-title"
              [innerHTML]="vid.title.rendered"></h4>
          <p class="card-text"
             [innerHTML]="vid.content.rendered | safe: 'html'"></p>
        </div>
        <div class="card-footer">
          <a routerLink="/videos/{{vid.id}}">View Video</a>
        </div>
      </div>

The pipe's code is 管道的代码是

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';

@Pipe({ name: 'safe' })

// see https://medium.com/@swarnakishore/angular-safe-pipe-implementation-to-bypass-domsanitizer-stripping-out-content-c1bf0f1cc36b
// usage: <div [innerHtml]="htmlSnippet | safe: 'html'"></div>
export class SafePipe implements PipeTransform {
  constructor(protected sanitizer: DomSanitizer) {}

  public transform(value: any, type: string): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
    switch (type) {
      case 'html':
        return this.sanitizer.bypassSecurityTrustHtml(value);
      case 'style':
        return this.sanitizer.bypassSecurityTrustStyle(value);
      case 'script':
        return this.sanitizer.bypassSecurityTrustScript(value);
      case 'url':
        return this.sanitizer.bypassSecurityTrustUrl(value);
      case 'resourceUrl':
        return this.sanitizer.bypassSecurityTrustResourceUrl(value);

      default:
        throw new Error(`Invalid safe type specified: ${type}`);
    }
  }
}

What do I need to do to get the component to render? 我需要怎么做才能渲染组件?

This is just writing plain html to the dom, youu need Angular to actually render that as components. 这只是将纯HTML编写到dom,您需要Angular才能将其实际呈现为组件。 For that you have some alternatives: 为此,您有一些选择:

You can write a component with a lot of *ngIf or *ngSwitch directives: 您可以编写带有许多*ngIf*ngSwitch指令的组件:

import { Component, Input } from '@angular/core'

@Component({
  selector: 'app-blog-post',
  template: `
    <article>
      <ng-container *ngFor="let data of datas">
        <app-component-1 [data]="data" *ngIf="data.type === '1'"></app-component-1>
        <app-component-2 [data]="data" *ngIf="data.type === '2'"></app-component-2>
        <app-component-3 [data]="data" *ngIf="data.type === '3'"></app-component-3>
      </ng-container>
    </article>
  `,
  styleUrls: ['./blog-post.component.scss'],
})
export class BlogPostComponent {
  @Input() datas: any[]
}

You can use the Angular Dynamic Component Loader to render the components programmatically: 您可以使用Angular Dynamic Component Loader来以编程方式渲染组件:

import {
  Component,
  ComponentFactoryResolver,
  Input,
  OnInit,
  ViewChild,
  ViewContainerRef,
} from '@angular/core'
import { Component1 } from '../component-1/component-1.component'
import { Component2 } from '../component-2/component-2.component'
import { Component3 } from '../component-3/component-3.component'

@Component({
  selector: 'app-blog-post',
  template: `
    <article>
      <app-blog-post-micro-component *ngFor="let data of datas" [data]="data"></app-blog-post-micro-component>
    </article>
  `,
})
export class BlogPostComponent {
  @Input() datas: any[]
}


@Component({
  selector: 'app-blog-post-micro-component',
  template: '<ng-container #container></ng-container>',
})
export class BlogPostMicroComponent implements OnInit {
  @Input() data: any[]
  @ViewChild('container', { read: ViewContainerRef }) private container: ViewContainerRef

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

  ngOnInit() {
    // Prepare to render the right component
    const component = this.getComponentByType(this.data.type)
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component)

    // Clear the view before rendering the component
    const viewContainerRef = this.container
    viewContainerRef.clear()

    // Create component
    const componentRef = viewContainerRef.createComponent(componentFactory)
    componentRef.instance.data = this.data
  }

  private getComponentByType(type: string) {
    const componentMapByType = { '1': Component1, '2': Component2, '3': Component3 }
    return componentMapByType[type]
  }
}

You should read this article to learn more: Angular Dynamic Components 您应该阅读本文以了解更多信息: Angular Dynamic Components

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM