fix(angular): adds tabs stack

This commit is contained in:
Manu Mtz.-Almeida
2018-11-14 19:10:27 +01:00
committed by Manu MA
parent d9172b7d68
commit adae8d4ad1
9 changed files with 68 additions and 20 deletions

View File

@ -184,6 +184,11 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
pop(deep = 1) { pop(deep = 1) {
return this.stackCtrl.pop(deep); return this.stackCtrl.pop(deep);
} }
getLastUrl() {
const active = this.stackCtrl.getActive();
return active ? active.fullpath : undefined;
}
} }
function emitEvent(el: HTMLElement) { function emitEvent(el: HTMLElement) {

View File

@ -1,5 +1,6 @@
import { ComponentFactoryResolver, Directive, ElementRef, HostListener, Injector, ViewContainerRef } from '@angular/core'; import { ComponentFactoryResolver, ContentChild, Directive, ElementRef, HostListener, Injector, ViewContainerRef } from '@angular/core';
import { AngularDelegate } from '../../providers/angular-delegate'; import { AngularDelegate } from '../../providers/angular-delegate';
import { IonRouterOutlet } from './ion-router-outlet';
@Directive({ @Directive({
@ -7,19 +8,32 @@ import { AngularDelegate } from '../../providers/angular-delegate';
}) })
export class TabDelegate { export class TabDelegate {
@ContentChild(IonRouterOutlet) outlet?: IonRouterOutlet;
private nativeEl: HTMLIonTabElement;
constructor( constructor(
private elementRef: ElementRef, elementRef: ElementRef,
resolver: ComponentFactoryResolver, resolver: ComponentFactoryResolver,
injector: Injector, injector: Injector,
angularDelegate: AngularDelegate, angularDelegate: AngularDelegate,
location: ViewContainerRef location: ViewContainerRef
) { ) {
elementRef.nativeElement.delegate = angularDelegate.create(resolver, injector, location); this.nativeEl = elementRef.nativeElement;
this.nativeEl.delegate = angularDelegate.create(resolver, injector, location);
}
get tab() {
return this.nativeEl.tab;
}
getLastUrl() {
return this.outlet ? this.outlet.getLastUrl() : undefined;
} }
@HostListener('ionRouterOutletActivated', ['$event']) @HostListener('ionRouterOutletActivated', ['$event'])
async onNavChanged() { async onNavChanged() {
const tab = this.elementRef.nativeElement as HTMLIonTabElement; const tab = this.nativeEl;
await tab.componentOnReady(); await tab.componentOnReady();
const tabs = tab.closest('ion-tabs'); const tabs = tab.closest('ion-tabs');
if (tabs) { if (tabs) {

View File

@ -1,25 +1,38 @@
import { Directive, ElementRef, HostListener, Optional } from '@angular/core'; import { ContentChildren, Directive, ElementRef, HostListener, Optional, QueryList } from '@angular/core';
import { Router } from '@angular/router'; import { TabDelegate } from './tab-delegate';
import { TabButtonClickDetail } from '@ionic/core';
import { NavController } from '../../providers';
@Directive({ @Directive({
selector: 'ion-tabs' selector: 'ion-tabs'
}) })
export class TabsDelegate { export class TabsDelegate {
@ContentChildren(TabDelegate) tabs: QueryList<TabDelegate>;
constructor( constructor(
@Optional() private router: Router, @Optional() private navCtrl: NavController,
elementRef: ElementRef elementRef: ElementRef
) { ) {
if (router) { const nativeEl = elementRef.nativeElement as HTMLIonTabsElement;
elementRef.nativeElement.useRouter = true; nativeEl.useRouter = true;
} }
urlForTab(tab: string) {
const tabDelegate = this.tabs.find(item => item.tab === tab);
return tabDelegate ? tabDelegate.getLastUrl() : undefined;
} }
@HostListener('ionTabButtonClick', ['$event']) @HostListener('ionTabButtonClick', ['$event'])
onTabbarClick(ev: UIEvent) { onTabbarClick(ev: any) {
const tabElm: HTMLIonTabButtonElement = ev.detail as any; const detail = ev.detail as TabButtonClickDetail;
if (this.router && tabElm && tabElm.href) { const { tab, href, selected } = detail;
this.router.navigateByUrl(tabElm.href); if (tab && href) {
const url = selected
? href
: this.urlForTab(tab) || href;
this.navCtrl.navigateBack(url, true);
} }
} }
} }

View File

@ -869,7 +869,7 @@ export class TabButton {
} }
export declare interface Tabs extends StencilComponents<'IonTabs'> {} export declare interface Tabs extends StencilComponents<'IonTabs'> {}
@Component({ selector: 'ion-tabs', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>' }) @Component({ selector: 'ion-tabs', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['useRouter'] })
export class Tabs { export class Tabs {
ionChange: EventEmitter<CustomEvent>; ionChange: EventEmitter<CustomEvent>;
ionNavWillLoad: EventEmitter<CustomEvent>; ionNavWillLoad: EventEmitter<CustomEvent>;
@ -880,6 +880,7 @@ export class Tabs {
c.detach(); c.detach();
const el = r.nativeElement; const el = r.nativeElement;
proxyMethods(this, el, ['select', 'setRouteId', 'getRouteId', 'getTab', 'getSelected']); proxyMethods(this, el, ['select', 'setRouteId', 'getRouteId', 'getTab', 'getSelected']);
proxyInputs(this, el, ['useRouter']);
proxyOutputs(this, el, ['ionChange', 'ionNavWillLoad', 'ionNavWillChange', 'ionNavDidChange']); proxyOutputs(this, el, ['ionChange', 'ionNavWillLoad', 'ionNavWillChange', 'ionNavDidChange']);
} }
} }

View File

@ -4500,6 +4500,7 @@ export namespace Components {
*/ */
'select': (tab: string | HTMLIonTabElement) => Promise<boolean>; 'select': (tab: string | HTMLIonTabElement) => Promise<boolean>;
'setRouteId': (id: string) => Promise<RouteWrite>; 'setRouteId': (id: string) => Promise<RouteWrite>;
'useRouter': boolean;
} }
interface IonTabsAttributes extends StencilHTMLAttributes { interface IonTabsAttributes extends StencilHTMLAttributes {
/** /**
@ -4518,6 +4519,7 @@ export namespace Components {
* Emitted when the navigation will load a component. * Emitted when the navigation will load a component.
*/ */
'onIonNavWillLoad'?: (event: CustomEvent<void>) => void; 'onIonNavWillLoad'?: (event: CustomEvent<void>) => void;
'useRouter'?: boolean;
} }
interface IonText { interface IonText {

View File

@ -6,5 +6,6 @@ export interface TabBarChangedDetail {
export interface TabButtonClickDetail { export interface TabButtonClickDetail {
tab: string; tab: string;
selected: boolean;
href?: string; href?: string;
} }

View File

@ -74,7 +74,8 @@ export class TabButton implements ComponentInterface {
if (!this.disabled) { if (!this.disabled) {
this.ionTabButtonClick.emit({ this.ionTabButtonClick.emit({
tab: this.tab, tab: this.tab,
href: this.href href: this.href,
selected: this.selected
}); });
} }
ev.preventDefault(); ev.preventDefault();

View File

@ -87,6 +87,13 @@ Using tabs with Angular's router is fairly straight forward. The only additional
<!-- Auto Generated Below --> <!-- Auto Generated Below -->
## Properties
| Property | Attribute | Description | Type | Default |
| ----------- | ------------ | ----------- | --------- | ------- |
| `useRouter` | `use-router` | | `boolean` | `false` |
## Events ## Events
| Event | Description | Detail | | Event | Description | Detail |

View File

@ -11,7 +11,6 @@ export class Tabs implements NavOutlet {
private transitioning = false; private transitioning = false;
private leavingTab?: HTMLIonTabElement; private leavingTab?: HTMLIonTabElement;
private useRouter = false;
@Element() el!: HTMLStencilElement; @Element() el!: HTMLStencilElement;
@ -21,6 +20,9 @@ export class Tabs implements NavOutlet {
@Prop({ context: 'config' }) config!: Config; @Prop({ context: 'config' }) config!: Config;
@Prop({ context: 'document' }) doc!: Document; @Prop({ context: 'document' }) doc!: Document;
/** @internal */
@Prop({ mutable: true }) useRouter = false;
/** /**
* Emitted when the tab changes. * Emitted when the tab changes.
*/ */
@ -42,7 +44,9 @@ export class Tabs implements NavOutlet {
@Event() ionNavDidChange!: EventEmitter<void>; @Event() ionNavDidChange!: EventEmitter<void>;
async componentWillLoad() { async componentWillLoad() {
if (!this.useRouter) {
this.useRouter = !!this.doc.querySelector('ion-router') && !this.el.closest('[no-router]'); this.useRouter = !!this.doc.querySelector('ion-router') && !this.el.closest('[no-router]');
}
this.tabs = Array.from(this.el.querySelectorAll('ion-tab')); this.tabs = Array.from(this.el.querySelectorAll('ion-tab'));
this.ionNavWillLoad.emit(); this.ionNavWillLoad.emit();
this.componentWillUpdate(); this.componentWillUpdate();
@ -69,9 +73,9 @@ export class Tabs implements NavOutlet {
protected onTabClicked(ev: CustomEvent<TabButtonClickDetail>) { protected onTabClicked(ev: CustomEvent<TabButtonClickDetail>) {
const { href, tab } = ev.detail; const { href, tab } = ev.detail;
const selectedTab = this.tabs.find(t => t.tab === tab); const selectedTab = this.tabs.find(t => t.tab === tab);
if (this.useRouter && href !== undefined) { if (this.useRouter) {
const router = this.doc.querySelector('ion-router'); const router = this.doc.querySelector('ion-router');
if (router) { if (router && href !== undefined) {
router.push(href); router.push(href);
} }
} else if (selectedTab) { } else if (selectedTab) {