magmast
magmast

Reputation: 1

Is there any way to handle List in app state in Flutter?

I want to have few Lists, which I can provide using Provider from provider package. I can add or remove elements from each of them. And elements of those lists are objects that can be changed too. I want my application to react to all of those changes.

For now I need to create separate class for each of those lists. Each of them has a field with List and methods to access, remove or add its elements. This requires a lot of boilerplate and handling changes in fields of elements is hard.

// I would like to use ChangeNotifier here, but then I need to make all fields
// private, write getters and setters for them and assign them manually in
// constructor.
class Model {
  int amount;

  Model(this.amount);
}

class ModelService extends ChangeNotifier {
  final models = <Model>[];

  UnmodifiableListView<Model> get all => UnmodifiableListView(models);

  int get length => models.length;

  remove(Model model) {
    models.remove(model);
    notifyListeners();
  }

  add(Model model) {
    models.add(model);
    notifyListeners();
  }

  Model elementAt(int index) => models.elementAt(index);

  elementChanged() => notifyListeners();
}

class ExampleWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Column(
    children: [
      RaisedButton(
        child: Text('Add model'),
        onPressed: () => Provider.of<ModelService>(context).add(Model(0)),
      ),
      Expanded(
        child: Consumer<ModelService>(
          builder: (context, service, child) {
            return ListView.builder(
              itemBuilder: (context, index) {
                if (index >= service.length) {
                  return null;
                }

                final model = service.elementAt(index);

                return ListTile(
                  leading: IconButton(
                    icon: Icon(Icons.add),
                    onPressed: () {
                      model.amount++;
                      service.elementChanged();
                    },
                  ),
                  title: Text(model.amount.toString()),
                  trailing: IconButton(
                    icon: Icon(Icons.delete),
                    onPressed: () => service.remove(model),
                  ),
                );
              },
            );
          },
        ),
      ),
    ],
  );
}

Is there any simpler or more idiomatic way to handle such cases?

Upvotes: 0

Views: 444

Answers (1)

szotp
szotp

Reputation: 2622

You can use Generics to make your object reusable:

class ModelService<Model> extends ChangeNotifier {
  final models = <Model>[];

  UnmodifiableListView<Model> get all => UnmodifiableListView(models);

  int get length => models.length;

  remove(Model model) {
    models.remove(model);
    notifyListeners();
  }

  add(Model model) {
    models.add(model);
    notifyListeners();
  }

  Model elementAt(int index) => models.elementAt(index);

  elementChanged() => notifyListeners();
}

Something I would often do is inherit from that class and add extra logic to it: sorting, fetching, filtering, saving, etc. For example:

class TodoService extends ModelService<Todo> {
  add(Todo model) {
    super.add(model);
    // save the list on disk
  }

  void setSearchText(String searchText) {
    // apply search text on the models list
  }
}

This way your widgets can become much simpler.

Upvotes: 1

Related Questions