Utpaul
Utpaul

Reputation: 2007

dynamic tabs rendering in ionic3 and angular 5

I want to rendering dynamic tabs but i'm unable to doing this.First time tabs render well but when we change refreshTabs function parameter its tabs show with first time render tabs. Suppose first time load APP_TEACHER_TABS elements and when its change to ADMIN then its render APP_TEACHER_TABS and APP_ADMIN_TABS both but i want to render only APP_ADMIN_TABS.

root-tabs.ts

import {Component} from '@angular/core';
import {IonicPage, NavController, NavParams, PopoverController} from 'ionic-angular';
import {TabInterface} from "../../models/tabsModels";
import {AuthProvider} from "../../providers/auth";
import {APP_ADMIN_TABS, APP_STUDENT_TABS, APP_TEACHER_TABS} from "../../constants";
import {SwitchAccountService} from "../../providers/switch-account";

@IonicPage({
  name: 'page-root-tabs',
  priority: 'high'
})

@Component({
  selector: 'page-root-tabs',
  templateUrl: 'root-tabs.html',
})
export class RootTabsPage{

  tabs =[];
  userLabel: any;

  constructor(public navCtrl: NavController,
              public navParams: NavParams,
              private auth:AuthProvider,
              public popoverCtrl: PopoverController,
              private switchAccountService: SwitchAccountService) {

    this.initializeTabs();

  }

  initializeTabs(){

    this.switchAccountService
      .getUserLabel()
      .subscribe(message =>{
        this.userLabel = message;
        this.refreshTabs(this.userLabel);
      });
  }

  refreshTabs(item){

      if( item == 'ADMIN'){
        while(this.tabs.length){
          this.tabs.pop();
        }

        APP_ADMIN_TABS.forEach(el => {
          this.tabs.push(<TabInterface>{label: el.label, icon: el.icon, component: el.component});
        });

        // this.tabs.splice(this.tabs.indexOf(0), 1);
        // setTimeout(()=>{
        //   APP_ADMIN_TABS.forEach(el => {
        //     this.tabs.push(<TabInterface>{label: el.label, icon: el.icon, component: el.component});
        //   });
        // },4000);


        //this.tabs.splice(0,1);
      }

      else if(item == 'TEACHER'){

        APP_TEACHER_TABS.forEach(el => {
          this.tabs.push(<TabInterface>{label: el.label, icon: el.icon, component: el.component});
        });

      }

      else{

        if(this.auth.currentUser.user_flag == 2){

          APP_TEACHER_TABS.forEach(el => {
            this.tabs.push(<TabInterface>{label: el.label, icon: el.icon, component: el.component});
          });

        }else{

          APP_STUDENT_TABS.forEach(el => {
            this.tabs.push(<TabInterface>{label: el.label, icon: el.icon, component: el.component});
          });

        }
      }

  }

  presentPopover(myEvent) {
    let popover = this.popoverCtrl.create('page-popover');
    popover.present({
      ev: myEvent
    });
  }
}

root-tabs.html

<ion-header>
  <ion-navbar no-border-bottom color="customColor">

    <ion-title class="custom-font" style="font-size: 2.1em;" text-center>
      DASHBOARD
    </ion-title>

    <ion-buttons end>
      <button ion-button icon-only (click)="presentPopover($event)">
        <ion-icon name="md-more"></ion-icon>
      </button>
    </ion-buttons>

  </ion-navbar>
</ion-header>

<ion-tabs tabsPlacement="top">
  <ion-tab *ngFor="let tab of tabs"
           [tabIcon]="tab.icon"
           [tabTitle]="tab.label"
           [root]="tab.component">
  </ion-tab>
</ion-tabs>

Upvotes: 3

Views: 1286

Answers (1)

Daniel W Strimpel
Daniel W Strimpel

Reputation: 8470

I don't fully know how you have your system set up, but I put together a stackblitz that shows how to have the tabs dynamically change as the user changes.

As you discovered, Ionic doesn't really work correctly if you change the actual tabs that are rendered in it. What you can do is dynamically show/hide them using the [show] property.

<ion-tabs #ionTabs>
  <ion-tab *ngFor="let tab of tabs$ | async; trackBy: trackByFn"
           [tabIcon]="tab.icon"
           [tabTitle]="tab.label"
           [root]="tab.component"
           [show]="tab.show">
  </ion-tab>
</ion-tabs>

I put all of the tabs together into an array and gave a list of roles that have access to each of them.

export const TABS: TabInterface[] = [
  { label: 'Home', icon: 'home', component: HomePage, roles: [UserRole.Admin], show: false },
  { label: 'About', icon: 'information-circle', component: AboutPage, roles: [UserRole.Admin, UserRole.Teacher], show: false },
  { label: 'Contact', icon: 'contacts', component: ContactPage, roles: [UserRole.Teacher, UserRole.Student], show: false }
];

Then as the user changed, I processed the tabs to determine which the user had access to based on the roles they had:

tabs$ = this.userService.user$
    .takeUntil(this.destroy$.asObservable())
    .map(user => this.processTabsForUser(user))
    .do(tabs => this.selectCorrectTab(tabs));

...

private processTabsForUser(user: User): TabInterface[] {
    return TABS.map(tab => {
        return Object.assign({}, tab, { show: user && user.isAuthorized(tab.roles)});
    });
}

In order to properly work if the user changed while another was logged in (which shouldn't happen in a real system I wouldn't think but...) I had to process the current selected tab and make sure the user had access to it. If not, I would select the first tab the user had access to:

private selectCorrectTab(tabs: TabInterface[]) {
    const selectedTab = this.ionTabs.getSelected();
    const tab = tabs.find(t => selectedTab && t.component === selectedTab.root);

    if (!tab || !tab.show) {
        const index = tabs.findIndex(t => t.show);

        if (!!~index) {
            // bug in Ionic causes the need to do in setTimeout if user changes when already logged in
            setTimeout(() => this.ionTabs.select(index));
        }
    }
}

This should get your end result of having the tabs dynamically change based on the user that is logged in.

Upvotes: 5

Related Questions