简体   繁体   English

访问结构指令中的组件实例

[英]Access component instance in structural directive

I have a structural directive and I need to access instance of a component to which it has been applied to. 我有一个结构指令,我需要访问它已应用于的组件的实例。

There is an open issue with few options / hacks that work for plain directives, but not structural. 有一个开放的问题,很少有选项/黑客适用于普通指令,但不是结构性的。

https://github.com/angular/angular/issues/8277 https://github.com/angular/angular/issues/8277

You cannot add a component to another like that - however you can call them dynamically. 您不能将组件添加到另一个组件 - 但您可以动态调用它们。

Attached is an actual example of building a dynamic component via directive. 附件是通过指令构建动态组件的实际示例。 Which is ultimately what I think you want. 这最终是我认为你想要的。 However you cannot cascade components - that doesn't work. 但是,您无法级联组件 - 这不起作用。 I made some comments so you know what is going on, the other thing is when you go this route you will have to go to your local module and add a line for entry components. 我做了一些评论,所以你知道发生了什么,另一件事是当你走这条路线时,你将不得不去你的本地模块并为入口组件添加一行。

import { footerComponent } from './../../uicomponents/footer/footer.component';
import { headerComponent } from './../../uicomponents/header/header.component';
import { cssloaderComponent } from './../../uicomponents/cssloader/cssloader.component';

// tslint:disable-next-line:max-line-length
import { Directive, Input, OnInit, ViewContainerRef, AfterViewInit, OnDestroy, ComponentFactoryResolver, OnChanges } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { Subject, Observable, from } from 'rxjs';
import { filter } from 'rxjs/operators';
import { viewsdataservice } from 'src/app/services/viewsdata.service';
import { contentoutletComponent } from 'src/app/uicomponents/contentoutlet/contentoutlet.component';

@Directive({
  selector: '[pagebuilderdirective]'
})
export class pagebuilderDirective implements OnInit, OnDestroy, AfterViewInit, OnChanges {
  @Input() pagebuilderdirective: Observable<any>;
  private onDestroy$ = new Subject<boolean>();
  components;
  route0$;

  private elRef: any;

  readonly templateMapper = {
    css: cssloaderComponent,
    contentoutlet: contentoutletComponent,
    header: headerComponent,
    footer: footerComponent
  };

  constructor(
    public viewContainerRef: ViewContainerRef,
    private factory: ComponentFactoryResolver,
    private router: Router,
    private vds: viewsdataservice
*********we created a view data service to connect to google firebase/firestore to get our particular data - we subscribe to the data and use it. ********
  ) {
    this.elRef = viewContainerRef;
    router.events.subscribe((event) => {
      if (event instanceof NavigationEnd) {
        this.pagebuilderdirective.subscribe(data => {
          if (data) {
            this.loadComponent(data);
          }
        });
      }
    });
  }

  ngOnInit(): void {


  }

  ngOnChanges() {
  }

  ngOnDestroy() {
    this.elRef.clear();
  }

  ngAfterViewInit() {

    this.pagebuilderdirective.subscribe(data => {
      if (data) {
        this.loadComponent(data)
      }
    });
  }

  checker() {
    return this.pagebuilderdirective;
  }

  loadComponent(data: any) {
    this.elRef.clear();

    const route0 = this.vds.route_arr;
    const components: Array<any> = data[0].components;

    const componentmanifest=this.vds.flatten(data[0].componentsmanifest);
     ***** we found that it was easier to write a service that flattens our array, you probably won't need this. *******
    const orgdata = data[0];
    if (components) {
      const filtered = from(components).pipe(
        filter(component => {
          if (
            component.published === true && componentmanifest.pagespublished === route0 || component.da === "pb") {
              return component;
*****we set a boolean on our components and create a manifest (array of actual components and where they go to, the final indicator was if it was a parent component or child, we did this speficially so we could segment components down to page and subcomponent(child components) and assign that data to them. If you don't do this, any components listed (assuming one has multiple directives, will generate or kick an error)******
          } 
        })
      );

      filtered.subscribe(
        (component) => {
        const componentFactory = 
******component factory is your friend here, we call the components via name to match the entry components ********
this.factory.resolveComponentFactory(this.getComponentByAlias(component.name));
        // this.elRef.clear();
        const componentRef = this.elRef.createComponent(componentFactory);
        (<any>componentRef.instance).data = orgdata;
      });
    }
    // this.elRef.clear();
  }

  private getComponentByAlias(alias: string) {
    return this.templateMapper[alias];
  }

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

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