Issue
I'm working at a page with multiple <ion-segment>
elements, some of which nested into async
containers.
Those ones do not get initialised correctly and the selected <ion-segment-button>
does not get highlighted as it should unless the initial value is hardcoded.
See example below:
HTML file
<ion-header>
<ion-toolbar>
<ion-title>Ionic Segment Bug Test</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-segment
[value]="segmentA$ | async"
(ionChange)="updateSegmentA($event.detail.value!)"
>
<ion-segment-button value="A-1">
<ion-label>segment A-1</ion-label>
</ion-segment-button>
<ion-segment-button value="A-2">
<ion-label>segment A-2</ion-label>
</ion-segment-button>
</ion-segment>
<p class="ion-text-center">segment A value = "{{ segmentA$.value }}"</p>
<hr />
<div *ngIf="observable$ | async as dataSource; else noData">
<ion-segment
[value]="segmentB"
(ionChange)="updateSegmentB($event.detail.value!)"
>
<ion-segment-button value="B-1">
<ion-label>segment B-1</ion-label>
</ion-segment-button>
<ion-segment-button value="B-2">
<ion-label>segment B-2</ion-label>
</ion-segment-button>
</ion-segment>
<p class="ion-text-center">segment B value = "{{ segmentB }}"</p>
<hr />
<ion-segment value="default">
<ion-segment-button value="default">
<ion-label>Default</ion-label>
</ion-segment-button>
<ion-segment-button value="segment">
<ion-label>Segment</ion-label>
</ion-segment-button>
</ion-segment>
</div>
<ng-template #noData>
<p class="ion-text-center">No data to display</p>
</ng-template>
</ion-content>
TS file (extract)
segmentA$ = new BehaviorSubject<string>('A-1');
observable$ = new Observable<any>();
segmentB = 'B-1';
constructor() {
this.fetchData();
}
updateSegmentA(value: SegmentValue) {
this.segmentA$.next(value as string);
}
updateSegmentB(value: SegmentValue) {
this.segmentB = value as string;
}
private fetchData() {
let option: string;
this.observable$ = this.segmentA$.pipe(
distinctUntilChanged(),
tap((o) => (option = o)),
delay(1000),
map(() => option),
);
}
See full example on GitHub or StackBlitz.
I tried using [(ngModel)]
or BehaviorSubject
with async
pipe without avail.
Solution
Looks like some bug due to state of the internal variable of ionic, as a temporary workaround, you can use the below method!
If needed do raise a bug on the ionic github page!
I am triggering change detection manually and toggling the property for [value]
binding so that the changes will get detected by the component!
ts
import { AsyncPipe, CommonModule, NgIf } from '@angular/common';
import { ChangeDetectorRef, Component, ViewChild } from '@angular/core';
import { IonContent,
IonHeader,
IonLabel,
IonSegment,
IonSegmentButton,
IonTitle,
IonToolbar,
SegmentValue, } from '@ionic/angular/standalone';
import { BehaviorSubject, Observable, distinctUntilChanged, tap, delay, map,finalize } from 'rxjs';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
standalone: true,
imports: [AsyncPipe, IonContent, IonHeader, IonLabel, IonSegment, IonSegmentButton, IonTitle, IonToolbar, CommonModule],
})
export class HomePage {
segmentA$ = new BehaviorSubject<string>('A-1');
observable$ = new Observable<any>();
segmentB = '';
constructor(private cdr: ChangeDetectorRef) {
this.fetchData();
}
updateSegmentA(value: SegmentValue) {
this.segmentA$.next(value as string);
}
updateSegmentB(value: SegmentValue) {
this.segmentB = value as string;
}
private fetchData() {
let option: string;
this.observable$ = this.segmentA$.pipe(
distinctUntilChanged(),
tap((o) => (option = o)),
delay(1000),
map(() => option),
tap(() => {
this.bugWorkAround();
})
);
}
bugWorkAround() {
this.segmentB = '';
this.cdr.markForCheck();
setTimeout(() => {
this.segmentB = 'B-1';
this.cdr.markForCheck();
})
}
}
html
<ion-header>
<ion-toolbar>
<ion-title>Ionic Segment Bug Test</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-segment
[value]="segmentA$ | async"
(ionChange)="updateSegmentA($event.detail.value!)"
>
<ion-segment-button value="A-1">
<ion-label>segment A-1</ion-label>
</ion-segment-button>
<ion-segment-button value="A-2">
<ion-label>segment A-2</ion-label>
</ion-segment-button>
</ion-segment>
<p class="ion-text-center">segment A value = "{{ segmentA$.value }}"</p>
<hr />
<div *ngIf="(observable$ | async) as dataSource; else noData">
<ion-segment
[value]="segmentB"
(ionChange)="updateSegmentB($event.detail.value!)"
>
<ion-segment-button value="B-1">
<ion-label>segment B-1</ion-label>
</ion-segment-button>
<ion-segment-button value="B-2">
<ion-label>segment B-2</ion-label>
</ion-segment-button>
</ion-segment>
<p class="ion-text-center">segment B value = "{{ segmentB }}"</p>
<hr />
<ion-segment value="default">
<ion-segment-button value="default">
<ion-label>Default</ion-label>
</ion-segment-button>
<ion-segment-button value="segment">
<ion-label>Segment</ion-label>
</ion-segment-button>
</ion-segment>
</div>
<ng-template #noData
><p class="ion-text-center">No data to display</p></ng-template
>
</ion-content>
Answered By - Naren Murali
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.