[Ionic 4 Beta] Unexpected @ViewChild return values


#1

Dear community,

a few days ago my company decided to upgrade a client’s project (Angular based) to the new Ionic 4 Beta version. :tada:

While we refactored pretty many things easily, there seems to be an issue with Ionic elements that are accessed via the “@ViewChild”-Notation:

/* nav.page.html */
<ion-nav [root]="masterPage" #masterNav></ion-nav>
<ion-nav [root]="detailPage" #detailNav main></ion-nav>

/* nav.page.ts */
export class AbSplitPaneComponent implements OnInit
{
    @ViewChild('detailNav') detailNav: Nav;
    @ViewChild('masterNav') masterNav: Nav;
}

In our current Ionic 3 project, the ion-nav-Element masterNav is fetched inside of the controller and returns an object like this: Nav {_config, _elementRef, _renderer, _componentName, parent}.

On the other hand, with the almost identical code base, using Ionic 4 Beta the @ViewChild result is an object like this: ElementRef {nativeElement}. Thus, only the element reference is returned which has previously been only an object property of the corresponding component, which is missing now.

It seems like either the ion-nav-Element cannot be resolved by Angular 6 (maybe because it’s a Web Component now?) and thus only the native element can be fetched; or there has been a general refactoring of some kind.

I already tried to add CUSTOM_ELEMENTS_SCHEMA in app.module.ts but this didn’t change anything.

Did anyone of you run into this trouble too, or can reproduce it with some view elements and @ViewChild access? Any help will be very greatly appreciated!


#2

I’ve only needed View Child for vanilla JS graphics libraries. The pure Angular/Ionic material I handle more abstractly through providers. I’m tempted to recommend that to you also. It feels as though you’re asking the template to do things that aren’t its job. This was a weakness of Ionic routing – it was page-template driven. Now you can play with things like PathLocationStrategy. You might not need navs at all.


#3

Having the exact same issue.

My view

<ion-tabs #tabs [tabbarHidden]="!isAuthenticated" color="primary">
    <ion-tab label="Home" icon="home" href="/tabs/(home:home)">
        <ion-router-outlet name="home"></ion-router-outlet>
    </ion-tab>
    <ion-tab label="workspace" icon="home" href="/tabs/(workspace:workspace)">
        <ion-router-outlet name="workspace"></ion-router-outlet>
    </ion-tab>
    <ion-tab label="login" icon="home" href="/tabs/(login:login)">
        <ion-router-outlet name="login"></ion-router-outlet>
    </ion-tab>
</ion-tabs>

My tabs viewmodel.

export class TabsPage implements OnInit, OnDestroy, AfterViewInit {

    @ViewChild('tabs') private tabs: Tabs;

    private isAuthenticated: boolean;
    private subscription: Subscription;

    constructor(
        private navController: NavController,
        private authService: AuthenticationService
    ) { }

    public async ngOnInit(): Promise<void> {
        this.isAuthenticated = await this.authService.isAuthenticated();
        console.log(this.tabs);
        this.subscription = this.tabs.ionChange.subscribe(async (x) => {
            this.isAuthenticated = await this.authService.isAuthenticated();
        });
    }

    public async ngAfterViewInit(): Promise<void> {
         console.log(this.tabs);
    }

    public async ngOnDestroy(): Promise<void> {
        this.subscription.unsubscribe();
    }
}

The only thing I am getting from the console.log(this.tabs) is this:

and of course the error

Error: Uncaught (in promise): TypeError: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined

Would love to have a solution for this.


#4

Created an issue for this => https://github.com/ionic-team/ionic/issues/15176


#5

To get slides in v4 with ViewChild the code has to be change a bit, maybe it’s the same with Tab

I guess you could try with an ElementRef or something like Slides ViewChild


#6

The solution provided to me was adding { read: Tabs }. Like this

@ViewChild('tabs', { read: Tabs }) private tabs: Tabs;

So for the OP it should be

@ViewChild('detailNav', { read: Nav }) detailNav: Nav;