Angular5 как открыть сиденав с компонентом загруженным на лету внутри - PullRequest
0 голосов
/ 23 мая 2018

я создал это на stackblizhttps://stackblitz.com/edit/angular-z85mgj

Мне бы хотелось узнать, как загрузить компонент fly внутри sidenav, я имею в виду:
из NavigatoComponent Я хочу открыть sidenav по щелчку с компонентом Acomponent загружен (объявлен в NavigatorModule ), вместо страницы 1 я хочу открыть sidenav с загруженным Bcomponent (объявлен в Page1Module ) и изsubpage1 sidenav откроется с Ccomponent (объявлено в Page1Module ).Я хотел бы избежать случая ngswitch внутри компонента sidenav, основанного на значениях, прошедших через события sidenavService .Поэтому я подумал создать компонент на лету или передать ссылку на компонент через службу.

Возможно ли это сделать?это хорошая практика или есть другие способы лучше?

Кроме того, как вы думаете, модули маршрутизации настроены правильно?а также, есть ли лучший способ открыть / закрыть sidenav из компонентов, импортированных в разные модули, без использования Rxjs Subject в сервисе?

1 Ответ

0 голосов
/ 23 мая 2018

Есть довольно много вопросов, которые вы задали.Вот решение, если вы заинтересованы в динамической загрузке компонентов до SideNav контента.

sidenav.service.ts

import {
  Injectable,
  Component,
  ComponentRef,
  NgModule,
  NgModuleRef,
  Injector,
  Compiler,
  ViewContainerRef
} from '@angular/core';

import {Subject} from 'rxjs';

@Injectable()
export class SidenavService {
  public subject = new Subject<string>();

  private sidenavVCRef: ViewContainerRef;

  constructor(private compiler: Compiler, private injector: Injector,
              private ngModuleRef: NgModuleRef<any>) {}

  // getSidenavVCRef() { return this.sidenavVCRef; }

  setSidenavVCRef(vc: ViewContainerRef) { this.sidenavVCRef = vc; }

  publish(eventName: string, componentName?: string) {
    console.log("qua", this.subject, eventName);
    if (componentName) {
      this.loadComponent(componentName).then(() => {
        this.subject.next(eventName);
      });
    } else {
      this.subject.next(eventName);
    }
  }

  // Create component on the fly, and insert to the view container
  private loadComponent(name: string): Promise<boolean> {

    // create component and module on the fly
    const template = `<span>I am ${name}</span>`;
    const tmpComp = Component({template : template})(class {});
    const tmpModule = NgModule({declarations : [ tmpComp ]})(class {});

    // compile the created module and component,
    // and get a hold of it with a componentRef
    return new Promise(resolve => {
      this.compiler.compileModuleAndAllComponentsAsync(tmpModule)
          .then(factories => {
            // Compiler will return all factories for corresponding components
            // to be created
            // Just take the first one as it is the only one.
            const f = factories.componentFactories[0];

            // create (component) view from its factory and return componentRef
            const compRef = f.create(this.injector, [], null, this.ngModuleRef);

            // just detach all previous views from view container
            this.sidenavVCRef.detach();
            // insert it to its view container
            this.sidenavVCRef.insert(compRef.hostView);

            resolve(true);
          })
          .catch(error => { console.log(error); });
    });
  }
}

navigator.component.ts

import {
  Component,
  OnInit,
  ViewChild,
  ViewContainerRef,
  AfterViewInit
} from '@angular/core';
import {SidenavService} from '../sidenav.service';
@Component({
  selector : 'app-navigator',
  templateUrl : './navigator.component.html',
  styleUrls : [ './navigator.component.css' ]
})
export class NavigatorComponent implements OnInit,
    AfterViewInit {
  @ViewChild('sidenav') sidenav;

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

  constructor(private sidenavService: SidenavService, ) {}

  ngOnInit() {
    this.sidenavService.subject.subscribe((value) => {
      console.log("value:", value);
      switch (value) {
      case 'open':
        this.openSidenav();
        break;
      case 'close':
        this.closeSidenav();
        break;
      default:
        break;
      }
    });
  }

  ngAfterViewInit() {
    // set sidenav view container reference at as the first thing when view is
    // available
    this.sidenavService.setSidenavVCRef(this.vc);
  }

  private openSidenav() { this.sidenav.toggle(); }

  private closeSidenav() { this.sidenav.close(); }

  openSN() { this.sidenavService.publish('open', 'Component A'); }
}

навигатор.component.html

<mat-sidenav-container class="example-container">
    <mat-sidenav #sidenav mode="side" opened="false">
        Sidenav content
        <div #vcDynamicComp></div>
    </mat-sidenav>
    <mat-sidenav-content>
        <mat-toolbar>My App
            <span style=" flex: 1 1 auto"></span>
            <button mat-raised-button routerLink="/page1">Page1</button>
            <button mat-raised-button routerLink="/page2">Page2</button>
            <button mat-raised-button color="primary" (click)="openSN()">Open sidenav</button>
        </mat-toolbar>
        <main>
            <router-outlet></router-outlet>
        </main>
    </mat-sidenav-content>
</mat-sidenav-container>

Вот рабочий пример при стеке блиц

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...