So, for example I have 2 similar tabs. One of them below. Each tab has its own content, I call it, subtab (mainContent, subContent), which are just switched content inside selected tab.
export class Tab1Component {
private tab1Data$;
constructor(private tab1Service: Tab1Service) {
const mainContent = { title: null, data: [] };
this.tab1Data$ = new BehaviorSubject({ mainContent, subContent: mainContent });
}
async ngOnInit(): Promise<void> {
// subscribe on changes per tab
this.qSubscr = combineLatest([this.tab1Service.tab1_Subtab1$, this.tab1Service.tab1_Subtab2])
.subscribe(([subtab1Data, subtab2Data]: any) => {
const currUObj = this.tab1Data$.value;
currUObj.mainContent = { title: 'Subtab 1', data: subtab1Data };
const title = `Subtab 2 ${subtab2Data && subtab2Data.length > 0 ? ` (${subtab2Data.length})` : ''}`;
currUObj.subContent = { title, data: subtab2Data };
this.tab1Data$.next(currUObj);
});
}
Each tab component has similar html.
<tab-template
[isDraggable]="true"
[tabObj]="tab1Data$"
[activeTab]=0
(clickOnItem)="clickOnItem($event)"
(clickHiddenOptions)="clickHiddenBtn($event)"
></tab-template>
TabTempateComponent.ts
export class TabTemplateComponent implements OnInit, OnDestroy {
public itemsList = [];
public activeSubTab: 'mainContent' | 'subContent';
public contentsItems: { mainContent: QuoteInProcess[], subContent: QuoteInProcess[] };
public chosenItems = [];
public draggedItem = null;
public tabTitleObj$: BehaviorSubject<TabTitleObject>;
@Input() isDraggable: boolean;
@Input() tabObj: BehaviorSubject<TabObject>;
@Input() activeTab: number;
@Output() clickOnItem: EventEmitter<any>;
@Output() clickHiddenOptions: EventEmitter<HiddenBtnEmitterObject>;
private tabObjSubscription: Subscription;
private selectedTabSubscription: Subscription;
constructor(private changeRef: ChangeDetectorRef, private tabbarService: TabbarService) {
this.tabTitleObj$ = new BehaviorSubject<TabTitleObject>({ mainTitle: null, subTitle: null });
this.clickOnQuote = new EventEmitter<any>();
this.clickHiddenBtn = new EventEmitter<HiddenBtnEmitterObject>();
}
ngOnInit() {
this.tabTitleObj$ = new BehaviorSubject<TabTitleObject>({ mainTitle: null, subTitle: null });
// this BehaviorSubject is filled from tabbar component on ionTabsWillChange event
this.selectedTabSubscription = this.tabbarService.selectedTab$.subscribe(tabInd => {
if ( this.activeTab === tabInd ) {
if ( this.activeSubTab && this.activeSubTab !== 'mainContent' ) {
return this.toggleContentOfTab('mainContent');
}
this.activeSubTab = 'mainContent';
if ( this.draggedItem ) {
this.draggedItem.closeDraggedQuote();
}
}
});
// listen to changes from parent tab Components (tab1Component and tab2Component)
this.tabObjSubscription = this.tabObj.subscribe(t => {
if ( !t ) {
return;
}
const { mainContent: { title: mainTitle, data: mainContent }, subContent: { title: subTitle, data: subContent } } = t;
this.tabTitleObj$.next({ mainTitle, subTitle });
this.contentsItems = { mainContent, subContent };
this.setItemsList();
});
}
trackByFn(index, item) {
return item._id;
}
// call this function once received relevant data from localStorage or DB
setItemsList() {
if (this.contentsItems) {
this.itemsList = this.chosenItems.length === 0 ?
this.contentsItems[this.activeSubTab] :
this.contentsItems[this.activeSubTab].filter(item => this.chosenItems.includes(item));
this.changeRef.detectChanges(); // to update View on changes
}
}
toggleContentOfTab(subTab: 'mainContent' | 'subContent') {
if (this.draggedItem) {
this.draggedItem.closeDraggedQuote();
}
this.chosenItems = [];
this.activeSubTab = subTab;
this.setItemsList();
}
async onItemDrag(event) {
const ratio = await event.getSlidingRatio();
if (!this.isDraggable || this.chosenItems.length > 0) {
return event.close();
}
if (ratio > -0.5 && ratio < 0.5) {
this.draggedItem = null;
} else {
this.draggedItem = event;
}
}
}
TabTemplateComponent.html
<app-searchbar
[chosenItems]="chosenItems"
(applyFilter)="setItemsList()"></app-searchbar>
<title-tab
[tabTitleObj]="tabTitleObj$"
[isMainContentActive]="activeSubTab === 'mainContent'"
(toggleSubTabs)="toggleContentOfTab($event)">
</title-tab>
<ion-content [scrollEvents]="true">
<ion-list inset>
<ion-item-sliding
*ngFor="let itemObj of itemsList; trackBy: trackByFn"
(ionDrag)="onItemDrag($event.target)">
<ion-item
detail
lines="none">
<ion-avatar slot="start"></ion-avatar>
<ion-label>
{{itemObj.text}}
</ion-label>
</ion-item>
<ion-item-options side="start">
<!-- Different buttons -->
</ion-item-options>
<ion-item-options side="end">
<!-- Different buttons -->
</ion-item-options>
</ion-item-sliding>
</ion-list>
</ion-content>
So, how I made tests:
- Open the app (which load all data from localStorage) on first tab
- Decrease Network speed to slow 3G
- Switch tab.
So If I use just ion-item inside of ion-list I see list immediately after switch, but if I use ion-item-sliding I see list once I get data from DB and not my default one from localStorage.