I try to get an array from backend using http.get. In response I have: ["Item1","Item2","Item3"].
constructor(private http:Http){
this.http.get('api').subscribe(
data => {this.array = data}
);
}
The code above makes this.array = undefined.
What should I use to get an array?
Please try to console first whether you are getting data or not , also you need to use .map (If you are not using httpClient) before subscribe like this
constructor(private http:Http){
this.http.get('api')
.map(data => {
console.log(data.json());
reuturn data.json();
)
.subscribe(data => {this.array = data});
}
You are accessing values outside subscribe and because get is asynchronous, you are not getting value in it.
constructor(private http:Http){
this.http.get('api').subscribe(
data => {this.array = data}
console.log(this.array); <== here it won't be undefined
);
}
If you want to access array in component you can use getter as:
get Array() {
return this.array;
}
in component you can access this by this.service.Array
Solution2
You can use async pipe.
Related
I'm new to NodeJS and are only familiar with Java. I'm trying to create a file that creates objects based on a database and adds them to an array. This array I want to be able to export so that I can use it throughout the whole program, but when I try to export the array it doesn't work. I've tried googling and understanding but haven't come across anything that was helpful unfortunately.
I hope that someone can help me understand
I've tried calling module.exports after the ".then" call, but it just returns an empty array because its async.
I've also tried calling module.exports = teams inside the .then call but it didn't work neither.
var teams = [];
function assignTeamsToClasses() {
return new Promise((resolve, reject) => {
getAllTeamsInDb((teamList) => {
teamList.forEach((aTeam) => {
let newTeam = new Team(aTeam['teamid'], aTeam['teamname'], aTeam['teamrank']);
teams.push(newTeam);
});
resolve();
});
})
}
assignTeamsToClasses().then(() => {
module.exports = teams;
});
main.js
var teams = require('./initialize.js');
console.log(teams);
I expect it to return all teams that are in the database. I know that array is not empty when called within the ".then" call, but the export part does not.
Simple
the sequence require() + console.log() is synchronous
assignTeamsToClasses() is asynchronous, i.e. it updates teams at some unknown later point in time.
You'll have to design your module API to be asynchronous, e.g. by providing event listener interface or Promise interface that clients can subscribe to, to receive the "database update complete" event.
A proposal:
module.exports = {
completed: new Promise(resolve =>
getAllTeamsInDb(teams => {
const result = [];
teams.each(aTeam =>
result.append(new Team(aTeam.teamid,
aTeam.teamname,
aTeam.teamrank)
)
);
resolve(result);
})
),
};
How to use it:
const dbAPI = require('./initialize.js');
dbAPI
.completed
.then(teams => console.log(teams))
.catch(error => /* handle DB error here? */);
Every caller who uses this API will
either be blocked until the database access has been completed, or
receive result from the already resolved promise and proceed with its then() callback.
I'm here trying to refactor a working app I made which get events from a Database (in order to be later displayed on a scheduler).
So here I am using an #observable events variable in which I'm setting an array I get using a POST request to my database.
But when I'm later trying to show in console what is now in my variable, instead of the array of strings I should have, I now have a Proxy object...
Can someone help me to understand what should I do in order to get back my array instead of the Proxy object ?
Thanks in advance !
PS : here's a bunch of the code
#observable events = [];
loadAgendaData = (event) => {
let viewModel = new SchedulerData('2017-12-18', ViewTypes.Week, false, false, {});
axios.post('http://localhost:5002/api/getCreneaux', {
id_grpe: event.value
}).then((res) => {
res.data.forEach((element) => {
element.start = moment.unix(element.start).format("YYYY-MM-DD HH:mm:ss");
element.end = moment.unix(element.end).format("YYYY-MM-DD HH:mm:ss");
})
viewModel.setEvents(res.data)
console.log(res.data); // this shows the Array
this.events = res.data; // giving this.events the value of the array
})
}
anotherFunction = (event) => {
console.log(events); // this unfortunately shows a Proxy object
}
I'm doing an Ionic project and I'm getting a little bit frustrated whit promises and '.then()' although I've read a lot of documentation everywhere.
The case is that I have one provider with the functions loadClients and getWaybills.
The first one gets all the clients that have waybills and the second one gets all the waybills from one concrete client.
loadClients() {
return new Promise(resolve => {
this.http.get('http://localhost/waybills?fields=descr1_sped&idUser='+ this.id)
.map(res => res)
.subscribe(data => {
this.data = data.json();
resolve(this.data);
});
});
}
// GET WAYBILLS
getWaybills(client) {
return new Promise(resolve => {
this.http.get('http://localhost/waybills/?stato=0&idUser='+ this.id +'&descr1_sped='+ client)
.map(res => res)
.subscribe(data => {
this.data = data.json();
resolve(this.data);
});
});
}
On the other hand, on the component welcome.ts I have a function loadWaybills which is called on the view load and is executing the following code, my idea is to get all the clients and then get the respective waybills of each one. Then I'll take just of the ones that are defined.
The problem is that on the second .then() instead of getting the variable data I'm getting just undefined... I've understood that if you put a synchronous code inside .then() can be properly executed and work with the "data" which is the result of the promise. Why am I getting this undefined?
loadWaybills() {
//We first load the clients
this.waybills.loadClients()
.then(data => {
this.waybill = data;
var preClients = this.waybill;
this.clients = [];
//Here we're deleting duplicated clients and getWaybills of them)
for (let i = 0; i < preClients.length; i++) {
if (this.clients.indexOf(preClients[i].descr1_sped) == -1) {
this.waybills.getWaybills(preClients[i].descr1_sped)
.then(data => {
**//Here we'll check if the clients has waybills or not**
this.clientWaybills[i] = data;
this.clients.push(preClients[i].descr1_sped)
});
}
}
});
}
It is hard to say because we don't know what the API is meant to return. For example, there may be a missing field somewhere from the first GET and now for the second one, it returns as undefined sometimes. If it only returns undefined sometimes, a simple solution to this, would be to check that the value is defined before assigning it to the variable.
If it always returns as undefined and shouldn't, try to debug the code and make sure that the values are present before the second .then.
I have two rest calls I need to make. Rest call 2 depends on rest call 1. And I want to store each result in the service before proceeding. Then I want to return an observable to the component that calls rest call 1 so the component can subscribe in case of issues.
code from service:
login(username: string, password: string): Observable<AuthAccess> {
// rest call 1
return this.getAuthClient()
.flatMap(res => {
this.client = res.body;
// rest call 2
return this.authenticate(username, password)
.flatMap(access => {
this.userAccess = access.body;
return Observable.of(this.userAccess);
});
});
}
I can get this to chain correctly, but the component that is calling this and subscribing to the call will show an undefined response. Any help on this would be greatly appreciated as I cannot find responses on this exact use case.
Live working example.
Use a map operator (and the lettable operatos sintax), instead of chain a new flatMap.
login(username: string, password: string): Observable<any> {
// rest call 1
return this.getAuthClient()
.pipe(flatMap(res => {
this.client = res.body;
// rest call 2
return this.authenticate(username, password)
.pipe(map(access => {
this.userAccess = access.body;
return this.userAccess;
}));
}));
}
Basically what i try to do is to hit my API once and save the result inside global variable in my Service, and then share and modify this value in my parent and child component with two helpers functions.
repairs.service.ts
public myItems:any[];
public GetRepairs = ():Observable<any> => {
this.headers = new Headers();
this.headers.set('Authorization', 'Bearer' + ' ' + JSON.parse(window.localStorage.getItem('token')));
return this._http.get(this.actionUrl +'repairs'{headers:this.headers})
.map((res) => {return res.json();
}).map((item) => {
let result:Array<any> = [];
if (item.items) {
item.items.forEach((item) => {
result.push(item);
});
}
this.myItems = result;
return this.myItems;
});
};
public GetItems() {
return this.myItems;
};
public UpdateItems(data:any[]) {
this.myItems = data;
};
And then in my main component i do
repairs.component.ts
export class RepairsComponent implements OnInit {
public myItems:any[];
constructor(private _userService:UserService,
private _RepairsService:RepairsService,
public _GlobalService:GlobalService) {
}
ngOnInit() {
this._userService.userAuthenticate();
this.getAllItems();
}
private getAllItems():void {
this._RepairsService
.GetRepairs()
.subscribe((data) => {
this._RepairsService.UpdateItems(data);
},
error => console.log(error),
() => {
this.myItems = this._RepairsService.GetItems();
});
}
}
This work just fine but when i try to invoke GetItems() in child component i get undefinded. I try to do it inside constructor and ngOnInit with the same result.
child.component.ts
export class ChildComponent {
private items:any[] = [];
constructor(private _RepairsService:RepairsService,
private _Configuration:Configuration) {
this.items = this._RepairsService.GetItems();
// undefinded
}
ngOnInit() {
this.items = this._RepairsService.GetItems();
// undefinded
}
}
From what i can see in the limited amount of code you shared, it would seem you are trying to get the items before the http get call finishes and saves the data. I think a better design pattern would be to make the GetItems() function also an observable or promise, and check if the data is there, if not call the http get call, and once that completes send the data back to the different components that need it.
As #MSwehli mentioned with async code execution you can't rely on the order of code lines. In this code:
ngOnInit() {
this.items = this._RepairsService.GetItems();
// undefinded
}
the async code in GetItems(); is scheduled for later execution into the event queue and then continued with the sync code. The scheduled code will be executed eventually but it's not determined when. It depends on the response of the server in this example.
If you return a Promise you can use .then(...) the chain the execution so that your code is only executed when the async execution is completed.
There are two errors/inconsistencies in your code:
userAuthenticate() call followed with getAllItems() call. These calls are async, user is not yet authenticated by the time getAllItems() is called, getAllItems will fail.
Solution here is to chain calls using rxjs flatMap:
//assuming userAuthenticate returns Observable
userService.userAuthenticate().flatMap(()=>{
return repairsService.GetRepairs();
}).subscribe(..process repairs..);
getAllItems() is called nearly at the same time as GetItems(). In most cases it fails also, because previous http request is not completed when GetItems() is called.
In my opinion early initialization is not necessary here, use service directly:
//ChildComponent
ngOnInit() {
this._RepairsService.GetRepairs().subscribe(..do anything with list of repairs i.e. assign to bindable property..);
}
You could add console.log statements in each part of the code to see the order of events in your app.