Flutter DropdownButton in DataTable

3.1k Views Asked by At

In flutter I'm trying to have one of the columns of a DataTable be a DropdownButton, where the user can select from the DropdownButton and it changes that cells value (and not any other cells, so don't change values in the 1st column at all).

See below for example code (DropdownButton doesn't change cell value), also in DartPad.

enter image description here


void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DataTableDemo(),
    );
  }
}

class User {
  String firstName;
  String lastName;

  User({this.firstName, this.lastName});

  static List<User> getUsers() {
    return <User>[
      User(firstName: "Paul", lastName: "Rudd"),
      User(firstName: "Owen", lastName: "Wilson"),
      User(firstName: "Jonah", lastName: "Hill"),
    ];
  }
}

class DataTableDemo extends StatefulWidget {
  DataTableDemo() : super();

  final String title = "Data Table Flutter Demo";

  @override
  DataTableDemoState createState() => DataTableDemoState();
}

class DataTableDemoState extends State<DataTableDemo> {
  List<User> users;
  

  @override
  void initState() {
    users = User.getUsers();
    super.initState();
  }

  List<String> lastNamesList = <String>[
    'Rudd',
    'Wilson',
    'Hill',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('DropdownButton in DataTable'),
        ),
        body: SingleChildScrollView(
          scrollDirection: Axis.vertical,
          child: DataTable(
            columns: [
              DataColumn(
                label: Text("FIRST NAME"),
                numeric: false,
                tooltip: "This is First Name",
              ),
              DataColumn(
                label: Text("LAST NAME"),
                numeric: false,
                tooltip: "This is Last Name",
              ),
            ],
            rows: users
                .map(
                  (user) => DataRow(cells: [
                    DataCell(
                      Text(user.firstName),
                      onTap: () {
                        print('Selected firstName: ${user.firstName}');
                      },
                    ),

                    DataCell(DropdownButton<String>(
                      value: user.lastName,
                      onChanged: (String newValue) {
                        setState(() {
                          //help! 
                        });
                      },
                      items: lastNamesList
                          .map<DropdownMenuItem<String>>((String value) {
                        return DropdownMenuItem<String>(
                          value: value,
                          child: Text(value),
                        );
                      }).toList(),
                    ))
                  ]),
                )
                .toList(),
          ),
        ));
  }
}
1

There are 1 best solutions below

2
On BEST ANSWER

You can copy paste run full code below
Step 1: You can use a List selectedUser to record each selection
Step 2: Use selectedUser.asMap().entries.map to get index
code snippet

List<User> selectedUser;
...
rows: selectedUser.asMap().entries.map((user) {
              int idx = user.key;
              print(idx);
              return DataRow(cells: [
                DataCell(
                  Text(selectedUser[idx].firstName),
                  onTap: () {
                    print('Selected firstName: ${selectedUser[idx].firstName}');
                  },
                ),
                DataCell(DropdownButton<User>(
                  value: selectedUser[idx],
                  onChanged: (User newUser) {
                    setState(() {
                      selectedUser[idx] = newUser;
                    });
                  },
                  items: users.map<DropdownMenuItem<User>>((User value) {
                    return DropdownMenuItem<User>(
                      value: value,
                      child: Text(value.lastName),
                    );
                  }).toList(),
                ))
              ]);
            }).toList(),

working demo

enter image description here

full code

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DataTableDemo(),
    );
  }
}

class User {
  String firstName;
  String lastName;

  User({this.firstName, this.lastName});

  static List<User> getUsers() {
    return <User>[
      User(firstName: "Paul", lastName: "Rudd"),
      User(firstName: "Owen", lastName: "Wilson"),
      User(firstName: "Jonah", lastName: "Hill"),
    ];
  }
}

class DataTableDemo extends StatefulWidget {
  DataTableDemo() : super();

  final String title = "Data Table Flutter Demo";

  @override
  DataTableDemoState createState() => DataTableDemoState();
}

class DataTableDemoState extends State<DataTableDemo> {
  List<User> users;
  List<User> selectedUser;

  @override
  void initState() {
    users = User.getUsers();
    selectedUser = List.from(users);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('DropdownButton in DataTable'),
        ),
        body: SingleChildScrollView(
          scrollDirection: Axis.vertical,
          child: DataTable(
            columns: [
              DataColumn(
                label: Text("FIRST NAME"),
                numeric: false,
                tooltip: "This is First Name",
              ),
              DataColumn(
                label: Text("LAST NAME"),
                numeric: false,
                tooltip: "This is Last Name",
              ),
            ],
            rows: selectedUser.asMap().entries.map((user) {
              int idx = user.key;
              print(idx);
              return DataRow(cells: [
                DataCell(
                  Text(selectedUser[idx].firstName),
                  onTap: () {
                    print('Selected firstName: ${selectedUser[idx].firstName}');
                  },
                ),
                DataCell(DropdownButton<User>(
                  value: selectedUser[idx],
                  onChanged: (User newUser) {
                    setState(() {
                      selectedUser[idx] = newUser;
                    });
                  },
                  items: users.map<DropdownMenuItem<User>>((User value) {
                    return DropdownMenuItem<User>(
                      value: value,
                      child: Text(value.lastName),
                    );
                  }).toList(),
                ))
              ]);
            }).toList(),
          ),
        ));
  }
}

full code 2, first column value not change

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DataTableDemo(),
    );
  }
}

class User {
  String firstName;
  String lastName;

  User({this.firstName, this.lastName});

  static List<User> getUsers() {
    return <User>[
      User(firstName: "Paul", lastName: "Rudd"),
      User(firstName: "Owen", lastName: "Wilson"),
      User(firstName: "Jonah", lastName: "Hill"),
    ];
  }
}

class DataTableDemo extends StatefulWidget {
  DataTableDemo() : super();

  final String title = "Data Table Flutter Demo";

  @override
  DataTableDemoState createState() => DataTableDemoState();
}

class DataTableDemoState extends State<DataTableDemo> {
  List<User> users;
  List<User> selectedUser;

  @override
  void initState() {
    users = User.getUsers();
    selectedUser = List.from(users);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('DropdownButton in DataTable'),
        ),
        body: SingleChildScrollView(
          scrollDirection: Axis.vertical,
          child: DataTable(
            columns: [
              DataColumn(
                label: Text("FIRST NAME"),
                numeric: false,
                tooltip: "This is First Name",
              ),
              DataColumn(
                label: Text("LAST NAME"),
                numeric: false,
                tooltip: "This is Last Name",
              ),
            ],
            rows: users.asMap().entries.map((user) {
              int idx = user.key;
              print(idx);
              return DataRow(cells: [
                /*DataCell(
                  Text(selectedUser[idx].firstName),
                  onTap: () {
                    print('Selected firstName: ${selectedUser[idx].firstName}');
                  },
                ),*/
                DataCell(
                  Text(user.value.firstName),
                  onTap: () {
                    print('Selected firstName: ${user.value.firstName}');
                  },
                ),
                DataCell(DropdownButton<User>(
                  value: selectedUser[idx],
                  onChanged: (User newUser) {
                    setState(() {
                      selectedUser[idx] = newUser;
                    });
                  },
                  items: users.map<DropdownMenuItem<User>>((User value) {
                    return DropdownMenuItem<User>(
                      value: value,
                      child: Text(value.lastName),
                    );
                  }).toList(),
                ))
              ]);
            }).toList(),
          ),
        ));
  }
}