How to update list of toggles in the DOM

Hi, I have a list of places that I want user to select from. The interface I chose for this is a toggle. I chose toggle because I really like the look and feel, and I may want to allow selecting multiple down the road.

<ion-list>
   <ion-item *ngFor="let location of places">
      <ion-label>{{location}}</ion-label>
         <ion-toggle (ionChange)="locationSelected($event, location)">
         </ion-toggle>
   </ion-item>
</ion-list>

Currently, however, I only want the user to select one toggle from that list. Which means when they select that toggle, all the other toggles will be checked to false. I’ve explored using ViewChild, contentRef. If I recall something about React, is that once I modify the data set (places), it would re-render the DOM. Does ng/ionic do something similar for my problem. I know it does it for a 2-way data bind. Is there a way to group all my toggles into an ngModel or something? A bit stuck. Thanks,

I’m very new to using ViewChild, but you may want to look into ViewChildren (also imported from @angular/core) <~ I think. Wherever ViewChild is imported from, i don’t have my computer on hand

Thanks! I’ll give it a try - googled that and found this video - https://www.youtube.com/watch?v=jYvIjd8rCVQ. Will go through it and see how it helps.

I tried a quick run-through (minus the ion-toggles) and it seems to provide the result you’re looking for. At least, a jumping off point.

<ion-list>
 <ion-item #items *ngFor="let place of places; let i = index" (click)="AlertMe($event, place, i)">
   {{place.name}}
 </ion-item>
</ion-list>
export class NewPopoverPage {

  @ViewChildren('items')myItems: ElementRef;

console.log(this.myItems) brings up all the items, so, hopefully it’s a start for you. Good luck!

1 Like

I would not use ViewChild here. Instead, I would do this:

<ion-toggle [checked]="location === selectedLocation"
  (ionChange)="locationSelected($event, location)">

constructor(cdr: ChangeDetectionRef) {}
locationSelected(toggle: Toggle, location: string) {
  // only pay attention to toggles becoming active or weirdness ensues
  if (toggle.value) {
    this.selectedLocation = location;
    // this is needed to avoid the dreaded "changed after checked"
    this.cdr.detectChanges();
  }
} 
3 Likes

Will try that as well ! I was in the middle of the ViewChildren implementation. Which is good exposure! But yes, the checked logic makes great sense :slight_smile:

Is it fair to say that ViewChild is to be reserved as a last resort / only if absolutely necessary?

I would basically agree with that. Anything that can be done using property binding should be. This particular question was considerably harder than I expected it to be at first. It’s really easy to write extremely simple buggy implementations of this that don’t work (see the two comments in my code).

The [checked] property seems to be surprisingly difficult to manipulate in tandem with other [checked]'s.

The most common mistake I see is people failing to grasp the fact that checked is completely ignored if the element is bound either to a FormControl or via [(ngModel)].

Perhaps we’ll be importing CheckedChild come Ionic 5, or something of the sort.

How does ```this.cdr.detectChanges() avoid the “changed after checked”? In this example, this isnt working for me.

It still checks against the locationSelected function 2x, first time toggle.value is true, second time toggle.value is false.

Should it be about using the detach() change detector method?

In this case, the “changed after checked” is an error message that Angular will throw up.

E.g. … has changed after it was checked. Previous value: … Current value: …

I just now caught that ChangeDetectionRef reference. Fantastic asset I wasn’t aware of. Thanks!