2

I have a list of food items. That has a category, subCategory1, subCategory2 ect.

When the user unselects an category item. They are also unselecting the subCategory1, subCatategory2 items etc as they are children of the original categogory item like this:

enter image description here

enter image description here

enter image description here

So I have a for loop that is running through looking for children category list elements and removing them like this:

  // Remove a category item and all of its children
  if (categoryType == "category") {
    List<String> subCategory1Children = List<String>.from(
        snapshot.data.documents[gridIndex]['subCategory1Children']);

    // Remove the subcategory items
    for (int i = 0; i < foodDrinkMenuElements['subCategory1'].length; i++) {
      String subID = foodDrinkMenuElements['subCategory1'][i];
      int removalIndex = _indexOfListGridElement('subCategory1', subID);

      if (subCategory1Children.contains(subID)) {
        _removeCategoryGridItem(removalIndex, subID, 'subCategory1');
      }
    }

    //Remove the actual item being pressed
    _removeCategoryGridItem(listIndex + 1, id, categoryType);
  }

Which calls _removeCategoryGridItem() like this:

void _removeCategoryGridItem(int removalIndex, String id, String categoryType) {
  _FoodandDrinkKey.currentState.removeItem(removalIndex,
      (BuildContext context, Animation<double> animation) {
    return _buildListItem(removalIndex, animation);
  });
  foodDrinkMenuElements[categoryType].remove(id);
}

The For loop is always finishing after 1 list item is removed. I assume this is because of the return statement in the function _removeCategoryGridItem.

I have seen other answers that say to put it in an list and run through the list but I don't see how that applies here.

Thanks for your help

1 Answer 1

3

The For loop is always finishing after 1 list item is removed. I assume this is because of the return statement in the function _removeCategoryGridItem.

No, generally the only way that a function could break out of a loop in a calling function is by throwing an exception.

I don't know what type foodDrinkMenuElements[categoryType] returns, but presuming that it's a List, Map, or Set, you cannot remove items from the collection while you iterating over the collection.

From the List documentation:

It is generally not allowed to modify the list's length (adding or removing elements) while an operation on the list is being performed.... Changing the list's length while it is being iterated ... will break the iteration.

There is similar language for Map and Set.

I have seen other answers that say to put it in an list and run through the list but I don't see how that applies here.

That is exactly what you should do: you should queue which items to remove and then process the queue to avoid mutating the same collection you're iterating over:

final pendingRemoves = List<void Function()>[];

// Remove the subcategory items
for (int i = 0; i < foodDrinkMenuElements['subCategory1'].length; i++) {
  String subID = foodDrinkMenuElements['subCategory1'][i];
  int removalIndex = _indexOfListGridElement('subCategory1', subID);

  if (subCategory1Children.contains(subID)) {
    pendingRemoves.add(() =>
        _removeCategoryGridItem(removalIndex, subID, 'subCategory1'));
  }
}

// Since an index is involved, you also need to remove in reverse order so that
// the queued indices still refer to the same elements.
for (pendingRemove in pendingRemoves.reversed) {
  pendingRemove();
}

//Remove the actual item being pressed
_removeCategoryGridItem(listIndex + 1, id, categoryType);
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your answer. What I don't understand you said "you should queue which items to remove and then process the queue to avoid mutating the same collection you're iterating over." if you put them in a list to queue would that that not need to be iterated over anyway? even if it's asynchronous wouldn't the return statement still break the iteration? Thanks again
@NicholasMuir No, because the queue you'd be iterating over would be a different collection from the collection you're removing from.
I assume what you are saying is to make a List <_removeCategoryGridItem> and do a for loop on that. How would I then get that to execute as _removeCategoryGridItem() is a function?
@NicholasMuir I've updated my answer with a more specific example.
Thank you very much! I will give it a try.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.