Inject the instance of a component in a service
Asked Answered
M

2

8

For a any good reaon, I am trying to inject my component into a service, but I obtain a new instance of it. I reproduce my problem with this code :

This component will display the instance number in h1 :

@Component({
    selector: 'my-component',
    template: '<h1>Instance number {{count}}</h1>'
})
export class MyComponent {
    private static i = 0;               /* <-- counts the myComponent's instances here */
    private _count: number = i++;
    get count(): number {return this._count}
}

The Service will log the instance number in console:

@Injectable()
export class MyService {
    constructor(myComponent: MyComponent) {
        console.log("Instance number " + myComponent.count);
    }
}

The main component will inject the component in a view and the service :

@Component({
    selector: 'app-root',
    template: '<my-component></my-component>',
})
export class AppComponent {
    constructor(service: MyService) {
    }
}

I'm using angular-cli, my app.module.ts looks :

@NgModule({
  declarations: [
    AppComponent,
    MyComponent
  ],
  imports: [
    BrowserModule,
  ],
  providers: [MyComponent, MyService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Currently, my console displays Instance number 0 and my html display Instance number 1. How can I obtain the same instance ?

Thanks for reading me

Midshipman answered 1/12, 2016 at 14:5 Comment(0)
V
13

This doesn't work. If your application has several instances of this component, which one should it inject.

What you can do is for example to inject the service to the component and make the component pass itself to the service

@Component({
    selector: 'my-component',
    template: '<h1>Instance number {{count}}</h1>'
})
export class MyComponent {

    constructor(service: MyService) {
      service.myComponent = this;
    }

    private static i = 0;
    private _count: number = i++;
    get count(): number {return this._count}
}

It's better to not pass components to services but instead use observables to notify components about events and let components do the rest.

For more details see https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Vltava answered 1/12, 2016 at 14:9 Comment(3)
Why is it better? When you pass components to services, as least after a few months you still understand what your code was doing.Barraza
@QianChen In Angular the philosophy is that you manipulate the state and the view (Angular components) just render that state to maintain clean dependencies in only one direction. If you pass components around this way you make components part of the state. In the long run this will result in a mess. If you don't follow this Angular philosophy anyway, then passing components to a service won't make much difference.Rone
I understand what you said. In practice, I found what making a mess are the observables.Barraza
M
3

Thanks for your answer @Günter. I post my new component with service subscription here for anybody interested in :

The observable service :

@Injectable()
export class MyService implements OnDestroy {
    private _count:number = 0;
    public numberSource = new Subject<number>();
    private numberObservable: Observable<number> = this.numberSource.asObservable().share();

    public count() {this.numberSource.next(this._count++);}
    public subscribe(s: any) {return this.numberObservable.subscribe(s);}
    public ngOnDestroy() {this.numberSource.complete();}
}

A subcriber component (I can have many) :

@Component({
    selector: 'my-component',
    template: `
<button (click)="increment()" >Count !</button>
<div *ngFor="let n of numbers">{{n}}</div>
`
})
export class MyComponent {
    private numbers: number[] = [];
    constructor(private myService: MyService) {
        myService.subscribe((n:number) => this.numbers.push(n));
    }
    increment() {
        this.myService.count();
    }
}

I don't know if I'm clear, but this is exactly what I was looking for. Thanks !

Midshipman answered 1/12, 2016 at 15:52 Comment(1)
Did you got the answer for it?Creosol

© 2022 - 2024 — McMap. All rights reserved.