'Deleting an Item from one list using indexWhere() when presisng a button on an item from a different list Flutter

So far I have declared a FavoriteItems class like so:

enum Type {
  a,
  b,
  c,
}

class FavoriteItem {
  final String id;
  final String itemType;
  final String title;
  final String icon;
  final String item;
  final Type type;

  FavoriteItem({
    required this.id,
    required this.itemType,
    required this.title,
    required this.icon,
    required this.item,
    required this.type,
  });

  FavoriteItem copyWith({
    String? id,
    String? itemType,
    String? title,
    String? icon,
    String? item,
    Type? type,
  }) {
    assert(tags != null);
    return FavoriteItem(
      id: id ?? this.id,
      itemType: itemType ?? this.itemType,
      title: title ?? this.title,
      icon: icon ?? this.icon,
      item: item ?? this.item,
      type: type ?? this.type,
    );
  }
}

And have succesfully implemented a manager to add items from other lists to this list, and from the favorites screen to be able to safely delete it... buuut, On the screen where the items to be favorited are I run into the problem of not being able to write the propper getter to be able to remove this element from the favorites list when clicking again on the heart icon.

IconButton(
              onPressed: () {
                if (_isFavorite == false) {
                  setState(() {
                    _isFavorite = true;
                  });
                  final manager =
                      Provider.of<FavoritesManager>(context, listen: false);
                  manager.addItem(
                    FavoriteItem(
                        id: widget.mitem.id,
                        itemType: widget.mitem.itemType,
                        title: widget.mitem.title,
                        icon: widget.mitem.icon,
                        item: widget.mitem.item,
                        type: Type.a),
                  );
                }
                if (_isFavorite == true) {
                  setState(() {
                    _isFavorite = !_isFavorite;
                  });
                  final manager =
                      Provider.of<FavoritesManager>(context, listen: false);

                  manager.deleteItem(favoriteItem
                      .indexWhere(widget.mitem.id = favoriteItems.id));
                }
              },
              icon: Icon(_isFavorite ? Icons.favorite : Icons.favorite_border),
            )

I have tried things like

final FavoriteItem favoriteitem

And

final _favoriteItems = <FavoriteItem>[];

  List<FavoriteItem> get favoriteItems => List.unmodifiable(_favoriteItems);

But they all either show errors at the very "getter" line or later mention that the favoriteitem does not have an id declared.

My question is, how do I properly call for the favorite items list so as to be able to use the indexwhere method to successfully remove the item from the favorites list?

I am of course a complete begginner



Solution 1:[1]

for removing an item from your favelist you can write manager.removeWhere((element) => element.id == widget.mitem.id);

Solution 2:[2]

I would suggest rethinking the data structures you are using rather than trying to delete an item from a List using indexWhere. If you use a Set instead of a List to track which of the items have been favorited, you can delete an item in O(1) by simply calling the remove method. Whereas indexWhere on a List will be O(n).

Try this demo:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<FavoritesManager>.value(
          value: FavoritesManager(),
        ),
      ],
      child: const MaterialApp(
        home: FavoritesPage(),
      ),
    ),
  );
}

class FavoritesPage extends StatelessWidget {
  const FavoritesPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Consumer<FavoritesManager>(
      builder: (context, manager, child) => Scaffold(
        appBar: AppBar(
          title: const Text('Favorites Page'),
        ),
        body: Column(
          children: [
            for (final item in manager.items)
              ListTile(
                title: Text(item.title),
                leading: Text(item.icon),
                trailing: IconButton(
                  onPressed: () => manager.isFavorite(item)
                      ? manager.removeFavorite(item)
                      : manager.addFavorite(item),
                  icon: Icon(
                    manager.isFavorite(item)
                        ? Icons.favorite
                        : Icons.favorite_border,
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

class FavoritesManager extends ChangeNotifier {
  // favorites contains only those items that have been marked
  // as a favorite.
  final Set<Item> _favorites = {};

  // _items contains all of the items whether they have been
  // marked as favorite or not.
  // The list has been populated with some example data.
  final List<Item> _items = const [
    Item(
      id: '0',
      itemType: 'A Type',
      title: 'A Title',
      icon: 'A Icon',
      item: 'A Item',
      type: Type.a,
    ),
    Item(
      id: '1',
      itemType: 'B Type',
      title: 'B Title',
      icon: 'B Icon',
      item: 'B Item',
      type: Type.b,
    ),
    Item(
      id: '2',
      itemType: 'C Type',
      title: 'C Title',
      icon: 'C Icon',
      item: 'C Item',
      type: Type.c,
    ),
  ];

  List<Item> get items => List<Item>.unmodifiable(_items);

  bool isFavorite(Item item) {
    return _favorites.contains(item);
  }

  void addFavorite(Item item) {
    _favorites.add(item);
    notifyListeners();
  }

  void removeFavorite(Item item) {
    _favorites.remove(item);
    notifyListeners();
  }
}

enum Type {
  a,
  b,
  c,
}

// renamed FavoriteItem to Item to be less confusing,
// since not every item will be favorited.
class Item {
  final String id;
  final String itemType;
  final String title;
  final String icon;
  final String item;
  final Type type;

  const Item({
    required this.id,
    required this.itemType,
    required this.title,
    required this.icon,
    required this.item,
    required this.type,
  });

  Item copyWith({
    String? id,
    String? itemType,
    String? title,
    String? icon,
    String? item,
    Type? type,
  }) {
    return Item(
      id: id ?? this.id,
      itemType: itemType ?? this.itemType,
      title: title ?? this.title,
      icon: icon ?? this.icon,
      item: item ?? this.item,
      type: type ?? this.type,
    );
  }

  // Add == and hashCode so that this class can be used
  // in data structures that use hashing such as Set.
  @override
  bool operator ==(Object other) {
    return other is Item && id == other.id;
  }

  @override
  int get hashCode => id.hashCode;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 reza
Solution 2 mmcdon20