AFSpawnService icon indicating copy to clipboard operation
AFSpawnService copied to clipboard

Doesn't work with EntryComponents defined in a lazy loaded module.

Open derekkite opened this issue 7 years ago • 0 comments

https://github.com/angular/angular/issues/14324

It has to do with the entry components of a lazy loaded module not being appended to the list in the app ComponentFactoryResolver.

The solution is the caller to inject it's ComponentFactoryResolver and Injector and pass it to the service. The ReflectiveInjector will need replacing at one point, but later.

`createLazyComponent(type: any, lcfr: ComponentFactoryResolver, inj: Injector, vcr: ViewContainerRef, context?: any) {

    const childComponent = lcfr.resolveComponentFactory(type);
    let refInjector = ReflectiveInjector
        .resolveAndCreate([{provide: type, useValue: type}], inj);
    let componentRef = vcr.createComponent(childComponent, 0, refInjector);

    let unsubs = this._wireOutputs(childComponent, componentRef, context);
    // Turn the provided inputs into an observable (if not already an observable)
    let observableSymbol = getSymbolObservable(window);
    let context$;
    if (context && context[observableSymbol]) {
        context$ = context;
    } else {
        context$ = new BehaviorSubject(context);
    }
    
    // Subscribe to the new observable for updated input values
    unsubs.push(context$.subscribe(() => {
        childComponent.inputs.forEach(i => {
            if (context) {
                if (context[i.propName] !== undefined) {
                    componentRef.instance[i.propName] = context[i.propName];
                }
            }
        })
    }));
    
    // This function will be returned to the caller, to be called when their context is destroyed
    let detach = () => {
        !vcr && this.appRef.detachView(componentRef.hostView);
        componentRef.destroy();
        unsubs.forEach(u => u());
    };
    
    // This function will be returned to the caller, to be called when there are new values for the inputs
    let next = (data) => {
        if (context$ === context) {
            throw `When passing an observable as a context, you cannot call the \`.next\`
             function from the result. If you wish to update the values in your context,
             send the data through the observable that you
             passed in as the context.`;
        }
        context$.next(data);
    };
    
    return {
        detach,
        next,
    }
}
`

derekkite avatar Aug 20 '17 04:08 derekkite