Giulia
Giulia

Reputation: 807

Issue with handling boolean instance in Flutter class

In my flutter app I have a class and a list of classes like the following:

class GuestType {
  final String name;
  bool isActive;

  GuestType({this.name, this.isActive});
}

List<GuestType> _guestTypes = [
  GuestType(name: 'White', isActive: false),
  GuestType(name: 'Blue', isActive: false),
  GuestType(name: 'Lavander', isActive: false),
  GuestType(name: 'Green', isActive: false),
  GuestType(name: 'Pink', isActive: false),
  GuestType(name: 'Yellow', isActive: false)
];

I'm mapping through _guestTypes and creating a card containing the name instance. Each card has the onPress attribute and what I need to achieve is that when a card is pressed, the isActive instance is set to true. However, only one card can be true at any time, so when a card is pressed all the other cards must be set to false.

This is my code to achieve the desired result:

...
children: _guestTypes
                      .map(
                        (type) => Card(
                          colour: type.isActive == true
                              ? widgetAttivo
                              : widgetInattivo,
                          onPress: () {
                             setState(() {
                               _guestTypes
                                   .map((guest) => guest.isActive == true
                                       ? setState(() {
                                           guest.isActive = false;
                                           type.isActive = !type.isActive;
                                         })
                                       : setState(() {
                                           type.isActive = !type.isActive;
                                         }));
                             });
                     
                            
                          },
...

This code doesn't work, I can still select and activate multiple cards.

Any clue?

Thanks a lot.

Upvotes: 0

Views: 402

Answers (3)

nvoigt
nvoigt

Reputation: 77304

You are using the wrong tool for the job. map is a way to create a new iterable, by mapping each item to a new item. That is not what you want. You simply want to iterate the existing items. That has always been a job for a loop:

onPress: () {
  setState(() {
    for(var guest in _guestTypes) {
      guest.isActive = false;
      type.isActive = !type.isActive;
    }
  }
}

I also shortened your loop body. It does the same thing, but with half the code.

Upvotes: 1

ikerfah
ikerfah

Reputation: 2862

Using map and changing some attributes inside the callback will not affect you current list (This is why map returns Iterable).
So as a solution I will propose the following :

setState(() {
_guestTypes = _guestTypes.map((guest) {
  if(guest.name == type.name){
    guest.isActive = true;
  }else{
    guest.isActive = false;
  }
  return guest;
 }).toList();
});

You have to check if the selected item name is the same with the item in the map. make it isActive true and all the others false.

Upvotes: 1

casraf
casraf

Reputation: 21694

In your setState call, you are re-mapping _guestTypes, but are not doing anything with the return value. map() does not map in-place, it returns an updated map.

Also, you don't need to use setState both inside and outside the map function, only setting it around the content you want to update is enough (and better).

() {
    setState(() {
        // notice the change here - use the result and set the value in the state
        _guestTypes = _guestTypes
            .map((guest) { 
                    // set `true` for same guest type, `false` for others. 
                    // (use a different condition to compare them if that isn't good enough)
                    guest.isActive = type.name == guest.name; 

                    // needs to return the final value for each item
                    return guest;
            }).toList();
    });
},

Upvotes: 1

Related Questions