Typescript error: @viewChild undefined

Tried using the select () method in tabs.ts from the Ionic Tabs documentation. But it seems that when I tried to run it it said "select is undefined" and I found that my viewChild is actually empty / undefined when I tried console.log (tabs). Tried looking for the reason why viewChild is undefined but couldn't figure out why.

Link to ionic tabs documentation: https://ionicframework.com/docs/api/components/tabs/Tabs/

tabs.html

<ion-tabs #tabs>
  <ion-tab [root]="tab1Root" tabTitle="Request" tabIcon="alert"></ion-tab>
  <ion-tab [root]="tab2Root" [rootParams]="detailParam" tabTitle="Pending" 
   tabIcon="repeat"></ion-tab>
  <ion-tab [root]="tab3Root" tabTitle="Completed" tabIcon="done-all"></ion-
   tab>
  <ion-tab [root]="tab4Root" tabTitle="Profile" tabIcon="person"></ion-tab>  
</ion-tabs>

      

tabs.ts

import { Component, ViewChild } from '@angular/core';
import { NavController, NavParams, AlertController, Tabs } from 'ionic-
angular';
import { PendingJobPage } from '../pending-job/pending-job';
import { CompletedJobPage } from '../completed-job/completed-job';
import { RequestPage } from '../request/request';
import { ProfilePage } from '../profile/profile';

@Component({
  templateUrl: 'tabs.html'
})
export class TabsPage {

  @ViewChild('tabs') tabRef: Tabs;
  pending: any;
  apply: boolean;
  detailsParam: any;

  tab1Root = RequestPage;
  tab2Root = PendingJobPage;
  tab3Root = CompletedJobPage;
  tab4Root = ProfilePage;

  constructor(public navParams: NavParams, public navCtrl: NavController) {
    this.pending = this.navParams.get('param1');
    this.apply = this.navParams.get('apply');
    this.detailsParam = this.navParams.data;
    console.log("a = ", this.tabRef);

    if(this.apply === true){
      this.navCtrl.parent.select(1);
    }
    else{
      this.navCtrl.parent.select(0);
    }
  }
}

      

+4


source to share


2 answers


As you can see in Angular Docs ,

ViewChild is set after view initialization

and

The ViewChild is refreshed after checking the view.

export class AfterViewComponent implements  AfterViewChecked, AfterViewInit {

  ngAfterViewInit() {
    // viewChild is set after the view has been initialized <- Here!
  }

  ngAfterViewChecked() {
    // viewChild is updated after the view has been checked <- Here!
  }

  // ...

}

      



So the problem with your code is that the view was not initialized when the constructor was executed. You will need to put all the code that interacts with the tabs in the ngAfterViewInit

lifecycle hook:

  ngAfterViewInit() {
    // Now you can use the tabs reference
    console.log("a = ", this.tabRef);
  }

      

If you just want to use Ionic custom lifecycle events, you need to use a hook ionViewDidEnter

:

export class TabsPage {

@ViewChild('myTabs') tabRef: Tabs;

ionViewDidEnter() {
    // Now you can use the tabs reference
    console.log("a = ", this.tabRef);
 }

}

      

+4


source


Some general approach:

You can create a method that will wait until it ViewChild

is ready

function waitWhileViewChildIsReady(parent: any, viewChildName: string, refreshRateSec: number = 50, maxWaitTime: number = 3000): Observable<any> {
  return interval(refreshRateSec)
    .pipe(
      takeWhile(() => !isDefined(parent[viewChildName])),
      filter(x => x === undefined),
      takeUntil(timer(maxWaitTime)),
      endWith(parent[viewChildName]),
      flatMap(v => {
        if (!parent[viewChildName]) throw new Error('ViewChild "${viewChildName}" is never ready');
        return of(!parent[viewChildName]);
      })
    );
}


function isDefined<T>(value: T | undefined | null): value is T {
  return <T>value !== undefined && <T>value !== null;
}

      



Using:

  // Now you can do it in any place of your code
  waitWhileViewChildIsReady(this, 'yourViewChildName').subscribe(() =>{
      // your logic here
  })

      

0


source







All Articles