前提・実現したいこと
Cordova + OnsenUI + Angular な環境で、Menuでログイン/ログアウトを遷移させ、ログイン後のメインコンテンツページでは、Tabを使って画面遷移を実現したい
環境
ブラウザ:Chrome バージョン: 69.0.3497.100(Official Build) (64 ビット)
Angular CLI: 6.0.8
Node: 8.11.2
Angular: 6.1.7
ngx-onsenui: 4.2.2
onsenui: 2.10.4
発生している問題・エラーメッセージ
Tabbarのactive指定していないTabに遷移しようとすると以下のエラーが発生する
core.js:1673 ERROR Error: Uncaught (in promise): TypeError: page._show is not a function TypeError: page._show is not a function at HTMLElement._onPostChange (onsenui.js:30200) at onsenui.js:15288 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:388) at Object.onInvoke (core.js:3824) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:387) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:138) at zone.js:872 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421) at Object.onInvokeTask (core.js:3815) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420) at HTMLElement._onPostChange (onsenui.js:30200) at onsenui.js:15288 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:388) at Object.onInvoke (core.js:3824) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:387) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:138) at zone.js:872 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421) at Object.onInvokeTask (core.js:3815) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420) at resolvePromise (zone.js:814) at zone.js:724 at zone.js:740 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:388) at Object.onInvoke (core.js:3824) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:387) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:138) at zone.js:872 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421) at Object.onInvokeTask (core.js:3815)
該当のソースコード
以下がコンポーネントの構成になります
app.component(Menu実装) ├ menu.component └ contents.component - <router-outlet></router-outlet> ├ login.component(guard無し) └ main-contents.component(guard有り、Tab実装) ├ tab1.component(active) └ tab2.component
基本的にはOnsenUIの公式ドキュメントを、Angularのスタイルガイドに則ってきちんと分割しただけのコードになります。
app.component
html
1<ons-splitter #splitter> 2 <ons-splitter-side [page]="sidePage" side="left" width="220px" collapse swipeable> 3 </ons-splitter-side> 4 5 <ons-splitter-content [page]="contentPage"> 6 </ons-splitter-content> 7</ons-splitter> 8
ts
1import { Component, ViewChild } from '@angular/core'; 2 3import { ContentsService } from './components/main/contents/contents.service'; 4import { MenuComponent } from './components/main/menu/menu.component'; 5import { ContentsComponent } from './components/main/contents/contents.component'; 6 7@Component({ 8 selector: 'app-root', 9 templateUrl: './app.component.html', 10 styleUrls: ['./app.component.css'] 11}) 12export class AppComponent { 13 sidePage = MenuComponent; 14 contentPage = ContentsComponent; 15 @ViewChild('splitter') splitter; 16 17 constructor(private contentsService: ContentsService) { 18 this.contentsService.menu$.subscribe(() => this.splitter.nativeElement.side.toggle()); 19 } 20 21}
menu.component
html
1<ons-toolbar> 2 <ons-toolbar-button (click)="openMenu()"> 3 <ons-icon icon="ion-navicon, material:md-menu"></ons-icon> 4 </ons-toolbar-button> 5<div class="center">Left Page</div> 6</ons-toolbar> 7<div class="background"></div> 8<div class="content"> 9 <li class="nav-item active"> 10 <a routerLink="/logout" class="nav-link" href="#">ログアウト</a> 11 </li> 12</div>
ts
1import { Component, OnInit } from '@angular/core'; 2 3import { ContentsService } from './contents.service'; 4 5@Component({ 6 selector: 'ons-page[contents]', 7 templateUrl: './contents.component.html', 8 styleUrls: ['./contents.component.css'] 9}) 10export class ContentsComponent implements OnInit { 11 12 constructor(private service: ContentsService) { } 13 14 ngOnInit() { 15 } 16 17 openMenu() { 18 this.service.open(); 19 } 20 21}
contents.component
html
1<ons-toolbar> 2 <div class="left"> 3 <ons-toolbar-button (click)="openMenu()"> 4 <ons-icon icon="ion-navicon, material:md-menu"></ons-icon> 5 </ons-toolbar-button> 6 </div> 7 <div class="center">Content Page</div> 8</ons-toolbar> 9<router-outlet></router-outlet>
ts
1import { Component, OnInit } from '@angular/core'; 2 3import { ContentsService } from './contents.service'; 4 5@Component({ 6 selector: 'ons-page[contents]', 7 templateUrl: './contents.component.html', 8 styleUrls: ['./contents.component.css'] 9}) 10export class ContentsComponent implements OnInit { 11 12 constructor(private service: ContentsService) { } 13 14 ngOnInit() { 15 } 16 17 openMenu() { 18 this.service.open(); 19 } 20 21}
app-routing.module
ts
1import { NgModule } from '@angular/core'; 2import { Routes, RouterModule } from '@angular/router'; 3 4import { AuthGuard } from './modules/auth/auth.guard'; 5import { LoginComponent } from './components/auth/login/login.component'; 6import { MainContentsComponent } from './components/main-contents/main-contents.component'; 7 8const routes: Routes = [ 9 { 10 path: 'main-contents', 11 component: MainComtentsComponent, 12 canActivate: [AuthGuard] 13 }, 14 { path: 'login', component: LoginComponent }, 15 { path: '**', redirectTo: '/main-contents' }, 16]; 17 18@NgModule({ 19 imports: [RouterModule.forRoot(routes)], 20 exports: [RouterModule] 21}) 22export class AppRoutingModule { }
main-contents.component
html
1<ons-tabbar> 2 <div class="tabbar__content"></div> 3 <div class="tabbar"> 4 <ons-tab label="tab1" icon="ion-home" [page]="tab1" active></ons-tab> 5 <ons-tab label="tab2" icon="ion-ios-browsers" [page]="tab2"></ons-tab> 6 </div> 7</ons-tabbar>
ts
1import { Component, OnInit } from '@angular/core'; 2 3import { Tab1Component } from './tab1/tab1.component'; 4import { Tab2Component } from './tab2/tab2.component'; 5 6@Component({ 7 selector: 'app-main-contents', 8 templateUrl: './main-contents.component.html', 9 styleUrls: ['./main-contents.component.css'] 10}) 11export class MainContentsComponent implements OnInit { 12 13 tab1 = Tab1Component; 14 tab2 = Tab2Component; 15 16 constructor() { } 17 18 ngOnInit() { 19 } 20 21}
tab1.components
html
1<ons-toolbar> 2 <div class="center">Tab 1</div> 3</ons-toolbar> 4<div class="background"></div> 5<div class="content" class="initial-page"> 6 <div style="text-align: center; margin: 10px"> 7 <p>This is the first page.</p> 8 </div> 9</div>
ts
1import { Component, OnInit } from '@angular/core'; 2 3@Component({ 4 selector: 'ons-page[tab1]', 5 templateUrl: './tab1.component.html', 6 styleUrls: ['./tab1.component.css'] 7}) 8export class Tab1Component implements OnInit { 9 10 constructor() { } 11 12 ngOnInit() { 13 } 14 15}
tab2.component
html
1<ons-toolbar> 2 <div class="center">Tab 2</div> 3</ons-toolbar> 4<div class="background"></div> 5<div class="content" class="normal-page"> 6 <div style="text-align: center; margin: 10px"> 7 <p>This is the second page.</p> 8 </div> 9</div>
ts
1import { Component, OnInit } from '@angular/core'; 2 3@Component({ 4 selector: 'ons-page[tab2]', 5 templateUrl: './tab2.component.html', 6 styleUrls: ['./tab2.component.css'] 7}) 8export class Tab2Component implements OnInit { 9 10 constructor() { } 11 12 ngOnInit() { 13 } 14 15}
試したこと
各selectorの'ons-page'を区別する必要がある/ないが怪しいと思っており、
- 全て'ons-page'
- 全て'ons-page[**]'で区別
- Menu側だけ'ons-page'で、Tab側は'ons-page[**]'で区別
- Tab側だけ'ons-page'で、Menu側は'ons-page[**]'で区別
の4パターンを試しましたが、全てうまくいきませんでした。
別途、Menuだけの実装とTabだけの実装は、サンプル通り'ons-page'で統一してうまくいったことを確認しております。
あなたの回答
tips
プレビュー