fix(nav): adds public willLoad lifecycle event

* fix(nav): adds public willLoad lifecycle event

* test(menu): adds more asserts
This commit is contained in:
Manu Mtz.-Almeida
2016-11-01 19:12:29 +01:00
committed by Adam Bradley
parent 504e6e0440
commit 033e1eae17
9 changed files with 195 additions and 26 deletions

View File

@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EventEmit
import { Backdrop } from '../backdrop/backdrop'; import { Backdrop } from '../backdrop/backdrop';
import { Config } from '../../config/config'; import { Config } from '../../config/config';
import { isTrueProperty } from '../../util/util'; import { isTrueProperty, assert } from '../../util/util';
import { Keyboard } from '../../util/keyboard'; import { Keyboard } from '../../util/keyboard';
import { MenuContentGesture } from './menu-gestures'; import { MenuContentGesture } from './menu-gestures';
import { MenuController } from './menu-controller'; import { MenuController } from './menu-controller';
@ -192,7 +192,6 @@ export class Menu {
private _cntEle: HTMLElement; private _cntEle: HTMLElement;
private _cntGesture: MenuContentGesture; private _cntGesture: MenuContentGesture;
private _type: MenuType; private _type: MenuType;
private _resizeUnreg: Function;
private _isEnabled: boolean = true; private _isEnabled: boolean = true;
private _isSwipeEnabled: boolean = true; private _isSwipeEnabled: boolean = true;
private _isAnimating: boolean = false; private _isAnimating: boolean = false;
@ -472,6 +471,8 @@ export class Menu {
} }
private _before() { private _before() {
assert(this._isAnimating === false, '_before should be called when we are not animating');
// this places the menu into the correct location before it animates in // this places the menu into the correct location before it animates in
// this css class doesn't actually kick off any animations // this css class doesn't actually kick off any animations
this.menuContent && this.menuContent.resize(); this.menuContent && this.menuContent.resize();
@ -482,6 +483,8 @@ export class Menu {
} }
private _after(isOpen: boolean) { private _after(isOpen: boolean) {
assert(this._isAnimating === true, '_after should be called when we are animating');
// keep opening/closing the menu disabled for a touch more yet // keep opening/closing the menu disabled for a touch more yet
// only add listeners/css if it's enabled and isOpen // only add listeners/css if it's enabled and isOpen
// and only remove listeners/css if it's not open // and only remove listeners/css if it's not open
@ -516,21 +519,21 @@ export class Menu {
/** /**
* @private * @private
*/ */
open() { open(): Promise<boolean> {
return this.setOpen(true); return this.setOpen(true);
} }
/** /**
* @private * @private
*/ */
close() { close(): Promise<boolean> {
return this.setOpen(false); return this.setOpen(false);
} }
/** /**
* @private * @private
*/ */
toggle() { toggle(): Promise<boolean> {
return this.setOpen(!this.isOpen); return this.setOpen(!this.isOpen);
} }
@ -633,12 +636,10 @@ export class Menu {
this._events.unlistenAll(); this._events.unlistenAll();
this._cntGesture && this._cntGesture.destroy(); this._cntGesture && this._cntGesture.destroy();
this._type && this._type.destroy(); this._type && this._type.destroy();
this._resizeUnreg && this._resizeUnreg();
this._cntGesture = null; this._cntGesture = null;
this._type = null; this._type = null;
this._cntEle = null; this._cntEle = null;
this._resizeUnreg = null;
} }
} }

View File

@ -30,7 +30,7 @@ export class ModalCmp {
this._bdDismiss = _navParams.data.opts.enableBackdropDismiss; this._bdDismiss = _navParams.data.opts.enableBackdropDismiss;
} }
ionViewWillLoad() { ionViewPreLoad() {
this._load(this._navParams.data.component); this._load(this._navParams.data.component);
} }

View File

@ -149,6 +149,7 @@ export class E2EPage {
<button ion-button full (click)="submit()">Submit</button> <button ion-button full (click)="submit()">Submit</button>
<p>ionViewCanEnter ({{called.ionViewCanEnter}})</p> <p>ionViewCanEnter ({{called.ionViewCanEnter}})</p>
<p>ionViewCanLeave ({{called.ionViewCanLeave}})</p> <p>ionViewCanLeave ({{called.ionViewCanLeave}})</p>
<p>ionViewWillLoad ({{called.ionViewWillLoad}})</p>
<p>ionViewDidLoad ({{called.ionViewDidLoad}})</p> <p>ionViewDidLoad ({{called.ionViewDidLoad}})</p>
<p>ionViewWillEnter ({{called.ionViewWillEnter}})</p> <p>ionViewWillEnter ({{called.ionViewWillEnter}})</p>
<p>ionViewDidEnter ({{called.ionViewDidEnter}})</p> <p>ionViewDidEnter ({{called.ionViewDidEnter}})</p>
@ -178,6 +179,7 @@ export class ModalPassData {
this.called = { this.called = {
ionViewCanEnter: 0, ionViewCanEnter: 0,
ionViewCanLeave: 0, ionViewCanLeave: 0,
ionViewWillLoad: 0,
ionViewDidLoad: 0, ionViewDidLoad: 0,
ionViewWillEnter: 0, ionViewWillEnter: 0,
ionViewDidEnter: 0, ionViewDidEnter: 0,
@ -213,6 +215,11 @@ export class ModalPassData {
}); });
} }
ionViewWillLoad() {
console.log('ModalPassData ionViewWillLoad fired');
this.called.ionViewWillLoad++;
}
ionViewDidLoad() { ionViewDidLoad() {
console.log('ModalPassData ionViewDidLoad fired'); console.log('ModalPassData ionViewDidLoad fired');
this.called.ionViewDidLoad++; this.called.ionViewDidLoad++;
@ -400,6 +407,7 @@ export class ContactUs {
<ion-content padding> <ion-content padding>
<p>ionViewCanEnter ({{called.ionViewCanEnter}})</p> <p>ionViewCanEnter ({{called.ionViewCanEnter}})</p>
<p>ionViewCanLeave ({{called.ionViewCanLeave}})</p> <p>ionViewCanLeave ({{called.ionViewCanLeave}})</p>
<p>ionViewWillLoad ({{called.ionViewWillLoad}})</p>
<p>ionViewDidLoad ({{called.ionViewDidLoad}})</p> <p>ionViewDidLoad ({{called.ionViewDidLoad}})</p>
<p>ionViewWillEnter ({{called.ionViewWillEnter}})</p> <p>ionViewWillEnter ({{called.ionViewWillEnter}})</p>
<p>ionViewDidEnter ({{called.ionViewDidEnter}})</p> <p>ionViewDidEnter ({{called.ionViewDidEnter}})</p>
@ -441,6 +449,7 @@ export class ModalFirstPage {
this.called = { this.called = {
ionViewCanEnter: 0, ionViewCanEnter: 0,
ionViewCanLeave: 0, ionViewCanLeave: 0,
ionViewWillLoad: 0,
ionViewDidLoad: 0, ionViewDidLoad: 0,
ionViewWillEnter: 0, ionViewWillEnter: 0,
ionViewDidEnter: 0, ionViewDidEnter: 0,
@ -479,6 +488,11 @@ export class ModalFirstPage {
return true; return true;
} }
ionViewWillLoad() {
console.log('ModalFirstPage ionViewWillLoad fired');
this.called.ionViewWillLoad++;
}
ionViewDidLoad() { ionViewDidLoad() {
console.log('ModalFirstPage ionViewDidLoad fired'); console.log('ModalFirstPage ionViewDidLoad fired');
this.called.ionViewDidLoad++; this.called.ionViewDidLoad++;

View File

@ -1,15 +1,22 @@
import { NgModule, Component, ViewChild } from '@angular/core'; import { NgModule, Component, ViewChild } from '@angular/core';
import { App, AlertController, Content, DeepLinkConfig, IonicApp, IonicModule, Label, NavController, NavParams, Tabs, Tab, ModalController, ViewController } from '../../../..'; import { App, AlertController, Content, DeepLinkConfig, IonicApp, IonicModule, NavController, NavParams, Tabs, Tab, ModalController, ViewController } from '../../../..';
@Component({
selector: 'my-cmp2',
template: `<span style="color:green">{{value}}</span>`
})
export class MyCmpTest2 {
value: string = 'Test Failed';
}
@Component({ @Component({
selector: 'my-cmp', selector: 'my-cmp',
template: `<ion-label>My Custom Component Test <ion-icon name="star"></ion-icon> template: `<my-cmp2></my-cmp2> <span style="color:green">{{value}}</span>`
<span style="color:green">{{value}}</span></ion-label>`
}) })
export class MyCmpTest { export class MyCmpTest {
@ViewChild(Label) _label: Label; @ViewChild(MyCmpTest2) _label: MyCmpTest2;
label: Label; label: MyCmpTest2;
value: string = ''; value: string = 'Test Failed';
ngOnInit() { ngOnInit() {
this.label = this._label; this.label = this._label;
@ -34,6 +41,7 @@ export class MyCmpTest {
<div padding> <div padding>
<p>ionViewCanEnter ({{called.ionViewCanEnter}})</p> <p>ionViewCanEnter ({{called.ionViewCanEnter}})</p>
<p>ionViewCanLeave ({{called.ionViewCanLeave}})</p> <p>ionViewCanLeave ({{called.ionViewCanLeave}})</p>
<p>ionViewWillLoad ({{called.ionViewWillLoad}})</p>
<p>ionViewDidLoad ({{called.ionViewDidLoad}})</p> <p>ionViewDidLoad ({{called.ionViewDidLoad}})</p>
<p>ionViewWillEnter ({{called.ionViewWillEnter}})</p> <p>ionViewWillEnter ({{called.ionViewWillEnter}})</p>
<p>ionViewDidEnter ({{called.ionViewDidEnter}})</p> <p>ionViewDidEnter ({{called.ionViewDidEnter}})</p>
@ -91,6 +99,7 @@ export class FirstPage {
this.called = { this.called = {
ionViewCanEnter: 0, ionViewCanEnter: 0,
ionViewCanLeave: 0, ionViewCanLeave: 0,
ionViewWillLoad: 0,
ionViewDidLoad: 0, ionViewDidLoad: 0,
ionViewWillEnter: 0, ionViewWillEnter: 0,
ionViewDidEnter: 0, ionViewDidEnter: 0,
@ -104,11 +113,11 @@ export class FirstPage {
for (var i = 1; i <= 50; i++) { for (var i = 1; i <= 50; i++) {
this.pages.push(i); this.pages.push(i);
} }
// if (!this.myCmp || !this.content || !this.myCmp.label) { if (!this.myCmp || !this.content || !this.myCmp.label) {
// throw new Error('children are not loaded'); throw new Error('children are not loaded');
// } }
this.myCmp.value = 'root!'; this.myCmp.value = '👍 self test passed!';
// this.myCmp.label.color = 'primary'; this.myCmp.label.value = '👍 children test passed!';
this.called.ionViewDidLoad++; this.called.ionViewDidLoad++;
} }
@ -810,6 +819,7 @@ export const deepLinkConfig: DeepLinkConfig = {
RedirectPage, RedirectPage,
AnotherPage, AnotherPage,
MyCmpTest, MyCmpTest,
MyCmpTest2,
FullPage, FullPage,
PrimaryHeaderPage, PrimaryHeaderPage,
TabsPage, TabsPage,

View File

@ -423,7 +423,7 @@ export class PickerCmp {
this.lastClick = 0; this.lastClick = 0;
} }
ionViewDidLoad() { ionViewWillLoad() {
// normalize the data // normalize the data
let data = this.d; let data = this.d;

View File

@ -60,7 +60,7 @@ export class PopoverCmp {
this.id = (++popoverIds); this.id = (++popoverIds);
} }
ionViewWillLoad() { ionViewPreLoad() {
let activeElement: any = document.activeElement; let activeElement: any = document.activeElement;
if (document.activeElement) { if (document.activeElement) {
activeElement.blur(); activeElement.blur();

View File

@ -0,0 +1,129 @@
import { Component, NgModule } from '@angular/core';
import { IonicApp, IonicModule, NavController, AlertController } from '../../../..';
//
// Tab 1
//
@Component({
template: `
<ion-header>
<ion-navbar>
<ion-title>Lifecyles</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>ionViewCanEnter ({{called.ionViewCanEnter}})</p>
<p>ionViewCanLeave ({{called.ionViewCanLeave}})</p>
<p>ionViewWillLoad ({{called.ionViewWillLoad}})</p>
<p>ionViewDidLoad ({{called.ionViewDidLoad}})</p>
<p>ionViewWillEnter ({{called.ionViewWillEnter}})</p>
<p>ionViewDidEnter ({{called.ionViewDidEnter}})</p>
<p>ionViewWillLeave ({{called.ionViewWillLeave}})</p>
<p>ionViewDidLeave ({{called.ionViewDidLeave}})</p>
<button ion-button (click)="push()">push()</button>
<button ion-button (click)="openAlert()">open alert</button>
</ion-content>
`
})
export class Tab1 {
called: any;
constructor(private alertCtrl: AlertController, private navCtrl: NavController) {
this.called = {
ionViewCanEnter: 0,
ionViewCanLeave: 0,
ionViewWillLoad: 0,
ionViewDidLoad: 0,
ionViewWillEnter: 0,
ionViewDidEnter: 0,
ionViewWillLeave: 0,
ionViewDidLeave: 0
};
}
push() {
this.navCtrl.push(Tab1);
}
openAlert() {
this.alertCtrl.create({
title: 'Example'
}).present();
}
ionViewCanEnter() {
this.called.ionViewCanEnter++;
return true;
}
ionViewCanLeave() {
this.called.ionViewCanLeave++;
return true;
}
ionViewWillLoad() {
this.called.ionViewWillLoad++;
}
ionViewDidLoad() {
this.called.ionViewDidLoad++;
}
ionViewWillEnter() {
this.called.ionViewWillEnter++;
}
ionViewDidEnter() {
this.called.ionViewDidEnter++;
}
ionViewWillLeave() {
this.called.ionViewWillLeave++;
}
ionViewDidLeave() {
this.called.ionViewDidLeave++;
}
}
@Component({
template: `
<ion-tabs>
<ion-tab tabTitle="Plain List" tabIcon="star" [root]="root"></ion-tab>
<ion-tab tabTitle="Schedule" tabIcon="globe" [root]="root"></ion-tab>
<ion-tab tabTitle="Stopwatch" tabIcon="logo-facebook" [root]="root"></ion-tab>
</ion-tabs>
`
})
export class TabsPage {
root = Tab1;
}
@Component({
template: `<ion-nav [root]="root"></ion-nav>`
})
export class E2EApp {
root = TabsPage;
}
@NgModule({
declarations: [
E2EApp,
Tab1,
TabsPage
],
imports: [
IonicModule.forRoot(E2EApp, {
tabsHighlight: true,
})
],
bootstrap: [IonicApp],
entryComponents: [
E2EApp,
Tab1,
TabsPage
]
})
export class AppModule {}

View File

@ -419,12 +419,15 @@ export class NavControllerBase extends Ion implements NavController {
// create ComponentRef and set it to the entering view // create ComponentRef and set it to the entering view
enteringView.init(componentFactory.create(childInjector, [])); enteringView.init(componentFactory.create(childInjector, []));
enteringView._state = ViewState.INITIALIZED; enteringView._state = ViewState.INITIALIZED;
this._willLoad(enteringView); this._preLoad(enteringView);
} }
_viewAttachToDOM(view: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) { _viewAttachToDOM(view: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) {
assert(view._state === ViewState.INITIALIZED, 'view state must be INITIALIZED'); assert(view._state === ViewState.INITIALIZED, 'view state must be INITIALIZED');
// fire willLoad before change detection runs
this._willLoad(view);
// render the component ref instance to the DOM // render the component ref instance to the DOM
// ******** DOM WRITE **************** // ******** DOM WRITE ****************
viewport.insert(componentRef.hostView, viewport.length); viewport.insert(componentRef.hostView, viewport.length);
@ -438,14 +441,11 @@ export class NavControllerBase extends Ion implements NavController {
this._renderer.setElementClass(pageElement, view._cssClass, true); this._renderer.setElementClass(pageElement, view._cssClass, true);
} }
// TODO: componentRef.changeDetectorRef.detectChanges();
// componentRef.changeDetectorRef.detectChanges();
// successfully finished loading the entering view // successfully finished loading the entering view
// fire off the "didLoad" lifecycle events // fire off the "didLoad" lifecycle events
this._didLoad(view); this._didLoad(view);
componentRef.changeDetectorRef.detectChanges();
} }
_viewTest(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction) { _viewTest(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction) {
@ -753,6 +753,12 @@ export class NavControllerBase extends Ion implements NavController {
} }
} }
_preLoad(view: ViewController) {
assert(this.isTransitioning(), 'nav controller should be transitioning');
view._preLoad();
}
_willLoad(view: ViewController) { _willLoad(view: ViewController) {
assert(this.isTransitioning(), 'nav controller should be transitioning'); assert(this.isTransitioning(), 'nav controller should be transitioning');

View File

@ -434,6 +434,15 @@ export class ViewController {
/** /**
* @private * @private
*/ */
_preLoad() {
this._lifecycle('PreLoad');
}
/**
* @private
* The view has loaded. This event only happens once per view will be created.
* This event is fired before the component and his children have been initialized.
*/
_willLoad() { _willLoad() {
this._lifecycle('WillLoad'); this._lifecycle('WillLoad');
} }