2016-09-24 6 views
8

最終リリース2.0.0でコンポーネントを動的にロードしようとしています。私は、次のコードを使用してロードされたRC5を使用して既存のコンポーネントを動的にロードする角度2最終リリース

は、コントロールをロードするディレクティブを作成します。次に

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最終リリースに更新した後、リゾルバはもはや存在せず、コンパイラに置き換えられました。

さまざまなコードを使用してロードする方法を示す場所がたくさん見つかりましたが、すべて複雑すぎて機能しませんでした。

は、例えばこれを持っ:How can I use/create dynamic template to compile dynamic Component with Angular 2.0?

をそれは、私はちょうどコンポーネントをロードし、モデルと呼ば@Inputを設定する必要があり、私の1、そのシナリオに、より具体的に見えます。

私が試していたことの一つは、各コンポーネントのモジュールを動的に作成し、コンポーネントを追加する必要があったことです。しかし、私は、コンポーネントが複数のモジュールに設定されていて、動作していない場所をいくつか削除しようとしているという問題がありました。

示すコードの大部分、私は、このリンクから入手:http://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2-rc-5/

や変更のカップルを行いました。

更新

私は、次のアプローチを使用して、それを動作させるために管理:

作成方法は、私が見つけた

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; 
     }); 
    } 

ほとんどの場所に変更されています、 Componentを作成してDynamicModuleに設定すると、別のモジュールで既に同じコンポーネントを宣言しているときに、angleがcomp約。私の場合のソリューションは、すべてのコントロールがエクスポートされている私のControlsModuleをインポートすることでした。

+0

私は同様のことを作成しようとしています。クラスとその講義リストを読み込むJSONファイルがあります。クラスはナビゲーションバーに追加され、講義は詳細ビューのリストとして追加されます。講義をクリックすると、コンポーネントが詳細ビューにロードされます。各講義ごとに異なるコンポーネントがあり、例のようなコンポーネントをロードするのではなく、各講義(およびルータアウトレット)のモジュールまたはルータリンクを作成することを考えていました。私はまだ物事を読み込むための最良の方法を理解しようとしています。 – Atieh

答えて

10

更新

すぐNgComponentOutlet

をカミング4.0.0-beta.3https://github.com/angular/angular/commit/8578682

でNgComponentOutletを導入して、私はそれを行うために2つのオプションを参照してください。

1)ComponentFactoryResolverを使用します。

それはすでに生成されたファクトリを使用してコードは次のようなものになります。私たちはモジュール

@NgModule({ 
    imports:  [ BrowserModule ], 
    declarations: [ AppComponent, DynamicComponent ], 
    entryComponents: [DynamicComponent], 
    bootstrap: [ AppComponent ] 
}) 
export class AppModule { } 
    のデコレータ内 declarationsentryComponentsプロパティで動的コンポーネントを定義する必要があり、この場合

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

  • Dynamically Creating Components With Angular 2.0
  • Plunker Example

2)ここで、我々は唯一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 Example

それはあなたのお役に立てば幸い!

+1

すばらしい説明をいただきありがとうございます。rango.ioから提供されているリンクは、私のコンポーネントが内部のいくつかのコントロールをレンダリングするモーダルなので、私がする必要があるものです。プランナーの例に感謝します。あなたは私をたくさん助けました。 Compiler上でComponentFactoryResolverを使用する利点はありますか?私は最初の方が簡単だと分かっています。 – Abner

+1

あなたはようこそ! – yurzui

+1

ちょっとYurzui何か他の上に優位?私はthr 2番目にキャッシングがあるのを見ました、私はちょっとそれを必要としません。私はそれらを再作成するときだけでなく、一旦動的なモーダルを閉じると、コンポーネントを破壊する方法を見つけ出そうとしていました。 – Abner

関連する問題