Hi!
I have created a Provider used for retrieving data from a JSON file.
@Injectable()
export class JsonProvider {
public plan:Array<any>=[];
constructor(public http: HttpClient) {
this.http.get('../assets/data/arbeidsplan.json').subscribe(data => {
this.plan.push(data);
});
}
}
And in the typescript file of my homePage, I have the following constructor
constructor(public navCtrl: NavController, public locationTracker: LocationTracker, public http: HttpClient, public jsonProvider : JsonProvider) {
this.jsonProv = jsonProvider;
console.log(this.jsonProv.plan)
}
The problem is that the page loads before the data is retrieved, and therefore “undefined” is written to the console, and I get the error “Can’t read … of undefined” when the data from the JSON file is used in another method.
How can I make sure that things are done in the correct order?
This is the wrong question. Instead ask “how can I make it so that I don’t care what happens in what order?”.
Well, presumably your proximate problem is that you have some property that is being referenced from a template. If you always make sure to initialize all arrays and objects, even if to something as mundane as []
or {}
, that should eliminate “cannot read property ‘foo’ of undefined” errors. Once the asynchronous task has completed, Angular’s change detection will handle the rest.
If you have a function B that needs the result of function A, then look into the mergeMap
operator. The way I think about this is that there are two kinds of functions: producers and consumers. Producers should never be calling subscribe
, and should generally have the first word in them be return
. Consumers should be given exactly what they are looking for (which often makes more work in the providers, but it’s worth it).
So most every producer looks something like:
return this.http.get(url).pipe(
map(foo => mogrify(foo)),
mergeMap(bar => frotzify(bar)));
…every consumer looks like:
thingies = [];
this.provider.getThingies().subscribe(t => this.thingies = t);
…and that way you get no errors in templates such as:
<div *ngFor="let thingy of thingies"></div>
Thank you! Had forgotten to initialize one of the arrays.