Ionic 3.6 - IonicPage loading too fast so my var aren't initialized

Hello everyone,
i’ve fixed my old problem ([Solved] Ionic 3.6 - Problem with IonicPage url loading the wrong page) but by fixing that another problem came out.

When i refresh the page or copy and paste the link on a new tab, the page is loaded too fast, my variable are sitll not initialized so i get errors (while if i inspect the code and look at the var, they are ok since after the error the var are filled with the right value).

I think the problem is that IonicPage load before the app.component.ts (since i tryed to move the code of var inizialization before the platform ready and it didn’t work) so it fail to find filled variable…

I can’t even link my online test since online it works correctly, but locally it returns the errors…

Does anyone have the same issue? Have found any solution?

app.component.ts

import { Component, ViewChild  } from '@angular/core';
import { Platform, Nav, AlertController, LoadingController } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import * as firebase from 'firebase';
import { AuthService } from '../providers/auth-service';
import { ChannelService } from '../providers/channel-service';
import { PushService } from '../providers/push-service';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  @ViewChild(Nav) nav: Nav;
  rootPage: any;
  loading: any;

  constructor(platform: Platform, public authService: AuthService, public channelService: ChannelService, public pushService: PushService, public alertCtrl: AlertController, public loadingCtrl: LoadingController, public statusBar: StatusBar, public splashScreen: SplashScreen) {
    firebase.initializeApp({});

    let self = this;

    platform.ready().then(() => {
      const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
        if(user) {
          firebase.database().ref('/users/' + user.uid).once('value').then((result) => {
            authService.initializeUser(result.val(), result.getKey());
            channelService.loadChannels();
            self.rootPage = 'TabsPage';
            unsubscribe();
          });
        } else {
          self.rootPage = 'LoginPage';
          unsubscribe();
        }
      });

      if(platform.is('cordova')) {
        statusBar.styleDefault();
        splashScreen.hide();

        pushService.initCordova();
      } else {
        pushService.initWeb();
      }
    });
  }
}

new.ts

import { Component } from '@angular/core';
import { IonicPage, NavController, LoadingController } from 'ionic-angular';
import { AuthService } from '../../providers/auth-service';

@IonicPage({
  priority: 'high',
  segment: 'news',
})
@Component({
  selector: 'page-news',
  templateUrl: 'news.html'
})
export class NewsPage {
  loading: any;
  username = "";

  constructor(public navCtrl: NavController, private authService: AuthService, private loadingCtrl: LoadingController) {
    let info = this.authService.getUserInfo();
    this.username = info.username;
  }
}

news.module.ts

import { NgModule } from '@angular/core';
import { NewsPage} from './news';
import { IonicPageModule } from 'ionic-angular';

@NgModule({
  declarations: [NewsPage],
  imports: [IonicPageModule.forChild(NewsPage)],
  entryComponents: [NewsPage]
})
export class NewsPageModule { }

No, that’s impossible. It may, however, load before Platform.ready() resolves, and you have to deal with that. I make it a habit to declare initializers for every controller property that is referenced from templates, such that at construction time the template can render without error.

2 Likes

What are the exact variables causing problems and what are the exact errors you are getting?

Well i actually do it too, i guess? What u are saying is that u initialize all the variable in the controller before the html is shown…

I’ve 2-3 calls on platform ready that initiaize all my variable inside the User class (and other classes too). The problem here is that it show first the html (i guess) then it call my function that initialize everything.

In the News example the error is on username (since i show it on the html part):

Uncaught (in promise): TypeError: Cannot read property 'username' of null 
TypeError: Cannot read property 'username' of null at new NewsPage

This actually means that you are trying to access a username property of an object that doesn’t exist (yet).

This would match the error message. Does getUserInfo resolve immediately? Or could info actually be null? Or return null?

I often think in terms of programming by contract. If you are going to do what you are doing on that second line, authService.getUserInfo() is contractually obligated to return a defined object. If getUserInfo() can’t hold up that end of the bargain, then anybody that calls it must use something like a truthiness check before blindly dereferencing its return value.

Here the strange thing i found out while testing this…

I placed a console.log(info) after let info; on my browser console, first it return null (since info is null) then it say that there’s an error on username (since is null) after that error all my init function start and it run again console.log(info) returning the right value (the user).

I guess this mean that the code run two time, first without my inti function and after with my init function… i think the problem is mine or something is bothering with IonicPage, making the page load once then reload with all the functions?

So you mean to check a promises and if it return the right value all fine, if it return error or null i should initialize the variable in another way? Something like this?

I can’t make any sense out of this.

The error message is telling you exactly what is going wrong. Inside the constructor of NewsPage, you are attempting to access a username property of a null variable. I don’t know whose fault that is: either NewsPage's constructor has to be able to handle the case where authService.getUserInfo() returns null, or authService.getUserInfo() must always return a defined object. You have to decide which way you want to go on that, by defining more rigidly the contract surrounding getUserInfo()'s return value.

1 Like

Yea i know where the error come from and how i could “fix” it, the problem here is another one:

  1. When i load the page normally, all the variable are initialized and working fine
  2. If i reload the page or copy and paste the link to a new tab, first it load the page WITHOUT the starting function, then it reload it again WITH the starting function

So the main issue here is that the first time it load the page he find the variable null and he can’t work on them alas giving the error since the var are empty.

When i wrote yesterday that i can’t post the link from my online test since it was working fine, i was wrong, because he has the error too (while looking at the browser console), but after that he show the page correctly since the variable are filled

As you were saying before it could be possible that IonicPage deeplink start off before the platform.ready, that’s why it first load the page without the starting function filling my variable and shortly after running and filling all my var needed on the app. I will move in this direction and see if i can find a solution.

I don’t know how many times I can restate this, but no, that is emphatically not the main issue. The main issue is that you are not programming by contract, and that makes your programs unreliable. If you want to eat at a busy restaurant at a certain time, you have two choices: make a reservation and show up then, or show up an hour before you want to eat and wait. If you show up without a reservation at the time you want to eat, things will not go well. That is exactly what you are doing here.

Do not spend time trying to figure out when various external sources are doing what. It won’t be consistent, and any program that relies on any such fragility will be of bad quality. Make a decision and either make your service return something that is always reliable (IMHO the better choice, in general), or bulletproof its clients when it is not.

2 Likes

You example is spot on with the issue here, i’m making a reservation for the 14:00 and they pretend me to beign there at 13:00 then saying they aren’t ready to get me and to wait 1 hour.

I’m sorry but personally your answer sound rude, as programmer i’m born to know how things work behind the curtian otherwise i wouldn’t be working as one. Is in our instict to know how things work, since if something dosn’t work out it mean two things, is your code or the thing working behind the scenes doing soemthing strange. I know i’m not perfect so it can totally be my code, but i’ve got experience on my shoudler too.

As i said i undertood what you said and i know what i can do to change the code, the issue is that i can rewrite all my code to wait for every variable to be ready before the app start (which i actually do, just need some fixing in some places), still if this was a bug of IonicPage since it’s beign just recently beign implemented with the new version, shouldn’t i post about it and see if it’s my or his problem? Telling a programmer to bliding work on the code of someonelse without knowing how it work isn’t a good way to deal with problems;
Anyway i’m not trying to start a war or anything, just saying what i think on the matter.

As i stated before, even if i moved my init function before platform ready the error would still occur, since IonicPage is running before that. If that is wanted or a bug i don’t know, since the documentation isn’t helping regarding this question, that’s why i’m here asking even if i’m used to just find out myself… this time i’m working on a personal project so i feel i can ask around if i’m lost.

No need to apologize, and you’re perfectly welcome to consider it rude. I would instead use “critical”, and you are right that I am criticizing your programming. I’m not here to coddle your feelings; I’m here to improve your code.

In this case, I cannot disagree with you more strongly. It is absolutely, 100% your responsibility to write code that is robust in the face of “the thing working behind the scenes doing something strange”.

I’m going to assume that by "bliding’ you mean “blindly”. I also may be misinterpreting what you mean here, and if that is the case, I apologize. If you do in fact mean that it is inappropriate for me to lecture you on how to interact with frameworks, then my opinion is that you are gravely mistaken. Again, this comes down to contracts. Anything that is publicly documented in an API is reliable. Anything else is not, and it is your responsibility to cope with anything that comes out of that.

If you are dependent on this, your app is broken.

1 Like

I looked at that.

First time the “/#/menu/home/news” loads info is null.
Then it is loaded again and is not null.

There is no code in news.ts that would trigger a “reload”.

But there is in your app.component.ts: You set the rootPage after the user is logged in.

Could you please add console.log before these setting of rootpage? Then this would be much easier to trace (without using the debugger)

This is happening:
When the page loads, it starts the authentication process in the background. First run through the constructor fails because no auth info is there, then auth finishes and reloads the whole thing by setting the rootPage, constructor again, is now successful as your method returns a valid info.

Solution: Make sure that news.ts can handle not having an info by a) setting it up not as null, but as an object that has the required properties or b) don’t try to access info before auth was actually successful in the first place. c) Would be to return a Promise or Observable so that it is only trying to do stuff when it is actually there.

IonicPage or update to Ionic 3.6 has absolutely nothing to do with it.

It is a common error to make, that’s why it wasn’t really hard for me to analyze right now - I make them each time I work with this async stuff and so am now quite competent in sniffing them out :wink:

What @rapropos said was all true, although as usual he didn’t spend much cycles to make it understandable and digestible to you. We all have to live with that. I am probably more fine with it than you are right now. But that’s fine, too - and if he was right the 5th time after you posted something, you will come to appreciate it. (I certainly do)

1 Like

I was facing OP’s exact same problem and your comment made me rethink the way I was coding. Thank you for this valuable advice.

Hi

Below is my console log after i reload page

This happened because the page loads before app.component loads, so the property is null.

Please advice on how i can get the displayname without error even the app.component loads later than my page