Reputation: 283
Hello I am basically new to Angular, Here I'm trying to access a boolean variable from service. A boolean variable with value true, I've declared in service. Based on some logic I'm going to change that service variable to false. That particular variable I'm using in several components. So I'm facing problem like, Initial value which I've assigned true is coming to all components where I've used, but after changing the value that is not reflecting in all components. Service class like this:
@Injectable()
export class MyService {
running: boolean = true;
}
Component 1:
export class FirstComponent {
constructor(private myService: MyService) { }
check(){
this.myservice.running = false;
}
}
Component 2:
export class SecondComponent implements OnChanges {
running;
constructor(private myService: MyService) { }
ngOnChanges(){
this.running = this.myService.running;
console.log('running', this.running);
}
}
This is the how I'm going to change boolean value and accessing from service in different components. I'm not sure whether this is correct approach or not, please correct me.
Upvotes: 1
Views: 6819
Reputation: 60548
How about a simple answer:
1) If you are using Angular v6 or newer, then simply change your service to the following:
@Injectable(providedIn: 'root')
export class MyService {
running: boolean = true;
}
2) Search your system and ensure that the MyService
service is NOT listed in the providers
array of any module or component.
3) Change your component to use a getter. As others have said, the ngOnChanges
only works for @Input
properties.
export class SecondComponent {
running;
constructor(private myService: MyService) { }
get running(): boolean {
return this.myService.running;
}
}
That should do it!
When the value changes in the service, Angular's built-in change detection will pick up the change and reget the value, calling the getter and providing the updated value to the template.
You do not need a Subject
or BehaviorSubject
for something as straightforward as this. (Those are waaaay overused IMHO.)
I have a very simple (and similar) example here: https://stackblitz.com/edit/angular-simpleservice-deborahk
It uses a string, but would work exactly the same for a Boolean.
Upvotes: 5
Reputation: 359
At first, you must be sure that your service is singleton or at least have only one instance within scope of every component that you want to connect. The easiest way to achieve this is registering your service inside AppModule
inside providers
and nowhere else.
Second thing is that even if your service changes it's value, ngOnChanges
will not be called without reason. It needs to be called by change detector, but service does not cause running change detection in way you are trying to use it.
Instead of that you should share this value with Observable
.
export class TestService {
private readonly _messageSubject: Subject<boolean>;
get observable(): Observable<boolean> {
return this._messageSubject.asObservable();
}
constructor() {
this._messageSubject = new Subject<boolean>();
}
sendMessage(value: boolean): void {
this._messageSubject.next(value);
}
}
And now, every component which injects TestService
has access to two methods:
observable
which is getter. It returns observable from subject from your service.
sendMessage(value: boolean)
it sends your boolean message to every subscriber of _messageSubject
.
If you want to subscribe that subject (and access every change of service's value) you need to use your service that way:
TestService.observable.subscribe(value => { /* You can access your boolean value here with name "value" */});
Notice that Subject
shares something like changes of value, so callback inside subscribe
method will only execute after every next change of that value (it means it will be called after every next call of sendMessage(value: boolean)
method). If you want to access previous value (it means value which was latest before calling subscribe
) use BehaviorSubject
instead).
Upvotes: 1
Reputation: 8558
You could use BehaviorSubject
in your service. Then create an Observable
through asObservable
method of subject and then subscribe to that observable in whichever component you want.
Note that ngOnChanges
is changed to ngOnInit
.
In Service:
private runningSubject: BehaviorSubject<boolean> = new BehaviorSubject(true);
running = this.runningSubject.asObservable();
setRunning = (value: boolean) => {
this.runningSubject.next(value);
}
In First Component:
export class FirstComponent {
constructor(private myService: MyService) { }
check(){
this.myservice.setRunning(false);
}
}
Second Component:
export class SecondComponent implements OnInit {
running;
constructor(private myService: MyService) { }
ngOnInit(){
this.myService.running.subscribe((isRunning) => {
this.running = isRunning;
console.log('running', this.running);
});
}
}
Upvotes: 4