Reputation: 41
I am using behaviour subject and subscribe it in ts file.
trying to access the variable outside the subject block in ts file..
code for service.ts
private messageSource = new BehaviorSubject<any>(null);
constructor(
private apiService: ApiService
) {
}
// try
sendMessage(value: any) {
this.messageSource.next(value);
}
get getMessage() {
return this.messageSource.asObservable();
}```
now in TS file
ngOnInit() {
// this.viewUser = this.commonService.getMessage;
this.subscription = this.commonService.getMessage.subscribe(value => {
this.viewUser = value;
console.log(this.viewUser)
});
console.log(this.viewUser)
}
file console showing data.. but in second console , it is showing inital value of behaviour subject ie. null how can i get data outside the block
Upvotes: 0
Views: 953
Reputation: 4127
The simplest way to share data between sibling components by using TypeScript Setter and Getter instead of an Observable (which we must need to unsubscribe to prevent memory leak).
service.ts
_message: string;
set message(value: any) {
this._message = value;
}
get message() {
return this._message;
}
Set value from any component or service etc
this.commonService.message = 'some message';
And finally get the value without any subscription etc
ngOnInit() {
this.viewUser = this.commonService.message
console.log(this.viewUser);
}
Upvotes: 0
Reputation: 2199
Observables
are new way of handling async
requests. Subscriptions to Observables
are quite similar to calling a function
. But where Observables
are different is in their ability to return multiple values called streams
.Observables not only able to return a value synchronously, but also asynchronously.
In your case first the second console.log(this.viewUser)
is executed which is not initialized with the subscription and because of that you get null
first and then your subscription
evaluated. You can try this:
app.component.ts
ngOnInit() {
this.subscription = this.commonService.getMessage.subscribe(value => {
this.viewUser = value;
console.log(this.viewUser)
this.logViewUser();
});
}
logViewUser() {
console.log(this.viewUser)
}
console.log(this.viewUser)
Upvotes: 0
Reputation: 31125
Normally I would say there is no way to access an asynchronous variable (this.viewUser
here) synchronously.
However since you're using BehaviorSubject
, there exists a cheeky way to access it's value synchronously. If you notice, a BehaviorSubject
is created with a default value. In other words it always holds some value. RxJS provides a getValue()
function (or the value
getter - they are synonymous) to synchronously get the value held by the BehaviorSubject
. So in your case you could do the following
Service
public messageSource = new BehaviorSubject<any>(null); // <-- public
constructor(private apiService: ApiService) { }
sendMessage(value: any) {
this.messageSource.next(value);
}
get getMessage() {
return this.messageSource.asObservable();
}
Component
ngOnInit() {
this.viewUser = this.commonService.messageSource.getValue();
console.log(this.viewUser);
}
There are multiple disadvantages
It's considered an anti-pattern and usually frowned upon since you lose the async behavior.
Say the statement this.viewUser = this.commonService.messageSource.getValue();
is executed before the function sendMessage()
in the service, you'd be assigning the value null
to the variable this.viewUser
. And the variable won't be updated automatically akin to the async behavior with a subscription.
Upvotes: 0
Reputation: 7733
What's inside your subscribe
is running asynchronously.
this.subscription = this.commonService.getMessage.subscribe(value => {
this.viewUser = value;
console.log(this.viewUser)
});
console.log(this.viewUser) // <-- This is running before what's inside subscribe
You could use the async
await
to make the function async and whats inside sync :
this.viewUser = await this.commonService.getMessage.asPromise();
The function containing this code should be async
.
Upvotes: 0