2016-08-19 39 views
0

我正在嘗試使用Angular2依賴注入來獲取對「Webgl2RenderingContext」的引用,該引用在我調用createContext函數之前是未定義的。有沒有辦法將引用注入多個不同的服務類,然後在HTMLCanvasElement可用後設置該值?Angular2依賴注入:創建一個最初未定義的屬性的引用

@Injectable() 
export class RenderContext { 
    get context() { return this.render_context; }; 

    constructor() { }; 

    createContext(canvas: HTMLCanvasElement) { 
     this.render_context = canvas.getContext("webgl2"); 
    }; 

    private render_context: WebGL2RenderingContext; 
} 

let get_context =() => { 
    return (render_context: RenderContext) => { 
     return render_context.context; 
    } 
} 

export const webgl2 = new OpaqueToken("webgl2"); 

export const webgl2_providers = [ 
    RenderContext, 
    { 
     provide: webgl2, 
     useFactory: get_context(), 
     deps: [RenderContext] 
    } 
]; 

回答

1

我覺得這是對觀測量一個很好的案例,並可能在你的情況從一個RxJS主題,因爲它允許通過一個發送調用發送到多個觀察員。在下面的代碼中,我使用ReplaySubject,因爲它允許您在上下文發送後訂閱主題,並仍然獲得最新的重新發送值(即,您不必在創建上下文之前確保所有訂閱都已到位,並且如果已經創建了上下文,則不必更改代碼)。

@Injectable() 
export class RenderContext { 
    //import from 'rxjs/ReplaySubject' Provide Observable functionality to 
    //multiple observers, and will replay last-set value so those that subscribe 
    //after context is set still get the context. 
    private __contextSubject : ReplaySubject = new ReplaySubject(1); 

    private render_context: WebGL2RenderingContext; 

    constructor() { }; 

    //not using property getter now since returning Observable, not actual value 
    getContext() : Observable { 
     return this.__contextSubject; 
    }; 

    //send value to subscribers 
    private emitContext() { 
     this.__contextSubject.next(this.render_context); 
    } 

    //after storing context, also emit it to subscribers 
    createContext(canvas: HTMLCanvasElement) { 
     this.render_context = canvas.getContext("webgl2"); 
     this.emitContext(); 
    }; 

} 

然後你會被直接注射RenderContext中(而不是通過一個工廠去)獲取上下文:

class OtherComponent { 
    constructor(renderContext: RenderContext) { 
     renderContext.getContext().subscribe(
      (context: WebGL2RenderingContext) => { 
       //do what you need to do with the context... 
      } 
     ) 
    } 
} 
0

一個解決方案,我發現是創建一個ReflectiveInjector作爲MainCanvas組件的屬性,在創建後爲「WebGL2RenderingContext」的初始值添加單個提供程序,然後創建一個具有所有其他類的子注入器,這些類依賴於上下文:

export class MainCanvas { 
    @ViewChild("canvas") canvas_ref: ElementRef; 

    private gl: WebGL2RenderingContext; 
    private context_injector: ReflectiveInjector; 
    private scene_renderer: SceneRenderer; 

    constructor(private render_context: RenderContext) {}; 

    ngAfterViewInit() { 
     this.render_context.createContext((<HTMLCanvasElement>this.canvas_ref.nativeElement)); 
     this.gl = this.render_context.context; 

     if (this.gl) { 

      let gl_provider = [{ provide: webgl2, useValue: this.gl }]; 

      this.context_injector = ReflectiveInjector.resolveAndCreate(gl_provider) 
       .resolveAndCreateChild([SceneRenderer, cube_providers, shader_providers]); 

      this.scene_renderer = this.context_injector.get(SceneRenderer); 
     } 
    } 
}; 

編輯:它也適用於不注射小孩注射器:

this.context_injector = ReflectiveInjector.resolveAndCreate([gl_provider, SceneRenderer, cube_provider, shader_providers]);