我试图使用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]
}
];
答案 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]);