From 4e01ec09a265c6f0fdaa22131078c1926cec6f52 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Sun, 22 Nov 2015 23:10:23 -0600 Subject: [PATCH] feat(tabs): ref parent nav controllers Closes #621 --- ionic/components/nav/nav-controller.ts | 9 +++ ionic/components/tabs/tab.ts | 30 ++++++---- ionic/components/tabs/tabs.ts | 63 ++++++++++---------- ionic/components/tabs/test/advanced/index.ts | 7 +++ 4 files changed, 66 insertions(+), 43 deletions(-) diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index c6f139d11f..490a541d37 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -148,12 +148,21 @@ export class NavController extends Ion { */ push(componentType, params = {}, opts = {}) { if (!componentType) { + console.debug('invalid componentType to push'); return Promise.reject(); } if (typeof componentType !== 'function') { throw 'Loading component must be a component class, not "' + componentType.toString() + '"'; } + let now = Date.now(); + let last = this.last(); + if (last && last.componentType === componentType && now + 500 > this._lastPush) { + console.debug('same componentType pushed as active'); + return Promise.reject(); + } + this._lastPush = now; + let resolve; let promise = new Promise(res => { resolve = res; }); diff --git a/ionic/components/tabs/tab.ts b/ionic/components/tabs/tab.ts index 913445a98b..e3824d3ee0 100644 --- a/ionic/components/tabs/tab.ts +++ b/ionic/components/tabs/tab.ts @@ -59,9 +59,9 @@ import {Tabs} from './tabs'; 'tabIcon' ], host: { - '[attr.id]': 'panelId', - '[attr.aria-labelledby]': 'btnId', '[class.show-tab]': 'isSelected', + '[attr.id]': '_panelId', + '[attr.aria-labelledby]': '_btnId', 'role': 'tabpanel' }, template: '' @@ -69,7 +69,7 @@ import {Tabs} from './tabs'; export class Tab extends NavController { constructor( - @Host() tabs: Tabs, + @Host() parentTabs: Tabs, app: IonicApp, config: Config, elementRef: ElementRef, @@ -80,9 +80,11 @@ export class Tab extends NavController { renderer: Renderer ) { // A Tab is a NavController for its child pages - super(tabs, app, config, elementRef, compiler, loader, viewManager, zone, renderer); - this.tabs = tabs; - this._isInitial = tabs.add(this); + super(parentTabs, app, config, elementRef, compiler, loader, viewManager, zone, renderer); + this._isInitial = parentTabs.add(this); + + this._panelId = 'tabpanel-' + this.id; + this._btnId = 'tab-' + this.id; } /** @@ -90,10 +92,10 @@ export class Tab extends NavController { */ onInit() { if (this._isInitial) { - this.tabs.select(this); + this.parent.select(this); - } else if (this.tabs.preloadTabs) { - setTimeout(() => { + } else if (this.parent.preloadTabs) { + this._loadTimer = setTimeout(() => { if (!this._loaded) { let opts = { animate: false, @@ -125,9 +127,9 @@ export class Tab extends NavController { */ loadPage(viewCtrl, navbarContainerRef, done) { // by default a page's navbar goes into the shared tab's navbar section - navbarContainerRef = this.tabs.navbarContainerRef; + navbarContainerRef = this.parent.navbarContainerRef; - let isTabSubPage = (this.tabs.subPages && viewCtrl.index > 0); + let isTabSubPage = (this.parent.subPages && viewCtrl.index > 0); if (isTabSubPage) { // a subpage, that's not the first index // should not use the shared tabs navbar section, but use it's own @@ -158,7 +160,11 @@ export class Tab extends NavController { } get index() { - return this.tabs.getIndex(this); + return this.parent.getIndex(this); + } + + onDestroy() { + clearTimeout(this._loadTimer); } } diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 38cef4bc10..f3d6ad6e52 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -1,10 +1,10 @@ import {Directive, ElementRef, Optional, Host, NgFor, NgIf, forwardRef, ViewContainerRef} from 'angular2/angular2'; import {Ion} from '../ion'; -import {IonicApp} from '../app/app'; import {Attr} from '../app/id'; import {Config} from '../../config/config'; import {Platform} from '../../platform/platform'; +import {NavController} from '../nav/nav-controller'; import {ViewController} from '../nav/view-controller'; import {ConfigComponent} from '../../config/decorators'; import {Icon} from '../icon/icon'; @@ -74,7 +74,7 @@ import {Icon} from '../icon/icon'; '' + '' + '' + - '' + + '' + '' + '{{t.tabTitle}}' + '' + @@ -105,17 +105,18 @@ export class Tabs extends Ion { * point that "Tabs" is itself is just a page with its own instance of ViewController. */ constructor( - app: IonicApp, config: Config, elementRef: ElementRef, @Optional() viewCtrl: ViewController, + @Optional() navCtrl: NavController, private platform: Platform ) { super(elementRef, config); - this.app = app; + this.parent = navCtrl; this.subPages = config.get('tabSubPages'); - this.tabs = []; + this._tabs = []; + this._id = ++tabIds; // Tabs may also be an actual ViewController which was navigated to // if Tabs is static and not navigated to within a NavController @@ -125,9 +126,9 @@ export class Tabs extends Ion { viewCtrl.setContentRef(elementRef); // TODO: improve how this works, probably not use promises here - this.readyPromise = new Promise(res => { this.isReady = res; }); + this._readyPromise = new Promise(res => { this._isReady = res; }); viewCtrl.onReady = () => { - return this.readyPromise; + return this._readyPromise; }; } } @@ -139,9 +140,9 @@ export class Tabs extends Ion { super.onInit(); this.preloadTabs = (this.preloadTabs !== "false" && this.preloadTabs !== false); - if (this.highlight) { + if (this._highlight) { this.platform.onResize(() => { - this.highlight.select(this.getSelected()); + this._highlight.select(this.getSelected()); }); } } @@ -150,12 +151,10 @@ export class Tabs extends Ion { * @private */ add(tab) { - tab.id = ++_tabIds; - tab.btnId = 'tab-' + tab.id; - tab.panelId = 'tabpanel-' + tab.id; - this.tabs.push(tab); + tab.id = this._id + '-' + (++_tabIds); + this._tabs.push(tab); - return (this.tabs.length === 1); + return (this._tabs.length === 1); } /** @@ -175,7 +174,7 @@ export class Tabs extends Ion { if (selectedTab === deselectedTab) { // no change - return this.touchActive(selectedTab); + return this._touchActive(selectedTab); } let opts = { @@ -192,16 +191,16 @@ export class Tabs extends Ion { selectedPage && selectedPage.willEnter(); selectedTab.load(opts, () => { - this.tabs.forEach(tab => { + this._tabs.forEach(tab => { tab.setSelected(tab === selectedTab); }); - this.highlight && this.highlight.select(selectedTab); + this._highlight && this._highlight.select(selectedTab); selectedPage && selectedPage.didEnter(); deselectedPage && deselectedPage.didLeave(); - this.isReady && this.isReady(); + this._isReady && this._isReady(); console.timeEnd('select tab ' + selectedTab.id); }); @@ -213,23 +212,23 @@ export class Tabs extends Ion { * @returns {TODO} TODO */ getByIndex(index) { - if (index < this.tabs.length && index > -1) { - return this.tabs[index]; + if (index < this._tabs.length && index > -1) { + return this._tabs[index]; } return null; } getSelected() { - for (let i = 0; i < this.tabs.length; i++) { - if (this.tabs[i].isSelected) { - return this.tabs[i]; + for (let i = 0; i < this._tabs.length; i++) { + if (this._tabs[i].isSelected) { + return this._tabs[i]; } } return null; } getIndex(tab) { - return this.tabs.indexOf(tab); + return this._tabs.indexOf(tab); } /** @@ -237,17 +236,17 @@ export class Tabs extends Ion { * "Touch" the active tab, going back to the root view of the tab * or optionally letting the tab handle the event */ - touchActive(tab) { + _touchActive(tab) { let active = tab.getActive(); - if(!active) { + if (!active) { return Promise.resolve(); } let instance = active.instance; // If they have a custom tab selected handler, call it - if(instance.tabSelected) { + if (instance.tabSelected) { return instance.tabSelected(); } @@ -259,7 +258,7 @@ export class Tabs extends Ion { // Otherwise, if the page we're on is not our real root, reset it to our // default root type - if(tab.root != active.componentType) { + if (tab.root != active.componentType) { return tab.setRoot(tab.root); } @@ -279,8 +278,8 @@ let _tabIds = -1; selector: '.tab-button', inputs: ['tab'], host: { - '[attr.id]': 'tab.btnId', - '[attr.aria-controls]': 'tab.panelId', + '[attr.id]': 'tab._btnId', + '[attr.aria-controls]': 'tab._panelId', '[attr.aria-selected]': 'tab.isSelected', '[class.has-title]': 'hasTitle', '[class.has-icon]': 'hasIcon', @@ -310,6 +309,8 @@ class TabButton extends Ion { } } +let tabIds = -1; + /** * @private @@ -320,7 +321,7 @@ class TabButton extends Ion { class TabHighlight { constructor(@Host() tabs: Tabs, config: Config, elementRef: ElementRef) { if (config.get('tabbarHighlight')) { - tabs.highlight = this; + tabs._highlight = this; this.elementRef = elementRef; } } diff --git a/ionic/components/tabs/test/advanced/index.ts b/ionic/components/tabs/test/advanced/index.ts index 67a939d833..5caae5ede7 100644 --- a/ionic/components/tabs/test/advanced/index.ts +++ b/ionic/components/tabs/test/advanced/index.ts @@ -47,6 +47,7 @@ class TabsPage { '' + '' + '

' + + '

' + '' + '' + '
' @@ -59,6 +60,12 @@ class Tab1Page1 { push() { this.nav.push(Tab1Page2) } + + logout() { + let tabs = this.nav.parent; + let rootNav = tabs.parent; + rootNav.pop(); + } }