I follow this guide, and i try to do something similar at Unrelated Components: Sharing Data with a Service paragraph
Data Service:
#Injectable()
export class MyDataService{
private messageSource = new BehaviorSubject(null);
currentMessage = this.messageSource.asObservable();
constructor(private http: HttpClient) {
setInterval(() => { this.changeMessage(this.resultFromRestCall()); }, 10 * 1000);
}
changeMessage(message: object) {
this.messageSource.next(message);
}
resultFromRestCall(){
const json;
this.http.get<object>(myApiUrl).subscribe(res =>
json['data'] = res['data'] //this is an example
);
return json;
}
Component:
export class MyComponent implements OnInit {
constructor(private dataservice: MyDataService) {}
ngOnInit() {
this.dataservice.currentMessage.subscribe(
message => {this.handleVarChange(message); }
);
}
handleVarChange(message) {
console.log(message.data);
}
With this code i got "undefined" in handleVarChange log
Instead of calling this.handleVarChange(message); in subscribe I write console.log(message) i got my result correctly.
So, my question is if it's possible use the value coming from data service in some function of my component.
Thanks in advance
With:
resultFromRestCall(){
const json;
this.http.get<object>(myApiUrl).subscribe(res =>
// takes x amount of time to populate json
json['data'] = res['data'] //this is an example
);
// executed instantly after above request has been called
return json;
}
You are returning json before it has been populated, since the request is asynchronous.
Instead you can flip it around a bit, and call resultFromRestCall() first, and when you get the response, then call changeMessage():
setInterval(() => {
this.resultFromRestCall().subscribe((data) => {
this.changeMessage(data);
});
}, 10 * 1000);
where resultFromRestCall simply returns an observable:
resultFromRestCall(){
return this.http.get<object>(myApiUrl);
}
Also remember to clearInterval in OnDestroy!
DEMO
Omit the .data in handleVarChange:
Instead of
handleVarChange(message) {
console.log(message.data);
}
write
handleVarChange(message) {
console.log(message);
}
Related
I am new to Angular and struck with subscribe method. I need to trigger subscribe first in which initialization of property is done. Please help me with this.
Here is my code..
json.service.ts
#Injectable({providedIn: 'root'})
export class JsonService {
constructor(private http: HttpClient) {}
//This fetch the json present in assets folder
url: string = `${window.location.origin}/assets/urls-list.json`;
getRestJson() {
this.http.get(url);
}
url.setting.ts
#Injectable({providedIn: 'root'})
export class UrlService {
fetchedJson: Array<any>;
constructor(private service: JsonService) {
this.fetchingJsonFromService();
}
fetchingJsonFromService() {
this.service.getRestJson().subscribe(
response => {
this.fetchedJson = response;
});
}
private static getValue(key: string) {
// use the key do some stuff with "this.fetchedJson"
and return only that value back to getServiceUrl()
return something;
}
public static getServiceUrl(key:string) {
const result = UrlService.getValue(key);
return result;
}
}
From debugging this code realized that "getValue()" is called first and the "this.fetchedJson" is undefined. Then the call goes to "fetchingJsonFromService()" where fetchedJson gets initialized which is too late. Kindly help me to solve this issue. It would be of great help.
"getServiceUrl(key)" - is called by multiple services throughout the application
Thanks a lot!! 😊
As getRestJson() is async you'll need to execute getValue() when it's response has arrived, which You can simply do by calling getValue() inside your fethcingJsomFromService()
fetchingJsonFromService() {
this.service.getRestJson().subscribe(
response => {
this.fetchedJson = response;
this.getValue();
});
}
private getValue() {
// do some stuff with "this.fetchedJson" and return only that value to other method
}
I need to detect the component change.
First check my code which work.
The problem here is that this is called init and it is unnecessary to call all the time ... you should only call for a change or when its data ( response ) is okay.
ngOnInit() {
this.calendarData();
}
detectChangeUser(){
this.sharedService.selectedUserType$.subscribe(
data => {
if(data === 'changed-view-user-trigger'){
this.calendarData();
this.calendarUsers();
}
},
err => console.log(err)
)
}
I need to detect only when data has a response.
Check also my service.
export class SharedService {
public latestViewSwither: any = null;
selectedUserType$ = new BehaviorSubject<any>(this.latestViewSwither);
training$ = this.selectedUserType$.asObservable();
constructor(
private http: HttpClient
) { }
swithViewChanged(e){
this.latestViewSwither = e;
this.selectedUserType$.next(e);
}
}
only to detect when data has value.
data === 'changed-view-user-trigger' don't worry about this. I send it from another component only a string...this is not important.
Only important thing is any hook which detects change... I am also trying with ngAfterViewChecked but my software crashes after this...
You can use BehaviorSubject for this. The BehaviorSubject has the characteristic that it stores the “current” value. This means that you can always directly get the last emitted value from the BehaviorSubject.
See the example below:
import * as Rx from "rxjs";
const subject = new Rx.BehaviorSubject();
// subscriber 1
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
subject.next(Math.random());
subject.next(Math.random());
// subscriber 2
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
subject.next(Math.random());
console.log(subject.value)
// output
// Subscriber A: 0.24957144215097515
// Subscriber A: 0.8751123892486292
// Subscriber B: 0.8751123892486292
// Subscriber A: 0.1901322109907977
// Subscriber B: 0.1901322109907977
// 0.1901322109907977
I would try something like that to solve the problem.
service:
export class SharedService {
public latestViewSwither: any = null;
selectedUserType$ = new BehaviorSubject<any>(this.latestViewSwither);
training$ = this.selectedUserType$.asObservable();
constructor(private http: HttpClient) { }
swithViewChanged(e){
this.latestViewSwither = e;
if (!!e) {
this.selectedUserType$.next(e);
}
}
}
I am trying to use a DataService property myData that is waiting for callback. But it is undefined when I call in DataComponent. How can I access and use it there?
export class DataService {
public myData;
constructor(private http: HttpClient) {
this.load().then((data) => {
this.myData = data
})
}
load() {
return new Promise((resolve) => {
this.http.get('https://reqres.in/api/users').subscribe(
(res: any) => {
console.log(res.data)
resolve(res.data)
},
(error) => {
console.log(error);
}
)
})
}
}
export class DataComponent implements OnInit {
constructor(private dataService: DataService) {
this.prepareData();
}
prepareData() {
console.log(this.dataService.myData)
}
ngOnInit(): void {
}
}
Here is the source code: https://stackblitz.com/edit/angular-ivy-kbpdpo
You are running into a race condition since this is an asynchronous function.
This change works: https://stackblitz.com/edit/angular-ivy-vf3llg
Consider reading up on https://angular.io/guide/http
Personally, I just have services return raw data and manipulate it elsewhere, but if needed you can tap into the response as I have shown i the updated example.
This question and answer are probably really a duplicate of this question...
What are pipe and tap methods in Angular tutorial?
your load() method is asynchronous, that means that it can return the response after 2 hours, so it will execute your callback after 2 hours, and you are asking myData synchronously which means that you are asking it right now, so it won't work.
you have to wait until the answer is returned, in your code there is no chance to accomplish this, so either remove yourData field and just subscribe it into the component, or create BehaviorSubject and emit value to the component
i have a class and a function named getStationDetail and i want to send a request to server and get the value and save it to dataFromServer variable
and i want to return that but when i cal that i get empty array
export class StationService {
dataFromServer: any = [];
constructor(private rest: RestService) { }
getStationsDetail() {
this.rest.sendRequest('GET', 'station', null).subscribe(
value => {
this.dataFromServer = value['Station'];
// return this.dataFromServer;
},
);
return this.dataFromServer;
}
}
and i cal it
export class StationComponent implements OnInit(){
mm: any;
ngOnInit() {
this.mm = this._stationService.getStationsDetail().subscribe();
console.log(this.mm);
}
}
but map not worked? how to cal subscribe?
When a request is sent to server then cursor doesn't stop to execute next lines of codes if we want some operations after receiving the response from server then we use observables and do these methods in subscribe(). so for examples:
ngOnInit() {
this._stationService.getStationsDetail()
.subscribe(stationDetails => {
console.log('Response array:' , stationDetails);
});}
I have this method:
export class PeriodicData {
public checkForSthPeriodically(): Subscription {
return Observable.interval(10000)
.subscribe(() => {
console.log('I AM CHECKING');
this.getData();
});
};
public getData(): Observable<MyObject> {
let objects: MyObject[] = this.filterData();
return Observable.from(objects);
}
public filterData(): MyObject[] {
let someData;
// someData = filter(...) // logic to filter data
return someData;
}
}
Now I subscribe to getData() in another class:
class Another {
constructor(private periodicData: PeriodicData ) {
this.periodicData.getData().subscribe(obj => {
console.log('IN ANOTHER CLASS');
});
}
}
This is not working. The "IN ANOTHER CLASS" is not being logged. Am I missing something ?
If you tested this only with live TypeScript transpiler, then it doesn't throw an error when you don't specifically include Observable and the from operator (even though I don't know why).
I added to the top of app.component.ts and it works now:
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/from';
See your demo on plnkr.co: http://plnkr.co/edit/uVnwG3bo0N8ZkrAgKp7F