Skip to content

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

@derekkite

Description

@derekkite

angular/angular#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,
    }
}
`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions