Flutter display sql data in ListTile instead of DataCell - flutter

I am displaying a list of data fetched from my sql database using DataCell, but I don't really like how it looks and want to switch it to display it using ListTile, this is the code that I am using to display it using DataCell:
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: [
DataColumn(
label: Text(''),
)
],
rows: _chatUsers
.map(
(user) => DataRow(cells: [
DataCell(
Text(user.firstNameUser),
// Add tap in the row and populate the
// textfields with the corresponding values to update
onTap: () {
// Set the Selected employee to Update
_selectedUser = user;
setState(() {
});
},
),
]),
)
.toList(),
),
),
);

You need to use the ListView widget for this.
There is a lot explained in that API reference section, I think you will be able to rework you app after reading.
So you will have a ListView with the childrenproperty set to smth like
_chatUsers
.map(
(user) =>
ListTile(
title: Text(user.firstNameUser),
// Add tap in the row and populate the
// textfields with the corresponding values to update
onTap: () {
// Set the Selected employee to Update
_selectedUser = user;
setState(() {
});
},
),
)
.toList()

Related

ListView.builder and Hive database, misaligned index when deleted an entry

I have a listView.builder building a list for me using information from Hive database.
If I create 3 entries (0, 1, 2), the builder will be like this (0,1,2). If Idelete the (1) hive database keys become this (0,2), but the index generated by the listviewBuilder becomes this (0,1). misaligning the data.
Each entry is an instance of a Person object, just so you guys know
What is the solution? There is a function to recreate the Keys without holes?
Created DB and ListView Builder
Deleted the second card
return ListView.builder(
itemCount: peopleList.length,
itemBuilder: (context, index) {
return Card(
child: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(
(Icons.person),
color: Colors.teal,
),
title: Text(
" ${peopleList[index].name} (${peopleList[index].vehicleType} ${peopleList[index].partieRole} ) ${isDriver(index)}"),
subtitle: Text(
'Injured: ${parseBool(peopleList[index].isInjured)}, transported to hospital: ${parseBool(peopleList[index].isTransported)} ${isCitated(index)} '),
trailing: IconButton(
icon: buildPopMenu(index, peopleList),
onPressed: () {},
),
onTap: () {
print(index);
},
)
],
),
),
);
},
);
the floating button creates showDialog that adds an object to the Hive db
box.add(Person);
so i understand you , you need first to give each item a keyValue based on the last item in your HiveBox and when you want to delete or update some items you will do that based on your keyValue and not based on the index of your ListViewBuilder
this code for adding items
void addNewOrder(NewOrder order) {
final ordersBox = Hive.box('order');
var lengthBox = Hive.box('order').values;
if (lengthBox.isEmpty) {
ordersBox.put(1, order);
print('the box is empty');
} else {
lengthBox.forEach((item) => allorder.add(item.key));
int lastElement = allorder.last;
int newElement = lastElement + 1;
ordersBox.put(newElement, order);
allorder.clear();
}
}
and this code is for retrieving the order of items
List<int> productkey = [];
List<dynamic> items = [];
items = Hive.box('order').values.toList();
items.forEach((item) {
productkey.add(item.key);
});
and this line is for deleting put it in the onPressed
Hive.box('order').delete(productkey[index]);
i hope i was clear

Flutter : Popup for each Listtile

I am working on a flutter project and I want to popup to get generated on clicking a particular tile. This is my code
This is my ListTile generator
Future<Widget> getRecordView() {
print("405 name " + name.toString());
print(nameArr);
var items = List<Record>.generate(int.parse(widget.vcont), (index) => Record(
name: nameArr[index],
type: typeArr[index],
address: addressArr[index],
state: stateArr[index],
phone:phoneArr[index],
city: cityArr[index],
id: idArr[index],
));
print("Started");
var listItems = items;
var listview = ListView.builder(
itemCount: int.parse(widget.vcont),
itemBuilder: (context,index){
return listItems[index] ;
}
);
return Future.value(listview);
}
The Popup I need on tap :
Future <bool> details(BuildContext context,String type) {
return Alert(
context: context,
type: AlertType.success,
title: "Submission",
desc: type, //The parameter
buttons: [
DialogButton(
child: Text(
"OKAY",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () => Navigator.pop(context),
color: Color.fromRGBO(0, 179, 134, 1.0),
radius: BorderRadius.circular(0.0),
),
],
).show();
}
I tried to wrap Record with GestureDetector and Inkwell, but I only got errors and Android Studio tells me that Record is not expected in that context. I looked up in the internet and couldnt find anything on this matter. Please help.
Record, as far I can see is just a model, and not a widget. Item Builder requires a widget. You should wrap what you are passing to the item builder with an actual widget like a Container(), ListTile(), .. etc. These widgets can be wrapped with Gesture Detector to perform the pop ups you want.
It would look like this
var listview = ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
// Tap on an item in the list and this will get executed.
},
// Return an actual widget, I'm using a ListTile here, but you can
// use any other type of widget here or a create custom widget.
child: ListTile(
// this will display the record names as list tiles.
title: Text(items[index].name),
),
);
},
);

Dynamic adding and removing elements from Widget list

I want to create a list of widgets(TextFormField) in which I can add a new element with button Add, and remove any element with the button next to that element. So I would have unknown number of TextFormFields in array and would be able to add a new one, and destroy any one TextFormField.
I was able to make adding of new TextFormFields but removing only works if I want to remove last one.
Is there any way to determine the index of removeButton that was clicked?
List<Widget> proba = new List<Widget>();
List<TextEditingController> _controllers = new List<TextEditingController>();
...
IconButton(
icon: Icon(Icons.add_circle_outline),
onPressed: () {
setState(() {
_controllers.add(new TextEditingController());
});
setState(() {
proba.add(Row(
children: [
Icon(Icons.radio_button_unchecked),
Expanded(
child: TextFormField(
controller: _controllers[_controllers.length - 1],
decoration:
InputDecoration(hintText: "Add text..."),
),
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
_controllers.removeAt(_controllers.length - 1);
proba.removeAt(proba.length - 1);
});
},
)
],
));
});
},
),
Adding works fine. The code removes last element but I would like to remove the element whose button was clicked.
I think you could use a ListView (for example with the builder constructor), so that each Row is a ListTile. The itemBuilder builds the item and you have access to the index. It would look something like this:
int itemCount = 3;
ListView.builder(
itemCount: _counter,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.radio_button_unchecked),
title: TextFormField(),
trailing: IconButton(
onPressed: () {
setState(() {
_counter--;
});
},
icon: Icon(Icons.delete),
),
);
},
),
In the setState Method in the onPressed property you have access to the index. In the example the ListView takes care to create the ListTiles based on the itemCount. You might want to create a list of objects instead of just the int itemCount to store data (maybe the text in the TextFormField). But you can still delete the item based on the index from the itemBuilder: values.deleteAt(index).
Have a look at the docs for the ListView and the ListTile classes:
https://api.flutter.dev/flutter/widgets/ListView-class.html
https://api.flutter.dev/flutter/material/ListTile-class.html

Flutter DataTable -Tap on entire Row

im new to Flutter. I need help on OnTap in DataCell. For example, instead of tapping one cell, I want the Row.
Heres my codes
DataTable(
columns: <DataColumn>[
DataColumn(
label: Text("Title"),
),
DataColumn(
label: Text("Contacts"),
),
)
],
rows: contracts.map((contract) => DataRow(
cells: [
DataCell(Text(contract.title),
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => List(),),
);
}),
DataCell(Text(contract.contacts),
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => List(),),
);
}),).toList()
i want to click on a specific row and it will route to another page also sends the index value of it.
Had the same issue, realised you could use the onSelectChanged from the DataRow.
Example from the DataTable
rows: searchList.map((item) {
return DataRow(
onSelectChanged: (bool value) {
// ENTER CALLBACK HERE (It's not restricted to use the bool)
},
cells: ...
Note, this will make the Checkbox visible, if you do not require this then make sure you force the showCheckboxColumn to false in the DataTable:
return DataTable(
showCheckboxColumn: false,
columns: [...]
To make the entire widget tappable
just wrap your widget with
InkWell() or GestureDetector Widget
InkWell() widget will add a clickable shadow kind of effect when you press on the widget
whereas GestureDetector() widget won't
In your case instead of wrapping DataCell just wrap your DataRow widget
There's a property in DataRow you can implement called onSelectChanged where you can put your function inside.
bool isSelected = false;
DataRow(
selected: isSelected,
onSelectChanged: (x) {
setState(() {
isSelected = x;
});
},
cells: <DataCell>[
DataCell(
Text('Row1'),
),
],
),
Try using DataRow.byIndex(), then use that index when wrapping your DataRow in a GestureDetector.

Fix top Row in Data table in flutter

I have a data table that scrolls horizontally and vertically due to the amount of data available. I want the top row which specifies the column names to always be visible when scrolling down.
code: No issues in the code I am getting the results, but when I scroll down The header wont be shown. Can any one help me in how to fix the header(1st row).
My header(1st row) elements keeps changing for each req,
the way its implemented is there will be cards in my dashboard onclicking each card it hits the API and I am displaying its result i.e contents of field named header list as my first row.
Content of the header keeps changing for each card. so once any card is clicked new page containing its data will popup, there I need to fix the header.
Widget getTable(BuildContext context, var data) {
Widget _widget;
_widget = SingleChildScrollView(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
rows: createDataRows(context, data),
columns: createDataColumns(context, data),
),
),
);
return _widget;
}
List<DataRow> createDataRows(BuildContext context, var jsonData) {
List<DataRow> _dataRows = [];
List<DataCell> _cells = [];
String _dataCellTitle;
Map<String, Object> headers = jsonData['headers'];
Map<int, String> headerMapping;
headerMapping = headers.keys
.toList()
.asMap()
.map((index, value) => MapEntry(index + 1, value));
if (jsonData["data"] == null) {
_dataRows = [];
} else {
for (var j = 0; j < jsonData["data"].length; j++) {
_cells.add(DataCell(Text('${j + 1}')));
for (int i = 1; i <= headerMapping.length; i++) {
_dataCellTitle = "${jsonData["data"][j][headerMapping[i]]}" ?? '-';
_cells.add(DataCell(Text('$_dataCellTitle')));
}
_dataRows.add(DataRow(cells: _cells));
_cells = [];
}
}
return _dataRows;
}
List<DataColumn> createDataColumns(BuildContext context, var jsonData) {
String columnTitle;
List<DataColumn> _dataColumns = [];
Map<String, Object> headers = jsonData['headers'];
Map<int, String> headerMapping;
headerMapping = headers.keys
.toList()
.asMap()
.map((index, value) => MapEntry(index + 1, value));
_dataColumns.add(DataColumn(label: Text('S. No.')));
for (int i = 1; i <= headerMapping.length; i++) {
columnTitle = headers[headerMapping[i]];
_dataColumns.add(
DataColumn(label: Text('$columnTitle')),
);
}
return _dataColumns;
}
like this here
where the first row is constant and first column also.
You can do the smart thing here, You can create two datatables one with only column, and one with rows.
Suppose your list_rows is a List<DataRow> and list_column is List<DataColumn> of your actual columns, then:
Column(
children: [
DataTable(
rows: [], // DONT PROVIDE ROWS
columns: list_column, // PROVIDE YOUR COLUMNS HERE
),
Expanded(
child: SingleChildScrollView(
child: DataTable(
rows: list_lows, // PROVIDE ROWS HERE
columns: List.generate(
list_column.length, (index) => DataColumn(label: Text(''))), // GENERATE EMPTY COLUMNS
headingRowHeight: 0, // SHRINK THE HEADER
),
),
),
],
)
This way your columns will always be on top!
Okay so you have one method getTable to get data content,
In it you are calling two methods
1) To fetch rows
2) To fetch columns.
But you didn't show the code of DataTable Widget.
I assume it is ListView or Column.
So in your DataTable Widget you should create one static Row for that heading.
ListView(
children: <Widget>[
Row(
children: <Widget>[
Text('$heading1'),
Text('$heading2'),
Text('$heading3'),
],
),
/// Your row and column
],
);
With information you provided i assume it will help you out.
I have Used Like that , and its working fine :
SingleChildScrollView dataBody() {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: DataTable(
columnSpacing: 10,
//sortAscending: sort,
//sortColumnIndex: 0,
columns: [
DataColumn(label: Text("Date"), numeric: false),
DataColumn(label: Text("Particulars"), numeric: false),
DataColumn(label: Text("Amount"), numeric: true)
],
rows: transactions
.map((txn) => DataRow(cells: [
DataCell(
Text(
DateFormat('dd-MMM-yyyy').format(txn.date),
style: TextStyle(fontSize: 12.0),
),
/*onTap: () {
print('Selected ${txn.date}');
}*/
),
DataCell(FittedBox(
child: Text(
txn.particulars,
),
)),
DataCell(Text(txn.amount.toString()))
]))
.toList(),
),
));
}
This is the solution to make Datatable Header sticky :
SizedBox(
height: 500,
width: 1000,
child: Scrollbar(
controller: _vertical,
thumbVisibility: true,
trackVisibility: true,
child: Scrollbar(
controller: _horizontal,
thumbVisibility: true,
trackVisibility: true,
child: SingleChildScrollView(
controller: _horizontal,
scrollDirection: Axis.horizontal,
child: Stack(
children: [
SingleChildScrollView(
controller: _vertical,
scrollDirection: Axis.vertical,
child: DataTable(
rows: list_rows, // PROVIDE ROWS HERE
columns: List.generate(
list_column.length,
(index) => DataColumn(
label: Text(''),
),
), //GENERATE EMPTY COLUMNS
headingRowHeight: 90, // HEADER HEIGHT
),
),
DataTable(
rows: [], // DONT PROVIDE ROWS
columns:
list_column, // PROVIDE YOUR COLUMNS HERE
headingRowHeight: 90, // HEADER HEIGHT
headingRowColor: MaterialStateColor.resolveWith(
(states) => Color.fromRGBO(86, 153, 255, 1),
),
border: TableBorder.all(
width: 1.0, color: Colors.white),
),
],
),
),
),
),
),