Ionic-framework: [ionic 4] ionViewWillEnter only triggers once.

Created on 21 Aug 2018  Â·  48Comments  Â·  Source: ionic-team/ionic-framework

Bug Report

Ionic Info
Run ionic info from a terminal/cmd prompt and paste the output below.

Ionic:

   ionic (Ionic CLI)          : 4.0.5
   Ionic Framework            : @ionic/angular 4.0.0-beta.3
   @angular-devkit/core       : 0.7.2
   @angular-devkit/schematics : 0.7.2
   @angular/cli               : 6.1.2
   @ionic/ng-toolkit          : 1.0.5
   @ionic/schematics-angular  : 1.0.4

Cordova:

   cordova (Cordova CLI) : 8.0.0
   Cordova Platforms     : android 7.0.0, ios 4.5.5

System:

   Android SDK Tools : 25.2.5
   ios-deploy        : 1.9.2
   ios-sim           : 6.1.2
   NodeJS            : v7.4.0 (/usr/local/bin/node)
   npm               : 4.0.5
   OS                : macOS High Sierra
   Xcode             : Xcode 9.4.1 Build version 9F2000

Environment:

   ANDROID_HOME : /usr/local/Cellar/android-sdk/24.4.1_1

Describe the Bug
The ionViewWillEnter lifecycle (if its still called that) only triggers once. In ionic 3 the ionViewWillEnter triggered every time you navigated to the view. Now it only triggers the first time.

Steps to Reproduce
Steps to reproduce the behavior:
1) Add ionViewWillEnter to your view

public ionViewWillEnter(): void {
     console.log('hi');
}

2) Navigate to the page
3) Navigate to a different page
4) Navigate again to the page with the ionViewWillEnter

Expected Behavior
Expect the console.log('hi') to be logged every time I navigate to the view.

Additional Context
Note that I use tabs. Is there perphaps a Angular lifecycle which replaced ionViewWillEnter?

-- tabs
     -- View 1 (with ionViewWillEnter)
     -- View 2
triage

Most helpful comment

In the meanwhile, as a workaround, I am using below setup to mock the ionViewWillEnter event. Note that the url in the subscription should be that of the current page.

import { OnEnter } from '../on-enter';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { NavigationEnd, Router } from '@angular/router';

@Component({
    selector: 'app-home',
    templateUrl: 'home.page.html',
    styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit, OnEnter, OnDestroy {

    private subscription: Subscription;

    constructor(
        private router: Router
    ) { }

    public async ngOnInit(): Promise<void> {
        await this.onEnter();

        this.subscription = this.router.events.subscribe((event) => {
            if (event instanceof NavigationEnd && event.url === '/tabs/(home:home)') {
                this.onEnter();
            }
        });
    }

    public async onEnter(): Promise<void> {
        // do your on enter page stuff here
    }

    public ngOnDestroy(): void {
        this.subscription.unsubscribe();
    }
}

Custom interface

export interface OnEnter {
    onEnter(): Promise<void>;
}

All 48 comments

Same issue here.
Lifecycle functions work if your page is not inside a tab (or if you change page inside the same tab) but not when switching between two different tabs.

Yeah just found out that as well! Thanks for providing the extra information. Recap:

  • Switching between tabs (multiple router outlets) E.g. tabs/(home:home) to tabs/(browse:browse) -> ionViewWillEnter only triggering once
  • Switching between pages (same router outlet) E.g. tabs/(home:home) to tabs(home:contact) -> ionViewWillEnter is triggering every time.

Same issue with ionViewDidEnter.

Concerning ionViewWillLeave :

  • Switching between tabs (multiple router outlets) E.g. tabs/(home:home) to tabs/(browse:browse) -> ionViewWillLeave is never triggered
    Switching between pages (same router outlet) E.g. tabs/(home:home) to tabs(home:contact) -> ionViewWillEnter is triggered every time.

Worst of all, if you have this kind of routing :

-- tabs
     -- home
     -- browse
-- otherPage

Navigating between home and otherPage the lifecycle events won't be triggered on home (at least for ionViewDidEnter or ionViewWillLeave, haven't tested the other).
They are triggered correctly on otherPage component thought.

Same issue as @TomDemulierChevret

same here

This also happens when using goRoot dynamically(programmatically). It wil not fire ionViewWillEnter..

bump

Made a repro repository for this since it has bitten me as well: https://github.com/cthos/ion4-tab-repro

@cthos

Thx for the effort! This issue is so crucial, because for example. I see no way for doing stuff over and over again (like fetching data from an API) when the page is opened again. Because compared the an angular application pages also never get destroyed, so that ngOnit could be used for that.

In the meanwhile, as a workaround, I am using below setup to mock the ionViewWillEnter event. Note that the url in the subscription should be that of the current page.

import { OnEnter } from '../on-enter';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { NavigationEnd, Router } from '@angular/router';

@Component({
    selector: 'app-home',
    templateUrl: 'home.page.html',
    styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit, OnEnter, OnDestroy {

    private subscription: Subscription;

    constructor(
        private router: Router
    ) { }

    public async ngOnInit(): Promise<void> {
        await this.onEnter();

        this.subscription = this.router.events.subscribe((event) => {
            if (event instanceof NavigationEnd && event.url === '/tabs/(home:home)') {
                this.onEnter();
            }
        });
    }

    public async onEnter(): Promise<void> {
        // do your on enter page stuff here
    }

    public ngOnDestroy(): void {
        this.subscription.unsubscribe();
    }
}

Custom interface

export interface OnEnter {
    onEnter(): Promise<void>;
}

I've implemented the following more generic workaround:

import { OnDestroy } from '@angular/core';
import { Router, NavigationEnd, ActivatedRouteSnapshot, ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter, tap } from 'rxjs/operators';

export abstract class RouterPage implements OnDestroy {

    private ngUnsubscribe: Subject<void> = new Subject();

    constructor(router: Router, route: ActivatedRoute) {
        router.events.pipe(
            takeUntil(this.ngUnsubscribe),
            filter(event => event instanceof NavigationEnd),
            filter(_ => this._isComponentActive(
                router.routerState.snapshot.root.pathFromRoot,
                route.snapshot.component
            ))
        ).subscribe(_ => this.onEnter());
    }

    private _isComponentActive(path: ActivatedRouteSnapshot[], component: any): boolean {
        let isActive = false;
        path.forEach((ss: ActivatedRouteSnapshot) => {
            if (ss.component === component) {
                isActive = true;
            } else {
                isActive = this._isComponentActive(ss.children, component);
            }
        });
        return isActive;
    }

    abstract onEnter(): void;

    public ngOnDestroy(): void {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
    }
}

This class can then used as follows:

export class MyPage extends RouterPage implements OnDestroy {

    constructor(private router: Router, private route: ActivatedRoute) {
        super(router, route);
    }

    onEnter() {
        console.log('My page enter');
    }

   onDestroy() {
      super.ngOnDestroy();
   }

}

same here

same here, fix it please.

Same with ngOnInit. Fix it please. It is fundamental.

I've implemented for now the @doender solution, and it works like a charm...

Thanks @doender

In the meanwhile, as a workaround, I am using below setup to mock the ionViewWillEnter event. Note that the url in the subscription should be that of the current page.

import { OnEnter } from '../on-enter';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { NavigationEnd, Router } from '@angular/router';

@Component({
    selector: 'app-home',
    templateUrl: 'home.page.html',
    styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit, OnEnter, OnDestroy {

    private subscription: Subscription;

    constructor(
        private router: Router
    ) { }

    public async ngOnInit(): Promise<void> {
        await this.onEnter();

        this.subscription = this.router.events.subscribe((event) => {
            if (event instanceof NavigationEnd && event.url === '/tabs/(home:home)') {
                this.onEnter();
            }
        });
    }

    public async onEnter(): Promise<void> {
        // do your on enter page stuff here
    }

    public ngOnDestroy(): void {
        this.subscription.unsubscribe();
    }
}

Custom interface

export interface OnEnter {
    onEnter(): Promise<void>;
}

This really works for movement between tabs, but it does not work if I'm in a tab and I open a page with push and close again the open page with push. How can I make it work?

It might be that you redirect in your routes. So I had to check for the url in the subscription:

if (event instanceof NavigationEnd) {
          if (event.url === '/' || event.url === '/tabs' || event.url === '/tabs/(home:home)') {
            this.onEnter();
        }
}

Instead of:

 if (event instanceof NavigationEnd && event.url === '/tabs/(home:home)') {
       this.onEnter();
 }

Same problem here. Did Ionic team notice this bug? Thanks

Also OnDestroy never happen i use the router.events workaround

It might be that you redirect in your routes. So I had to check for the url in the subscription:

if (event instanceof NavigationEnd) {
          if (event.url === '/' || event.url === '/tabs' || event.url === '/tabs/(home:home)') {
            this.onEnter();
        }
}

Instead of:

 if (event instanceof NavigationEnd && event.url === '/tabs/(home:home)') {
       this.onEnter();
 }

like a charm!

Bump

Same issues.
I also have some other issues which could be related to this.

If i navigate from a normal page to my tabs page my ion-slides and ion-virtual-scroll elements don't initiate correctly on those child pages. Slides are not swipeable and virtual-scroll has very big space between the elements.

But when i open the tabs page first everything works great. Anybody an idea how to fix this?
There's no method to reinit the virtual-scroll ( i can fix slides by reiniting it with the workarounds above). Thanks

Bump

I'm experiencing the same issue.

Any update on when this is going to be fixed from the ionic team

@thomasferns I think we should rely on angular router-outlet events activate and deactivate for now, as others have mentioned above.
Create interface page with method didEnter
export interface AppPageInterface {
didEnter: () => void;
willLeave: () => void;
}
Implement it in pages you wish to use
export class SamplePage implements AppPageInterface {
didEnter() {
......
}
}

In main component router outlet or tabs router outlet
(deactivate) ="!!$event.willLeave ? $event.willLeave() : undefined" >

Hi guys,

any thing on this from the Ionic team yet?

Bump

It has been a while since the first post. Can't believe that nobody has fixed this bug.

I am facing the same issue. When I was not in a tab ionViewWillEnter was working ok. Now with tabs when I navigateForward and come back is not calling it. Also when I navigate between tabs.

Bump, 4.0.0-beta-17 release still has this critical issue :(

I make it work.

Be sure that if you navigate to one page in the tab, that page have the same outlet.
Also with that if the navigation you don't do it properly it will go back but will not enter in the ionViewWillEnter.
For html with ionic component: href="/main/tabs/(home:sneaker/{{sneaker.$key}})" routerDirection="forward"
Following the outlet:
{
path: 'sneaker/:id',
outlet: 'home',
component: SneakerPage
},

What exactly is the issue?

If it's the tab issue, then please follow https://github.com/ionic-team/ionic/issues/14566#issuecomment-416243089

If you wonder about life cycles, please read here -> https://medium.com/@paulstelzer/ionic-4-and-the-lifecycle-hooks-4fe9eabb2864

@paulstelzer when switching between tabs, ionViewWillEnter is not re-triggered.

Thx for the link. I found the answer here:

And what about ion-tabs?

At the moment (beta.15) ion-tabs are only lazy loading at the beginning. Open a tab initialize the component. If you now switch to another tab, this will be initialize at the first time. If you move back to the last tab, you will not see any Lifecycle hooks (neither ngOnInit nor ionViewWillEnter ).

If you remove the TabsPage from the Stack (for example by navigateRoot() to another route), all components will be destroyed at once. Then you will see the ngOnDestroy lifecycle hook.

Maybe the lifecycle of tabs change in future, but for now this is the behaviour. You can take a look at this issue at GitHub to follow that process.

We did not know it was an official behavior. I use the router.events trick for now as mentioned in previous comments.

Okay, I close it here now because for tabs is a seperate issue - duplicate of #14566

@paulstelzer Can you at least tell us if it's planned to change the lifecycle behaviours for tabs ?

With your post medium (thanks for the clarification btw) the current behaviour is not a bug. But at the same time it's not really the behaviour wanted nor expected by the users (especially regaring the names of the lifecycle hooks).
If nothing is planned for tabs & lifecycle hooks, we will be forced to keep the ugly hack based on routes to know is a user enters/leaves a tab.

At least this issue should not be closed but transformed instead in a feature request.

It's closed because it's a duplciate of #14566 (it makes no sense to have different issues open for the same topic)

How is it a duplicate of #14566 ?
You can have lifecycle hooks without lazy-loading.
Lifecyle hooks are supposed to be about navigation and wich page/component is focused, not about how and when it is loaded.

I'm not talking from a technical point of view (I don't know how Ionic handle it internally) but from a functionnal point of view.

As some mentioned it seems to be related to lazy loading. Once i offloaded all my "shell" components to be pages/lazyloaded components the ionOnViewEnter fired on every reload, ngoninit did still not work as intended if i recall correctly.

I updated to 4.0.0-beta.18 and this issue is partially fixed but there are still cases where lifecycle events don't trigger properly for tabs.

ionViewWillEnter still doesn't seem to trigger in RC0.

IonViewWillEnter only triggers when navigation is within the same tab. If
you navigate to a different page in tab 1 and then back IonViewWillEnter is
fired but it isn't fired on switching tabs

On Thu, Dec 27, 2018, 4:36 PM RZR666 <[email protected] wrote:

ionViewWillEnter still doesn't seem to trigger in RC0.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/ionic-team/ionic/issues/15260#issuecomment-450130337,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AqZ_uoIiauIXjt6qJXBYc_v_LTeMKDLPks5u9KmogaJpZM4WF0ly
.

IonViewWillEnter only triggers when navigation is within the same tab. If you navigate to a different page in tab 1 and then back IonViewWillEnter is fired but it isn't fired on switching tabs

@thomasferns Having this issue as well here

@raulruizbarea Has the correct answer above. You have to make sure both routes have the same outlet.

Does any of you have that ngOnInit() triggers only one time in rc.0? It was working for me before but now it's stopped and triggers once.

Ionic:

   ionic (Ionic CLI)             : 4.6.0
   Ionic Framework               : @ionic/angular 4.0.0-rc.0
   @angular-devkit/build-angular : 0.11.4
   @angular-devkit/schematics    : 7.1.4
   @angular/cli                  : 7.1.4
   @ionic/angular-toolkit        : 1.2.2

Cordova:

   cordova (Cordova CLI) : 8.1.2 ([email protected])
   Cordova Platforms     : android 7.1.4
   Cordova Plugins       : cordova-plugin-ionic-keyboard 2.1.3, cordova-plugin-ionic-webview 2.2.3, (and 8 other plugins)

System:

   Android SDK Tools : 26.1.1 
   NodeJS            : v8.11.3 
   npm               : 6.4.1
   OS                : Linux 4.15

ionViewWillEnter is triggering when navigating between tabs. It doesn't trigger when navigating back from different page to tab.

It doesn't work with RC0.

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alexbainbridge picture alexbainbridge  Â·  3Comments

manucorporat picture manucorporat  Â·  3Comments

brandyscarney picture brandyscarney  Â·  3Comments

danbucholtz picture danbucholtz  Â·  3Comments

fdnhkj picture fdnhkj  Â·  3Comments