0

I'm trying to pass a specific instance of a Service down to components that are inside of an ngx-bootstrap modal.

However since the modal isn't a child of the component that is launching the modal it's unable to resolve the Service dependency if I try to inject it.

I am able to pass the service as data when opening the modal and then as an input for the child modal of that and it works, but that doesn't seem like the correct way to do this.

I don't want to make the service providedIn: 'root' or provided in the module since it contains persistent data over the life the component providing it as well as having functions using that data.

I looked into passing an injector when opening the modal but it seems like ngx-bootstrap doesn't support that option. The only example I found of passing a custom injector was for ng-bootstrap.

Passing the Service as data to the modal seems okay if I'm not able to pass an injector to the modal but I would still like to be able to inject it into children of the base modal component.

Stackblitz example(passing service as data and then as an input):

https://stackblitz.com/edit/ngx-modal-25zz6k?file=src/app/app.component.ts

Main component:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [AppService],
})
export class AppComponent {

  modalRef: BsModalRef;
  constructor(private modalService: BsModalService, private appService: AppService, private injector: Injector) {}

  openModal() {
    this.appService.increment();
    this.modalRef = this.modalService.show(SomeComponent,  {
      initialState: {
        title: 'Modal title',
        appService: this.appService,
      },
    });
  }
}

Modal Component:

export class SomeComponent implements OnInit {
  appService: AppService;
  title;
  constructor(
    public modalRef: BsModalRef,
  ) {
  }

  ngOnInit() {

  }

}

Child of SomeComponent:

export class ChildComponent implements OnInit {
  constructor(
    public modalRef: BsModalRef,
  ) { }

  @Input() appService: AppService;

  count: number = 0;

  ngOnInit() {
    this.count = this.appService.num;
  }
}

Ideally I would like it to work in a similar way that ng-bootstrap does it where I can pass a custom injector to the modal similar to:

this.modal.open(SomeComponent, {
  injector: Injector.create([{
    provide: AppService, useValue: this.appService
  }], this.injector)
}) 

Being able to add the AppService to the injector of SomeComponent would be okay as well but from what I tried the only ways to inject it would be to perform it at the time the component is constructed and the AppService isn't defined until ngOnInit is run in SomeComponent.

I feel like something like this would work as well in SomeComponent:

constructor(@Inject(forwardRef(() => returnObservableForAppService)) appServiceObsv: Observable<AppService>) { }

But injecting an Observable instead of the actual service seems about the same as just passing it as an input.

Asguard
  • 91
  • 8

1 Answers1

0

How about using Injector to create an instance of the service, which you can import to the components you need it:

const injector = Injector.create({
  providers: [
    { provide: AppService, deps: [] },
  ]
});

export const appService = injector.get(AppService);

Then in the components needed, import appService and use it:

import { appService } from '....';

// ...

openModal() {
  appService.increment();
  this.modalRef = this.modalService.show(SomeComponent, {
    initialState: {
      title: 'Modal title'
    },
  });
}

import the same for ChildComponent and...

ngOnInit() {
  this.count = appService.num;
}

Your forked STACKBLITZ

AT82
  • 71,416
  • 24
  • 140
  • 167
  • Wouldn't this approach do the same thing as providedIn: 'root' on the service? https://stackblitz.com/edit/ngx-modal-ciu2xh?file=src/app/app.component.ts – Asguard Sep 24 '19 at 14:39
  • Maybe I misunderstood. I though you meant that you want a separate instance of that service shared in just these components. That is not what you want? – AT82 Sep 24 '19 at 16:48
  • Well if you for example want to create a new instance when entering main component... then create a new instance of the service there always when component is created using `Injector`? Trying to understand the use case here so maybe I'm completely misunderstanding :D – AT82 Sep 24 '19 at 16:50