Ionic3 <ion-segment> w/dynamic content won't show selected CSS class

3.5k views Asked by At

I'm using Angular 4 Reactive Forms, with "Ionic(3) native" UI components, and techniques from various "nested reactive forms" blogs/tutorials to create a dynamic, multi-section data entry app.

I wanted a reusable segmented control component that takes in a title & an array of options (based on a dropdown selection) so I don't have to create multiple nearly identical sub-form components.

It all works great the 1st time, but appeared to break after a subsequent selection if the ion-segment changes its number of buttons or their label values (if 2 selections happen to have identical options, the segment buttons all still work fine).

Example: The initial set of 3 options had "adult & "unknown" ... enter image description here

After changing the dropdown & the passed-in array of segment options, the common choices can still be selected, but I cannot set "calf" or "yearling" as Active (although in the component code & formGroup model it does get set). If I first select "goat", which only has 1 "unknown" option, that's the only one I can select.

enter image description here

"Calf" only turns light/disabled instead of "Active". This is what I need to fix.

It properly updates to show the correct number of buttons with the correct labels, and it properly updates the formGroup model even when it appears broken, but the "Active" state only works for the 1st selection. I've tried using (click) and (ionSelect) to call the method on the button, but no difference.

Basically everything seems to work except for the Ionic styling & CSS classes on subsequent changes to the @Input array of button options.

MY QUESTION: Where/how can I tell the Ionic <ion-segment> to only use the latest values & # of segments?? The examples in tutorials or Ionic docs use static lists and template-driven forms with [(ngModel)] data-binding, which I can't use w/a reactive form. Is this only possible with template-driven forms??

1

There are 1 answers

0
mc01 On BEST ANSWER

So after waaay too many hours wasted, turns out it's some problem w/how Ionic applies CSS classes to components that use a structural directive ... None of the lifecycle or ChangeDetection methods worked because it was already up to date! Grrr ....

For future reference: If you use an *ngFor or *ngIf structural directive to generate your <ion-segment-button> elements, and you change either:

  1. the number of buttons in the segment or
  2. their values ...

The result is that it appears as if you cannot select updated segment buttons ...

But you can - it all works fine except for applying the segment-activated CSS class to the selected button and removing it from all the others.

If your updated segment data source has identical values & number of buttons, no problem. But, the segment-activated class won't get applied to any buttons that have a higher index or different value than previous ones.

I finally hacked together this ugly approach to fix the problem, and it'll have to do since I've wasted so much time on it already ...

<ion-segment formArrayName="segmentArray">
    <ion-segment-button *ngFor="let option of options; let i=index;" [value]="i" (tap)="setOption(i, $event)">{{option}}</ion-segment-button>
</ion-segment>

public setOption(index, event) {
    if (this.options[index] != null) {
      this.selectedSegment = this.options[index]; 

      //note you have to use "tap" or "click" - if you bind to "ionSelected" you don't get the "target" property
      let segments = event.target.parentNode.children;
      let len = segments.length;
      for (let i=0; i < len; i++) {
        segments[i].classList.remove('segment-activated');
      }
      event.target.classList.add('segment-activated');
}

It's ugly & ol'skool, but it gets the job done and I have no more time to make it fancy ...