pasonmoasca
pasonmoasca

Reputation: 31

increment counter for a specific list item in Flutter

Good evening, As in my example image, below, I want to increase or decrease the quantity on button click for a single item in the listing. If I increment the counter in setState(), it is incremented in each element of the list. From what I understand you need to find the index, but it doesn't work (I tried different solutions where there is onPressed)

enter image description here

        import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:db_local/db.dart';
    import 'package:db_local/edit_student.dart';
    
    class ListStudents extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _ListStudents();
      }
    }
    
    class _ListStudents extends State<ListStudents> {
      int _itemCount = 0;
    
      List<Map> slist = [];
      MyDb mydb = MyDb();
    
      @override
      void initState() {
        mydb.open();
        getdata();
        super.initState();
      }
    
      getdata() {
        Future.delayed(const Duration(milliseconds: 500), () async {
          slist = await mydb.db.rawQuery('SELECT * FROM students');
          setState(() {});
        });
      }
    
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("List of Students"),
      ),
      body: SingleChildScrollView(
        child: Container(
          child: slist.isEmpty
              ? const Text("No any students to show.")
              : Column(
                  children: slist.map((stuone) {
                    ListView.builder(
                      itemCount: slist.length,
                      itemBuilder: (context, index) {
                        List<int> itemCounts =
                            List.generate(slist.length, (_) => 0);
                        return Card(
                            child: ListTile(
                          leading: const Icon(Icons.people),
                          title: Text(stuone["name"] + " " + stuone["ID"]),
                          subtitle: Text("Numero Carte:" +
                              stuone["roll_no"].toString() +
                              ", Add: " +
                              stuone["address"]),
                          trailing: Row(
                            mainAxisSize: MainAxisSize.min,
                            children: <Widget>[
                              IconButton(
                                icon: const Icon(Icons.remove),
                                onPressed: () =>
                                    setState(() => itemCounts[index]--),
                              ),
                              Text('$itemCounts'),
                              IconButton(
                                icon: const Icon(Icons.add),
                                onPressed: () =>
                                    setState(() => itemCounts[index]++),
                              ),
                            ],
                          ),
                        ));
                      },
                    );
                  }).toList(),
                ),
        ),
      ),
    );
  }
    }

Update Code

class ListStudents extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ListStudents();
  }
}

class _ListStudents extends State<ListStudents> {
  //int _counts = 0;
  List<int> _itemCounts;

  List<Map> slist = [];
  MyDb mydb = MyDb();

  //_ListStudents(this._itemCounts);

  @override
  void initState() {
    mydb.open();
    getdata();
    super.initState();
  }

  getdata() {
    Future.delayed(const Duration(milliseconds: 500), () async {
      slist = await mydb.db.rawQuery('SELECT * FROM students');
      _itemCounts = List.generate(slist.length, (_) => 0);
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("List of Students"),
      ),
      body: slist.isEmpty
          ? Text('No any students to show.')
          : ListView.builder(
              itemCount: slist.length,
              itemBuilder: (context, index) {
                final stuone = slist[index];
                return Card(
                  child: ListTile(
                    leading: const Icon(Icons.people),
                    title: Text(stuone["name"] + " " + stuone["ID"]),
                    subtitle: Text("Numero Carte:" +
                        stuone["roll_no"].toString() +
                        ", Add: " +
                        stuone["address"]),
                    trailing: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        IconButton(
                          icon: const Icon(Icons.remove),
                          onPressed: () => setState(() => _itemCounts[index]--),
                        ),
                        Text(_itemCounts[index].toString()),
                        IconButton(
                          icon: const Icon(Icons.add),
                          onPressed: () => setState(() => _itemCounts[index]++),
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),
    );
  }
}

Upvotes: 0

Views: 1160

Answers (1)

Robert Sandberg
Robert Sandberg

Reputation: 8607

Instead of slist.map((stuone) {...} you could use the ListView.builder() instead which gives you the index for each element that will be displayed.

So something like this:

ListView.builder(
  itemCount: slist.length,
  itemBuilder: (context, index) {
    return Card(
      child: ListTile( ... )
    ),
  },
)

There are different options for storing the state. But without to much intervention you could instead of int _itemCount = 0 have a List<int> itemCounts = List.generate(slist.length, (_) => 0); which you set after you've fetched the data and assign to a state variable.

You can then for each button, increment or decrement the value e.g. as: itemCounts[index]++;

Update to clarify:

Obviously not tested, but this should give you directions for how to construct the code and use the widgets. You shouldn't use the ListView as you did within a column within a scrollview.

// under class _ListStudents extends State<ListStudents> {
late final List<int> _itemCounts;

// assign _itemCounts in getData()
getdata() {
        Future.delayed(const Duration(milliseconds: 500), () async {
          slist = await mydb.db.rawQuery('SELECT * FROM students');
          _itemCounts = List.generate(slist.length, (_) => 0);
          setState(() {});
        });
      }


// When building your scaffold:
body: slist.isEmpty ? 
  Text('No any students to show.') : 
  ListView.builder(
    itemCount: slist.length,
    itemBuilder: (context, index) {
      final stuone = slist[index];
       return Card(
       ....
      );
    }
  )

Upvotes: 2

Related Questions