Search code examples
angulartypescriptdependency-injectionng-component-outlet

Angular 7: injection with dependencies for ngComponentOutlet


I need to use some kind of @Input() decorator for my ngComponentOutlet.

But seems that Angular hasn't this feature. Instead, all things that I want to pass inside my outlet components should be provided via Injector.

And it's fine if I want to initiate the thing I want provide to inside injectable class. But I need to dive deeper and provide some kind of observable variable (Observeble<number> type for example) at creation Injector step. But I can't to get observable variable inside outlet component. Getting following error: NullInjectorError: No provider for [object Object]!.

Here is an example of code, I got this pattern from angular docs (angular.io/api/common/NgComponentOutlet) and modified a little:

@Injectable()
export class Greeter {
    suffix$: Observable<number> = null;
    constructor(private _suffix$: Observable<number>) {
        this.suffix$ = this._suffix$;
    }
}

@Component({
    selector: 'complete-component',
    template: `Complete: {{ greeter.suffix$ | async }}`
})
export class CompleteComponent {
    constructor(public greeter: Greeter) {
        this.greeter.suffix$.subscribe(data => console.log('data', data));
        // not working
    }
}

@Component({
    selector: 'ng-component-outlet-complete-example',
    template: `
        <ng-container *ngComponentOutlet="CompleteComponent; 
                                        injector: myInjector;"
    })
export class NgTemplateOutletCompleteExample {
    CompleteComponent = CompleteComponent;
    myInjector: Injector;

    suffix$: Observable<number> = of(3);

    constructor(injector: Injector) {
        this.myInjector =
            Injector.create({providers: [{provide: Greeter, deps: [this.suffix$]}], parent: injector});
    }
}

So how can I get and subscribe into this $suffix variable inside outlet component.

P.S. If I provide NgTemplateOutletCompleteExample into the deps array and get NgTemplateOutletCompleteExample.suffix$ inside injectable component Greeter - it will work. But the thing is I have a lot of NgTemplateOutletCompleteExample components and this thing invalid in my case.


Solution

  • The main thing is that Injector - is a static injector. So, to provide any data inside component oultet (or get out any callbacks) I must use useValue instead deps.

    Contructor in NgTemplateOutletCompleteExample should be like this:

    constructor(injector: Injector) {
        this.myInjector =
            Injector.create({providers: [{provide: Greeter, deps: [], useValue: {suffix$: this.suffix$}], parent: injector});
    }