How to delete a row from a DataTable in Flutter? - flutter

I'm new to flutter. I'm creating a app with a table which a button in every row. I need to delete the row when that button is pressed.
This is the code of the table.
DataTable(
columns: const <DataColumn>[
DataColumn(label: Text('Medications')),
DataColumn(label: Text('Amount')),
DataColumn(label: Text('When')),
DataColumn(label: Text(' '))
],
rows:
_data // Loops through dataColumnText, each iteration assigning the value to element
.map(
((element) => DataRow(
cells: <DataCell>[
DataCell(Text(element[
"drug"])), //Extracting from Map element the value
DataCell(Text(element["amount"])),
DataCell(Text(element["when"])),
DataCell(new RButton(
id: bid,// bid variable increments by 1 every t
onPressed: onPressed,
))
],
)),
)
.toList(),
),
This is the code of RButton
class RButton extends StatelessWidget {
final int id;
final Function onPressed;
const RButton({this.id, this.onPressed});
#override
Widget build(BuildContext context) {
return SizedBox(
width: 30,
child: FlatButton(
onPressed: () {
onPressed(this.id);
print(this.id);
},
textColor: Colors.red,
child: Text("-"),
));
}
}
This is the code of the function button run when pressed.
onPressed(id) {
setState() {
_data.remove(_data[id]);
}
}

Assuming that you are properly using a StatefulWidget to create this example.
setState is a function that takes another function as it's single parameter.
So, it must used like this,
onPressed(id) {
setState(() {
_data.remove(_data[id]);
});
}

Related

How can I show my data in to table form using data table [FLUTTER]

I am working on a flutter where I have 2 Lists, 1. usersEmails, usersNames
How can I sort that code in a way that 1st element of userEmails and userNames become the 1st Row of data table.
Example:
List of Emails: [ABC, DEF, GHI]
List of Names: [MNO, PQR, XYZ]
What I want is:
The Data Rows will depend on the total numbers elements in the Email/Name List.
DataTable(
columns: const [
DataColumn(label: Text('ID'),),
DataColumn(label: Text('Email'),),
DataColumn(label: Text('Name'),),
],
rows: const [
DataRow(cells: [
DataCell(Text("101")),
DataCell(Text("ABC")),
DataCell(Text("MNO")),
]),
DataRow(cells: [
DataCell(Text("102")),
DataCell(Text("DEF")),
DataCell(Text("PQR")),
]),
DataRow(cells: [
DataCell(Text("103")),
DataCell(Text("GHI")),
DataCell(Text("XYZ")),
]),
]
)
Can you try following code.
class _MyHomePageState extends State<MyHomePage> {
List lst = ['ABC', 'DEF', 'GHI'];
List lst2 = ['asdas', 'adsasd', 'dfaas'];
List<DataRow> generateDataRow(List ls) {
List<DataRow> dataRows = [];
//Both list should have same length
//Otherwise it will throw errors.
for (int i=0; i<ls.length; i++) {
dataRows.add(
DataRow(
cells: [
DataCell(Text(ls[i])),
DataCell(Text(lst2[i])),
]
)
);
}
return dataRows;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16),
child: DataTable2(
columnSpacing: 12,
horizontalMargin: 12,
minWidth: 600,
columns: const [
DataColumn2(
label: Text('Email'),
size: ColumnSize.L,
),
DataColumn(
label: Text('Name'),
),
],
rows: generateDataRow(lst),),
),// This trailing comma makes auto-formatting nicer for build methods.
);
}
}

What can I do to make my ListView stop incrementing the data every time I open it?

My first Flutter project, which is a tricycle booking system, has just begun. Using the ListView widget, I wanted to display all of the active passengers that are saved in my Firebase Database. However, when I attempted to display it and place it in a List, all functions are working fine at first click. When you click the button to view the ListView a second time, all of the saved data are replicated. The list continues after my third click and grows by three. The image below illustrates what takes place when I repeatedly click on the ListView.
These are the blocks of code that are utilized for this functionality:
CODE for Functionality
retrieveOnlinePassengersInformation(List onlineNearestPassengersList) async
{
dList.clear();
DatabaseReference ref = FirebaseDatabase.instance.ref().child("passengers");
for(int i = 0; i<onlineNearestPassengersList.length; i++)
{
await ref.child(onlineNearestPassengersList[i].passengerId.toString())
.once()
.then((dataSnapshot)
{
var passengerKeyInfo = dataSnapshot.snapshot.value;
dList.add(passengerKeyInfo);
print("passengerKey Info: " + dList.toString());
});
}
}
CODE for the UI
body: ListView.builder(
itemCount: dList.length,
itemBuilder: (BuildContext context, int index)
{
return GestureDetector(
onTap: ()
{
setState(() {
chosenPassengerId = dList[index]["id"].toString();
});
Navigator.pop(context, "passengerChoosed");
},
child: Card(
color: Colors.grey,
elevation: 3,
shadowColor: Colors.green,
margin: EdgeInsets.all(8.0),
child: ListTile(
leading: Padding(
padding: const EdgeInsets.only(top: 2.0),
child: Icon(
Icons.account_circle_outlined,
size: 26.sp,
color: Color(0xFF777777),
),
),
title: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text(
dList[index]["first_name"] + " " + dList[index]["last_name"],
style: TextStyle(
fontFamily: "Montserrat",
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
Icon(
Icons.verified_rounded,
color: Color(0xFF0CBC8B),
size: 22.sp,
),
],
),
],
),
),
),
);
},
),
Expected Result:
Actual Result AFTER CLICKING MANY TIMES:
Made a demo for you how to call function once on load
class CustomWidgetName extends StatefulWidget {
const CustomWidgetName({Key? key}) : super(key: key);
#override
State<CustomWidgetName> createState() => _CustomWidgetNameState();
}
class _CustomWidgetNameState extends State<CustomWidgetName> {
List? dList = [];
void myDataFunction() async {
// do your data fetch and add to dList
final newList = [];
setState(() {
dList = newList;
});
}
#override
void initState() {
super.initState();
myDataFunction(); // Call your async function here
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Try this solution.
Update SelectNearestActiveDriversScreen() like this:
class SelectNearestActiveDriversScreen extends StatefulWidget
{
DatabaseReference? referenceRideRequest;
final List list;
SelectNearestActiveDriversScreen({this.referenceRideRequest, required this.list});
#override
State<SelectNearestActiveDriversScreen> createState() => _SelectNearestActiveDriversScreenState();
}
In homepage.dart, declare List dList = [];, then change line 378 like this:
Navigator.push(context, MaterialPageRoute(builder: (c)=> SelectNearestActiveDriversScreen(list: dList)));
In SelectNearestActiveDriversScreen(), replace all dList with widget.list.
Finally, if you are using variables in a specific file declare them in that file(not in another file) or pass them in the constructor of the class / file / widget /screen you are calling.
If you would rather use global variables and state managers go for packages like GetX.

Flutter DataTable truncates text

I am writing a flutter app and am trying to insert a DataTable. I am having issues with the text getting truncated though and not overflowing to a new line. It will do 2 lines but not 3 on the device I am on. I tried adding the text in an Expanded widget, but that won't work and throws a 'Incorrect use of ParentDataWidget'. Any way to get really long text to span 3, 4, or 5+ lines? Below is the code.
import 'package:flutter/material.dart';
class ClaimTypeTable extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: new DataTableWidgetExtract(),
);
}
}
class DataTableWidgetExtract extends StatelessWidget {
const DataTableWidgetExtract({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return DataTable(
columnSpacing: 10.0,
horizontalMargin: 5,
columns: <DataColumn>[
DataColumn(label: Text('Type')),
DataColumn(label: Text('Description',)),
],
rows: claimTypesList
.map(
(itemRow) => DataRow(
cells: [
DataCell(Text(itemRow.shortName),
showEditIcon: false, placeholder: false, onTap: () {
print('We tapped it - ${itemRow.shortName}');
}),
DataCell(
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(itemRow.description,),
),
showEditIcon: false,
placeholder: false,
),
],
),
)
.toList(),
);
}
}
class ClaimType {
String shortName;
String description;
ClaimType({
this.shortName,
this.description,
});
}
var claimTypesList = <ClaimType>[
ClaimType(
shortName: 'Fire',
description:
'There was a fire. The fire department may or may not have been called, but shit got burnt up.',
),
ClaimType(
shortName: 'Water',
description:
'Water damage. Examples of typical water damage include: burst pipe, broken water heater, or faulty toilet.',
),
ClaimType(
shortName: 'Wind',
description:
'There is non-hurricane wind damage to your residence. If it is related to a hurricane, please select Hurricane as the claim type instead. This one is really long and gets truncated.',
),
ClaimType(
shortName: 'Crime',
description:
'Vandalism, theft, or other criminal behavior that resulted in a loss.'),
];
And here is the image of what it looks like:
Three to four things to apply-
Inside the DataCell widget you need to use a ConstrainedBox. In the ConstrainedBox specify the maxWidth and minWidth to cover the height.
In Datacell widget's child if Text widget give overflow: TextOverflow.visible, softWrap: true,
In DataTable widget give dataRowHeight property.
Data tables are so hard to work with. I just ended up using a listview with dividers.

Why do i get a RangeError, if i add something to my List?

im trying to create a new Hero Widget by klicking on my FloatingActionButton. Therefore i have created a HeroCover widget, which holds the single Hero widgets.
class HeroCover extends StatelessWidget {
final Widget callPage;
final heroTag;
final coverImageName;
final name;
HeroCover({this.callPage, this.heroTag, this.coverImageName, this.name});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Hero(
tag: heroTag,
child: GestureDetector(
onTap: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => callPage)),
child: Column(children: <Widget>[
Image(
image: new AssetImage(coverImageName),
height: 100,
width: 100,
),
Text(name),
])),
),
);
}
}
On my HeroPage i now Create those HeroCover widgets depending on the following Lists with mapping
static List<int> matrixID = [0, 1, 2];
static var heroTag = ['matrix1', 'matrix2', 'matrix3'];
static var name = ['Matrix Kitchen', 'DAAANCEFLOR', 'Bath'];
static var matrixIMG = [
'imgs/matrix1.png',
'imgs/matrix2.png',
'imgs/matrix3.png'
];
var matrixCall = [
...matrixID.map((id) {
return MatrixPageOne(
name: name[id],
matrixSize: 20,
heroTag: heroTag[id],
heroImage: matrixIMG[id],
);
}).toList(),
];
Here i map the matrixID in the BuildMethod to return HeroCover Widgets depending on matrixID's length:
body: Column(
children: [
Wrap(children: [
...matrixID.map((id) {
return HeroCover(
heroTag: heroTag[id],
callPage: matrixCall[id],
name: name[id],
coverImageName: matrixIMG[id],
);
}).toList()
] // wrap children
),
],
),
Now if i press my FloatingActionButton, i add one Element to each of the lists:
floatingActionButton: FloatingActionButton(
onPressed: () {
//startAddMatrix(context);
setState(() {
matrixID.add(matrixID.length);
name.add('new Matrix');
matrixIMG.add('imgs/matrix1.png');
heroTag.add(DateTime.now().toString());
});
},
child: Icon(Icons.add),
backgroundColor: color_3,
),
So the .map should find one more element in each list and the next HeroCover Widget should be displayed ( if i add it manually to each list there is no problem), but if i press my FloatingActionButton, this happens:
but if i tap on "Home" in my BottomNavigationBar now and back to "Devices" everything is as it should be:
i just dont understand why .add is causing an RangeError. If anyone knows whats wrong here, id be very Thankful for your help!
your matrixCall init with ...matrixID.map((id) { ,
so it have 3 values 0..2
In your floatingActionButton, did not extend matrixCall, matrixCall still only have 3 values 0..2
when use
Wrap(children: [
...matrixID.map((id) {
return HeroCover(
heroTag: heroTag[id],
callPage: matrixCall[id],
name: name[id],
coverImageName: matrixIMG[id],
);
}).toList()
matrixID have 4 values 0..3,
and matrixCall still have 3 values, matrixCall[3] do not have value.

Flutter - get value in ListView text to paste on TextField on another dart file

main.dart image
homeview.dart
I have a problem I have 2 different dart files, main.dart and homeview.dart here I deliberately made a custom dialog at homeview.dart, the dialog contains listview and only data strings, I want to make it and on the item list I create an Inkwell widget to be able to OnTap :, and in main.dart it contains TextFormField,
The question is how when in the onTap list item, the text string moves to TextFormField on main.dart?
homeview.dart
final List<String> _listViewTypeInvest = [
"12 Months Invest",
"18 Months Invest",
"24 Months Invest",
];
child: ListView(
children: _listViewTypeInvest
.map( (data) => ListTile(
title: Text(data),
onTap: () => _scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(
"$data Clicked!",
style: TextStyle(fontFamily: "Montserrat"),
),
duration: Duration(seconds: 1),
)),
))
.toList(),
),
You could work with a Function callback.
So in your homeview.dart you want to add a Function as a property.
class HomeView extends StatelessWidget {
final void Function(String) onStringSelected;
const HomeView({Key key, #required this.onStringSelected}) : super(key: key);
...
Now you can call this function once the user presses a button in your dialog.
So this will be your onTap() function:
onTap: () {
onStringSelected(data); // this fires the callback function
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(
"$data Clicked!",
style: TextStyle(fontFamily: "Montserrat"),
),
duration: Duration(seconds: 1),
));
}),
Where ever you instantiate the homeview.dart file you can now listen for that new onStringSelected function callback and for example set the text property of your TextFormField.
HomeView(
onStringSelected: (myDataString) {
print("The user clicked $myDataString");
},
);