Okay, I just realize that we are doing an unnecessary thing: we are storing some data in device storage, then we are getting this same data just to populate in our variable. We can simplify this by populating the local variables the first time you get the geolocation (result: Geoposition). And again we need to resolve the getPositionUser() Promise before we run showMap():
Every time you type the word any in your code, you should feel anguish and guilt. I believe it’s really a crucial part of the issue here, because there are fundamentally three ways to deal with data that is going to arrive at some point in the future, which we have here:
A. Initialize it with a default and overwrite that when the true value comes in.
B. Initialize it with a sentinel and test for that sentinel value whenever used.
C. Never refer to it directly; always refer to it via a future.
Each of these strategies is viable, and, importantly, each lends itself to a different type signature. The ultimate type we’re going to get from the geolocation plugin is Geoposition, so our three strategies’ declarations look like this:
A. coords: Geoposition = { ...bunch of whatever defaults you like... };
B. coords: Geoposition | null = null;
C. coords$: Promise<Geoposition>; (initialize me in constructor once we have geolocation)
This makes the code somewhat self-documenting, and helps protect you from bugs.
Specifically, it’ll make showMap harder to write (and that’s a good thing).
In case A, showMap actually can just forget about all of the timing issues, but they get kicked upstairs to the caller, which has to know to call showMap again whenever the underlying coords changes. That’s ordinarily something you want Angular change detection to do, so A may not be the best choice here.
In case B, showMap has to check for null, and we still have the same calling timing problems we had in case A.
Which leaves case C, which I would prefer here, and is more or less what @leonardofmed is also suggesting. showMap then becomes responsible for waiting on coords$:
showMap(): void {
this.coords$.then(coords => {
// only inside here coords are reliable
}
}
This also scales well to using an Observable instead of a Promise when we want to start having multiple changes to coords over the life of the app.
My main point here is that aggressively typing everything in your app makes you think early about important design choices, and reinforces what choices you do make, so that you code consistently and defensively.
This is an imperative programming mindset, which doesn’t fit the reactive paradigm used in Ionic apps. You’re fighting the framework, which is a recipe for frustration.
You can make them look more synchronous, but it’s a fool’s errand. Instead, I think you will be much happier in the long run if you embrace reactive thinking.
Constructors should only be about putting the object into a sane initial state. Specifically, you should not be trying to interact with the DOM at all until you are certain the view hierarchy has been built. See the Angular lifecycle docs, especially ngAfterViewInit.