Angular2依赖注入:创建对最初未定义的属性的引用

时间:2016-08-19 11:39:50

标签: angular typescript

我试图使用Angular2依赖注入来获取对#g; Webgl2RenderingContext"的引用,这是未定义的,直到我调用createContext函数。有没有办法将引用注入几个不同的服务类,然后在HTMLCanvasElement可用后设置值?

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

2 个答案:

答案 0 :(得分:1)

我认为对于Observables来说这是一个很好的例子,并且可能在你的情况下来自RxJS的Subject,因为它允许通过一个emit调用发送给多个观察者。在下面的代码中,我使用了一个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...
            }
        )
    }
}

答案 1 :(得分: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]);