mctuna
mctuna

Reputation: 871

Ionic 3 Tabs are not refreshed after initialized

Each tab calls the same Component "EventDetailItemsComponent" with different navParams. And the async data (Observable) is retrieved from this.itemService and displayed as expected.

Problem starts when I switch back to the same tab the second time. Since Component is not called again, it displays the same async data. So tab view is not updated.

What I want is to call EventDetailItemsComponent every time a tab is clicked. Not just on the first click.

Would it be the right way to pass that async data from parent component EventDetailComponent to child component EventDetailItemsComponent with (ionSelect)="myMethod()"

    <ion-tabs no-margin no-padding selectedIndex="1">
        <ion-tab [root]="EventDetailItems1" [rootParams]="{itemTypeId:1, eventId: (eventDetail | async)?.id}" tabTitle="{{'ALL' | translate}}"></ion-tab>
        <ion-tab [root]="EventDetailItems2" [rootParams]="{itemTypeId:2, eventId: (eventDetail | async)?.id}" tabTitle="{{'BOUGHT' | translate}}"></ion-tab>
        <ion-tab [root]="EventDetailItems3" [rootParams]="{itemTypeId:3, eventId: (eventDetail | async)?.id}" tabTitle="{{'LEFT' | translate}}"></ion-tab>
    </ion-tabs>


    export class EventDetailComponent implements OnInit {

        EventDetailItems1: any = EventDetailItemsComponent;
        EventDetailItems2: any = EventDetailItemsComponent;
        EventDetailItems3: any = EventDetailItemsComponent;

        constructor(){ }
    }

Child Component EventDetailItemsComponent and its html

    @Component({
        selector: 'event-detail-items',
        styleUrls: ['/event-detail-items.scss'],
        templateUrl: 'event-detail-items.html'
    })
    export class EventDetailItemsComponent implements OnInit, OnChanges  {
        private _itemDetail = new BehaviorSubject<ItemViewModel[]>(null);
        itemDetail = this._itemDetail.asObservable();

        itemToggle: number = 0;
        lastImage: string = null;
        loading: Loading;

        constructor(
            public itemService: ItemService,
            public eventService: EventService,
            public navParams: NavParams,
            public navCtrl: NavController,
            public loadingCtrl: LoadingController,
            private app: App) {

        }

        ngOnInit() {
            let itemParams: GiftItemTabNavParams = JSON.parse(JSON.stringify(this.navParams.data));                
            this.itemService.getItemList(itemParams.eventId, itemParams.itemTypeId).subscribe(x => {
                this._itemDetail.next(x);
            });
        }
    }


          <ion-grid id="gift-list-grid">                
            <ion-row class="gift-list-row" *ngFor="let giftItem of (itemDetail | async)" text-center bottom>
                <ion-col (click)="toggleItemDescription(giftItem.id)" class="gift-item-col-item-pic" col-3>
                    <img src="{{giftItem.giftImagePath}}" />
                </ion-col>
                <ion-col (click)="toggleItemDescription(giftItem.id)" class="gift-item-col-detail" col-6>
                    <ion-label text-wrap class="gift-item-text" no-margin text-left>
                        <span>
                            {{giftItem.giftItemName}}
                        </span>
                        <span>
                            {{giftItem.brand}}
                        </span>
                    </ion-label>
                </ion-col>
                <ion-col (click)="toggleItemDescription(giftItem.id)" class="gift-item-col-gift-count" col-3>
                    <img src="./assets/img/inner-pages/gift_box.png" />
                    <p>
                        {{giftItem.amount}}
                    </p>
                </ion-col>
                <ion-col (click)="toggleItemDescription(giftItem.id)" *ngIf="itemToggle == giftItem.id" col-9>
                    <ion-label text-wrap class="gift-item-description" no-margin text-left>
                        <span>
                            {{giftItem.amount}} {{'AMOUNT' | translate}}
                        </span>
                        <span>
                            {{giftItem.description}}
                        </span>
                    </ion-label>
                </ion-col>
                <ion-col (click)="toggleBuyStatus(giftItem.id, giftItem.isBought, giftItem.giftStatus)" *ngIf="itemToggle == giftItem.id" class="gift-item-col-detail"  col-3>
                    <!--RESERVABLE ITEM-->
                    <img *ngIf="giftItem.giftStatus == 0" src="./assets/img/inner-pages/free.png" />
                    <!--CAN BE UNRESERVED-->
                    <img *ngIf="giftItem.giftStatus == 1" src="./assets/img/inner-pages/unreservable.png" />
                    <!--CAN NOT BE UNRESERVED-->
                    <img *ngIf="giftItem.giftStatus == 2" src="./assets/img/inner-pages/not-unreservable.png" />
                </ion-col>
            </ion-row>
        </ion-grid>

UPDATE: As Sampath suggests, Events solved the problem. You can find the usage below:

Root EventDetailComponent - Event Publish:

public eventTabsChanged(itemTypeId) {
            let event = this._eventDetail.getValue();
            this.events.publish('tab:clicked', itemTypeId, event.id);
        }

Tab content EventDetailItemsComponent - Event Subscribe

    constructor(
            public itemService: ItemService,       
            public events: Events) {
            events.subscribe('tab:clicked', (itemTypeId, eventId) => {
                this.itemService.getItemList(eventId, itemTypeId).subscribe(x => {
                    this._itemDetail.next(x);
                });
            });
        }

Upvotes: 2

Views: 2769

Answers (1)

Sampath
Sampath

Reputation: 65978

It seems you need to know how to pass data between parent to child.So you can do it using input properties.

Option 1:

In your case :

<event-detail-items [itemDetail]="itemDetail"></event-detail-items>

Please see the offical doc here.

child.ts

import { Component, Input } from '@angular/core';

import { Hero } from './hero';

@Component({
  selector: 'hero-child',
  template: `
    <h3>{{hero.name}} says:</h3>
    <p>I, {{hero.name}}, am at your service, {{masterName}}.</p>
  `
})
export class HeroChildComponent {
  @Input() hero: Hero;
  @Input('master') masterName: string;
}

parent.ts

import { Component } from '@angular/core';

import { HEROES } from './hero';

@Component({
  selector: 'hero-parent',
  template: `
    <h2>{{master}} controls {{heroes.length}} heroes</h2>
    <hero-child *ngFor="let hero of heroes"
      [hero]="hero"
      [master]="master">
    </hero-child>
  `
})
export class HeroParentComponent {
  heroes = HEROES;
  master = 'Master';
}

Option 2: Using Events

Upvotes: 1

Related Questions