Доступ к экземпляру компонента в структурной директиве - PullRequest
0 голосов
/ 15 мая 2019

У меня есть структурная директива, и мне нужен доступ к экземпляру компонента, к которому он был применен.

Существует открытая проблема с несколькими опциями / хаки, которые работают для простых директив, но не являются структурными.

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

1 Ответ

0 голосов
/ 15 мая 2019

Невозможно добавить один компонент к другому, однако вы можете вызывать его динамически.

В приложении приведен пример построения динамического компонента с помощью директивы. Что в конечном итоге то, что я думаю, вы хотите. Однако вы не можете каскадировать компоненты - это не работает. Я сделал несколько комментариев, чтобы вы знали, что происходит, другое дело, когда вы идете по этому пути, вам нужно будет перейти к локальному модулю и добавить строку для компонентов входа.

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];
  }
...