簡體   English   中英

動態加載現有組件Angular 2 Final Release

[英]Load existing components dynamically Angular 2 Final Release

我正在嘗試在最終版本2.0.0中動態加載組件。

使用RC5我使用以下代碼加載:

創建一個指令來加載控件:

import {
  CheckboxComponent, CheckboxListComponent,DatePickerComponent
} from '../components/';

@Directive({
      selector: '[ctrl-factory]'
    })
    export class ControlFactoryDirective implements OnChanges {
      @Input() model: any;

      constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) {
      }

      create(cp) {
        this.resolver.resolveComponent(cp)
          .then(factory => {
            const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
            this.vcRef.createComponent(factory, 0, injector, []);
            let ch = this.vcRef.createComponent(factory, 0, injector, []).instance;
            ch.model = this.model;
        });
      }

      ngOnChanges() {
        if (!this.model) return;

        switch (this.model.type) {
          case 'checkbox':
            this.create(CheckboxComponent);
            break;
          case 'checkboxlist':
            this.create(CheckboxListComponent);
            break;
          case 'datepicker':
            this.create(DatePickerComponent);
            break;
          default:
            break;
        }
      }
    }

然后在我的頁面中加載該指令,如下所示:

<div ctrl-factory *ngFor="let child of page.childrens" [model]="child"></div>

但是從rc5更新到2.0.0最終版本后,解析器不再存在,被編譯器取代。

我發現大量的地方顯示如何使用不同的代碼加載它,但所有那些太復雜,我無法使其工作。

以此為例: 我如何使用/創建動態模板來使用Angular 2.0編譯動態組件?

它看起來更具體到那個場景,我只需要加載組件並設置一個名為model的@Input。

我嘗試的一件事是我必須為每個組件動態創建一個模塊,然后將組件添加到它。 但后來我遇到的問題是該組件被設置在多個模塊中,嘗試在某些地方刪除不起作用。

顯示的代碼的主要部分,我從這個鏈接: http//blog.lacolaco.net/post/dynamic-component-creation-in-angular-2-rc-5/

並做了一些改變。

更新

我設法使用以下方法使其工作:

create方法已更改為

private create(cp) {
    @NgModule({
      imports: [BrowserModule, ControlsModule],
      declarations: []
    })
    class DynamicModule {}

    this.compiler.compileModuleAndAllComponentsAsync(DynamicModule)
      .then(({componentFactories}) => {
        const compFactory = componentFactories.find(x => x.componentType === cp);
        const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
        const cmpRef = this.vcRef.createComponent(compFactory, 0, injector, []);
        cmpRef.instance.model = this.model;
      });
  }

我找到的大多數地方,設置創建組件並將其設置為DynamicModule,問題是當你已經在另一個模塊中聲明相同的組件時,angular會抱怨。 在我的情況下,解決方案是導入我的ControlsModule,我的所有控件都被導出。

更新

NgComponentOutlet是在4.0.0-beta.3中引入的.https ://github.com/angular/angular/commit/8578682

即將推出的NgComponentOutlet

我看到兩個選項:

1)使用ComponentFactoryResolver

它使用已經生成的工廠,代碼如下所示:

constructor(private vcRef: ViewContainerRef, private resolver: ComponentFactoryResolver) { }
create(comp) {
  const factory = this.resolver.resolveComponentFactory(comp);
  const compRef = this.vcRef.createComponent(factory);

  (<any>compRef).instance.model = this.model;
}

在這種情況下,我們必須在模塊的decorator中的declarationsentryComponents屬性中定義動態組件

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, DynamicComponent ],
  entryComponents: [DynamicComponent],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

2)使用編譯器

在這種情況下,我們只能使用compiler.compileModuleAndAllComponentsAsync運行模塊compiler.compileModuleAndAllComponentsAsync ,然后從componentFactories數組中查找組件。 您的指令可能如下所示:

constructor(private vcRef: ViewContainerRef, private loader: DynamicLoaderService) { }

create(comp) {
  this.loader.createComponentFactory(comp).then(factory => {
     const compRef = this.vcRef.createComponent(factory);

    (<any>compRef).instance.model = this.model;
  })
}

DynamicLoaderService是一個加載和存儲組件工廠的全局服務。

@Injectable()
export class DynamicLoaderService {
  constructor(protected compiler: Compiler) {}

  private resolveCompHelper$ = new Subject<any>();
  private cache = new Map<string, ComponentFactory<any> | number>();

  public createComponentFactory(type: string) : Promise<ComponentFactory<any>> {
    let factory = this.cache.get(type);

    // if factory has been already loading
    if(factory === 1) {
      return new Promise((resolve) => {
        // waiting compilation of factory
        const subscriber = this.resolveCompHelper$.subscribe((data) => {
          if(type !== data.type) return;
          subscriber.unsubscribe();
          resolve(data.factory);
        });   
      });
    } 
    // factory exists in cache
    if (factory) {
      return new Promise((resolve) => resolve(factory));
    }

    const comp = typeMap[type];
    // factory startes loading
    this.cache.set(type, 1);
    return new Promise((resolve) => {
      this.compiler.compileModuleAndAllComponentsAsync(createComponentModule(comp))
        .then((moduleWithFactories: ModuleWithComponentFactories<any>) =>  {
            factory = moduleWithFactories.componentFactories
              .find(x => x.componentType === comp);
            this.cache.set(type, factory);
            this.resolveCompHelper$.next({ type, factory});

            resolve(factory);
        });
    });
  }
}

Plunker示例

希望它能幫到你!

根據指令看到這個選項對我很有用,但我根據組件找到了符合我需求的選項: https//www.ag-grid.com/ag-grid-angular-aot-dynamic-components /

快樂的編碼!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM