I have DataTable in flutter which is working fine until I got an empty list. In case the widget.detailDate.brands is empty, I get "Bad state: No element" error, now my question is, how can I handle the error, I've tried something like
widget.detailDate.brands.map((brand) => {
if (brand != ' '){
// do the DataRow stuff
}else{
print('brnad not found')
}
}).toList();
But it's not working. I wanna add something like "-", if the list is empty
My whole code looks like this:
DataTable buildBrandTable(context) {
return DataTable(
columnSpacing: 0,
showCheckboxColumn: false,
columns: const <DataColumn>[
DataColumn(
label: Text(
'Brand',
),
),
DataColumn(
label: Text(
'Mandant',
),
),
DataColumn(
label: Expanded(
child: Text(
'Januar',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'Februar',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'März',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'April',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'Mai',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'Juni',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'Juli',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'August',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'September',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'Oktober',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'November',
textAlign: TextAlign.end,
),
)),
DataColumn(
label: Expanded(
child: Text(
'Dezember',
textAlign: TextAlign.end,
),
),
),
],
rows: [
...widget.detailData.brands!
.map(
(brand) => DataRow(
onSelectChanged: (bool) {
Navigator.of(context)
.pushNamed(DetailScreen.routeName, arguments: {
'pageType': 'Brand',
'id': brand['brand_slug'].toString(),
});
},
color: (brand['brand'] == 'Gesamt')
? MaterialStateProperty.resolveWith(
(Set<MaterialState> states) => Colors.grey[300])
: null,
cells: [
DataCell(Text(brand['brand'])),
DataCell(Text(brand['mandant'])),
..._month
.map(
(month) => DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(formatter.format(brand[month])),
],
),
),
)
.toList(),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
formatter.format(
_month
.map((month) => brand[month])
.toList()
.reduce((a, b) => a + b),
),
),
],
),
),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text((brand['rate'] != null)
? formatterPercent.format(brand['rate'] / 100)
: 'N/A'),
],
),
),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text((brand['rate_letztes_jahr'] != null)
? formatterPercent
.format(brand['rate_letztes_jahr'] / 100)
: 'N/A')
],
),
),
],
),
)
.toList(),
],
);
}
I think your problem is caused by
rows: [
...widget.detailData.brands!
.map( // rest of your mapping function
...
maybe you should
widget.detailData.brands.length>0 ?
...widget.detailData.brands.map( // rest of your mapping function
:
[]
in your widget tree
Update
for example
Using the spread operator(...), adds the items individually not as a list
Column(
children: [
...values.map((value) {
return Text(value);
}),
],
),
Related
I need help to add button row in PaginatedDataTable but I don't know where to add it?
I try to add button in column test7 many time but it does not work
if you could help me where can I add button in table?
in data column or data cell?
like this
const kTableColumns = <DataColumn>[
DataColumn(
label: Expanded(
child: Text('test7',
textAlign: TextAlign.start,
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold)),
),
numeric: true,
),
];
class DetailstDataSource extends DataTableSource {
int selectedCount = 0;
List\<A\> myData = \<A\>\[
A(
'test',
3,
1,
'test',
'test',
'test',
'test',
),
\];
DataCell(
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 100,
child: Text(dessert.test7,
maxLines: 3,
overflow: TextOverflow.visible,
textAlign: TextAlign.start,
style: const TextStyle(fontSize: 12)),
),
],
),
),
],
);
}
I have a datatable with 4 columns but only 3 are currently showing when the screen is rotated i am able to see all 4 columns it is not even scrollable.
I am try to see the 4 columns in a single view ut I am getting this error:
lib/screens/home_screen.dart:79:29: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
DataTable(
^^^^^^^^^
lib/screens/home_screen.dart:78:54: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
const SingleChildScrollView(
^
/C:/src/flutter/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart:140:9: Context: Found this candidate, but the arguments don't match.
const SingleChildScrollView({
^^^^^^^^^^^^^^^^^^^^^
Restarted application in 274ms.
Here is th e code for the table:
ExpansionTile(
title: const Text("Click Here to See table Name"),
children: [
const SingleChildScrollView(
DataTable(
columns: const <DataColumn>[
DataColumn(
label: Text(
'Sr.No',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
DataColumn(
label: Text(
'Website',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
DataColumn(
label: Text(
'Tutorial',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
DataColumn(
label: Text(
'Review',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
],
rows: const <DataRow>[
DataRow(
cells: <DataCell>[
DataCell(
Text('1'),
),
DataCell(
Text('https://flutter.dev/'),
),
DataCell(
Text('Flutter'),
),
DataCell(
Text('5*'),
),
],
),
DataRow(
cells: <DataCell>[
DataCell(
Text('2'),
),
DataCell(
Text('https://dart.dev/'),
),
DataCell(
Text('Dart'),
),
DataCell(
Text('5*'),
),
],
),
DataRow(
cells: <DataCell>[
DataCell(
Text('3'),
),
DataCell(
Text('https://pub.dev/'),
),
DataCell(
Text('Flutter Packages'),
),
DataCell(
Text('5*'),
),
],
),
],
),
),
],
),
My question: How can make the table view in one screen so that it can be wrapped or the columns shrink to be view in a singleview?
You nee to pass DataTable to SingleChildScrollView's child, you forget to add child world also needed to pass scrollDirection too:
SingleChildScrollView(
scrollDirection: Axis.horizontal,// <---add this
child: DataTable(// <---add this
columns: <DataColumn>[
...
]
)
)
You have to define Datatable to child and if you are going to define more than one, you need to remove const in columns.
SingleChildScrollView(
child: DataTable( //Edited
columns: <DataColumn>[ //Edited
...
]
)
)
In my flutter project, I want to make the screen which is user enter quantity for multiple product. I want to manage text controllers for multiple data rows in the data table.
My data table code is:
TextEditingController textController = TextEditingController();
AlertDialog(
content: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.height,
margin: EdgeInsets.all(0),
child: ListView(
padding: EdgeInsets.all(0),
primary: true,
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: [
DataTable(
columns: [
DataColumn(
label: Text(
"Product",
softWrap: true,
),
),
DataColumn(
label: Text(
"Qty",
),
),
DataColumn(
label: Text(
"Rs",
)),
DataColumn(
label: SizedBox(
width: 40,
child: Text(
'BalQty',
),
),
),
DataColumn(
label: SizedBox(
width: 40,
child: Text(
'Stock',
),
),
),
],
rows: listOfProduct!
.map(
((element) => DataRow(
cells: <DataCell>[
DataCell(Text(
element.name,
)),
DataCell(
TextField(
controller: textEditingController,
maxLength: 4,
decoration: InputDecoration(
labelText: 'Qty',
labelStyle: TextStyle(fontSize: 9.sp),
counterText: "",
),
),
),
DataCell(
Text(
(element.pTR ?? 0).toStringAsFixed(2),
),
),
DataCell(Text(
element.text!.printDashIfEmpty(),
)),
DataCell(Text(
(element.balQty ?? 0).toStringAsFixed(2),
)),
],
)),
)
.toList(),
),
],
),
),
actions: <Widget>[
OutlinedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Cancel",
)),
SizedBox(
width: 10,
),
OutlinedButton(
onPressed: () async {
print("QUANTITY : $textEditingController");
listSearchProductMaster!.forEach((e) {
return print("TEXT CONTROLLER: ${e.textEditingController}");
});
},
child: Text(
"Add",
))
],
)
The output I see is that the quantity that the user inserts should be added to the particular product.
Currently, my application output is
Does anyone help?
Well, in my case, my approach was:
When user tap item to edit, show modal with initial value
User make input and tab Confirm button
after valid input, apply
It wrap focus node and controller, so easy to use.
But it force user to dig in 1 more UI level, so maybe there are better ways, but it works anyway.
I made TextEditModal widget and function to show that.
Future<String> showSingleTextEditDialog({
#required BuildContext context,
String initText = '',
}) async {
String text = initText;
bool submit = false;
await showDialog(
context: context,
builder: (_) {
return _SingleTextEditDialog(
text: text,
textChanged: (value) => text = value,
onSubmit: () => submit = true,
);
},
);
return submit ? text : null;
}
class _SingleTextEditDialog extends StatefulWidget {
_SingleTextEditDialog({
Key key,
#required this.text,
#required this.textChanged,
this.onSubmit,
}) : super(key: key);
final String text;
final ValueChanged<String> textChanged;
final VoidCallback onSubmit;
#override
_SingleTextEditDialogState createState() => _SingleTextEditDialogState();
}
class _SingleTextEditDialogState extends State<_SingleTextEditDialog> {
TextEditingController textController;
#override
void initState() {
super.initState();
textController = TextEditingController(text: widget.text);
}
#override
void dispose() {
textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SimpleDialog(
children: [
DecoInput(
controller: textController,
onChanged: widget.textChanged,
),
VSpace.md,
StyledInterfaceButton(
onTap: () {
setState(() => widget.onSubmit());
Navigator.of(context).pop();
},
text: 'Confirm',
),
// VSpace.md,
],
);
}
}
and use like
onTap: () async {
HapticFeedback.mediumImpact();
final input = await showSingleTextEditDialog(
context: context,
initText: text,
);
if (input == null) return;
// valid user input here
valueChanged(input); // apply user input
},
This is not complete code. I minimized code for readability. So ignore if there are any error.
Add your table code inside SingleChildScrollView() with scrollDirection: Axis.horizontal refer below code hope it help to you
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(20),
child: Table(
defaultColumnWidth: FixedColumnWidth(80.0),
border: TableBorder.all(
color: Colors.black,
style: BorderStyle.solid,
width: 2),
children: [
TableRow(
children: [
Column(
children: [
Text(
'Website',
style: TextStyle(fontSize: 20.0),
),
],
),
Column(
children: [
Text(
'Tutorial',
style: TextStyle(fontSize: 20.0),
),
],
),
Column(
children: [
Text(
'Review',
style: TextStyle(fontSize: 20.0),
),
],
),
Column(children: [
Text(
'Review',
style: TextStyle(fontSize: 20.0),
),
]),
Column(
children: [
Text(
'Review',
style: TextStyle(fontSize: 20.0),
),
],
),
],
),
TableRow(children: [
Column(
children: [
Text('Javatpoint'),
],
),
Column(
children: [
Text('Flutter'),
],
),
Column(
children: [
Text('5*'),
],
),
Column(
children: [
Text('5*'),
],
),
Column(
children: [
Text('5*'),
],
),
]),
TableRow(
children: [
Column(children: [
Text('Javatpoint'),
]),
Column(
children: [
Text('MySQL'),
],
),
Column(
children: [
Text('5*'),
],
),
Column(children: [
Text('5*'),
]),
Column(children: [
Text('5*'),
]),
],
),
],
),
),
],
),
),
Scroll your table horizontaly
Your screen like - >
I'm trying to create Paginated Data Table to fill the height. However, whatever I'm trying nothing seems to work. How can I make the table fill the height? Also, how can I change the pagination background color?
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(state.department.name),
),
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(onPressed: () {}, child: Text('TEst 1')),
TextButton(onPressed: () {}, child: Text('TEst 1'))
],
),
Container(
child: PaginatedDataTable(
showCheckboxColumn: false,
headingRowHeight: 35,
columns: const <DataColumn>[
DataColumn(
label: Text(
'First Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Last Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Id',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Time',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Operator',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
source: tableSource
),
)
],
),
);
}
With Container the container itself is filling up the height, but the paginated data table not.
Solution
static const double topViewHeight = 50.0;
static const double paginateDataTableHeaderRowHeight = 35.0;
static const double pagerWidgetHeight = 56;
static const double paginateDataTableRowHeight = kMinInteractiveDimension;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello'),
),
body: LayoutBuilder(
builder: (context, constraint) {
return Column(
children: <Widget>[
Container(
width: constraint.maxWidth,
height: topViewHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(onPressed: () {}, child: Text('TEst 1')),
TextButton(onPressed: () {}, child: Text('TEst 1'))
],
),
),
Container(
color: Colors.greenAccent,
height: constraint.maxHeight - topViewHeight,
child: Center(
child: PaginatedDataTable(
showCheckboxColumn: false,
headingRowHeight: paginateDataTableHeaderRowHeight,
rowsPerPage: ((constraint.maxHeight -
topViewHeight -
paginateDataTableHeaderRowHeight -
pagerWidgetHeight) ~/
paginateDataTableRowHeight)
.toInt(),
columns: const <DataColumn>[
DataColumn(
label: Text(
'First Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
source: TableSource()),
))
],
);
},
),
);
}
Need to know
note:
Column is an infinite height constraint so it will not suit to fit the height.
If, you warp the column inside the SingleChildScrollViewWidget to avoid constraint errors and warnings
There's a derivative of Flutter's DataTable widget on pub.dev (called DataTable2) which solves exactly that issues - filling the height of the parent widget. It is in-place substitute for DataTable and also provides data rows scrolling and sticky header.
https://pub.dev/packages/data_table_2
When I get data from the server and change that to a model Called SetupIdeaModel I get this error.
type 'SetupIdeaModel' is not a subtype of type 'SetupIdeaModel' where
SetupIdeaModel is from package:onion/models/idea.dart
package:onion/models/Idea.dart:1
SetupIdeaModel is from package:onion/models/Idea.dart
package:onion/models/Idea.dart:1
I say the SetubIdeaModel is not a subtype of type 'SetupIdeaModel' But it is the same file and same model. Why I get this error.
I get data with this method.
Future getRequestDetails(String token, String requestId) async {
Response response = await APIRequest().get(
myUrl: "$baseUrl/innovator/idea/request/$requestId",
token: token,
);
try {
List data = [
User().fromMap(response.data['data']['userId']),
SetupIdeaModel().fromJson(response.data['data']['ideaId']),
RequestModel().formJson(response.data['data']),
];
return data;
} catch (e, st) {
print("Error $e");
print("Stacktrace $st");
return "Something went wrong!";
}
}
the APIRequest() is a global method that I created for my requests. Ans also I'm using Dio packages for my requests.
The SetupIdeaModel
class SetupIdeaModel {
String id;
String userId;
String typeIdea = "Implemented Idea";
String category; //Or Industry
String experienceYear;
String experienceMonth;
String ideaHeadline;
String ideaText;
Map timeline = {
"timelineType": "date",
"details": null,
};
fromJson(json) {
return SetupIdeaModel(
typeIdea: json['ideaType'],
category: json['industry'],
ideaHeadline: json['headline'],
ideaText: json['idea'],
);
}
SetupIdeaModel({
this.uploadVideo,
this.location,
this.estimatedPeople,
this.whitePaper,
this.id,
this.userId,
this.typeIdea,
this.category,
this.experienceYear,
this.experienceMonth,
this.ideaHeadline,
this.ideaText,
this.timeline,
});
List documents = [];
Map uploadVideo;
String location;
String estimatedPeople;
Map whitePaper;
bool needServiceProvider = false;
bool needInvestor = true;
Map toSendMap() {
return {
"ideaType": typeIdea,
"industry": category,
"industryExperienceInMonth":
"${int.parse(experienceYear) * 12 + int.parse(experienceMonth)}",
"headline": ideaHeadline,
"idea": ideaText,
"timeline": timeline,
"uploadDocuments": documents,
"uploadVideo": uploadVideo,
"targetAudience": "$location",
"uploadPaper": whitePaper,
"estimatedPeople": estimatedPeople,
"needServiceProvider": "$needServiceProvider",
"needInvestor": "$needInvestor",
};
}
}
Using models with is FutureBuilder
FutureBuilder(
future: getData,
builder: (context, snapshot) {
if (snapshot.hasData) {
User _user = snapshot.data[0];
SetupIdeaModel _idea = snapshot.data[1];
RequestModel _request = snapshot.data[2];
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${_idea.typeIdea}",
style: TextStyle(
color: deepBlue,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
IconButton(
icon: Icon(Icons.info_outline,
color: middlePurple, size: 20),
onPressed: () {},
),
],
),
Card(
elevation: 4,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
child: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
"${_request.postedOn}",
style: TextStyle(color: Colors.black),
),
],
),
SizedBox(height: 10),
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(width: 0.5, color: deepGrey),
),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text("Industry",
style: TextStyle(color: deepGrey)),
Text(
"${_idea.category}",
style: TextStyle(color: Colors.black),
),
],
),
Divider(),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text("Idea Headline",
style: TextStyle(color: deepGrey)),
Text(
"${_idea.ideaHeadline}",
style: TextStyle(color: Colors.black),
),
],
),
Divider(),
SizedBox(height: 5),
Align(
alignment: Alignment.centerLeft,
child: RichText(
text: TextSpan(
text: 'Idea: ',
style: TextStyle(color: Colors.black),
children: <TextSpan>[
TextSpan(
style: TextStyle(
color: deepGrey,
fontWeight: FontWeight.normal),
text: "${_idea.ideaText}",
),
],
),
),
),
],
),
),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
CircleAvatar(
backgroundImage: NetworkImage(
"${_user.profile ?? 'https://i.pravatar.cc/300'}"),
),
SizedBox(width: 5),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text("${_user.name}",
style: TextStyle(
fontWeight: FontWeight.bold)),
Text("${_user.industry}",
style:
TextStyle(color: deepGrey)),
Row(children: [
Text("Rated: ",
style:
TextStyle(color: deepGrey)),
MyFiveRating(rateVal: _user.rate),
])
],
),
]),
Row(children: [
InkWell(
child: Icon(Icons.more_vert,
color: deepGrey),
onTap: () {},
),
])
],
),
Divider(),
Row(children: [
Text("Interested in: "),
Icon(Icons.radio_button_checked,
color: middlePurple),
Text("${_request.investAs.type}"),
]),
Divider(),
RichText(
text: TextSpan(
text: 'Message: ',
style: TextStyle(color: Colors.black),
children: <TextSpan>[
TextSpan(
style: TextStyle(
color: deepGrey,
fontWeight: FontWeight.normal,
),
text:
"This is my message to you. Yes you, Who are reading this text.I'm with you how are you I'm fine thanks. Everything is goin well and what about you bro."),
],
),
),
],
),
)
]),
),
),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GlowCheckbox(
color: Theme.of(context).primaryColor,
value: checkboxSelected,
enable: true,
onChange: (bool value) {
setState(() {
checkboxSelected = !checkboxSelected;
});
},
),
SizedBox(
width: 10,
),
Expanded(
// child: Text(
// "By Cheacking the box you agree to out terms and services",
// ),
child: RichText(
text: TextSpan(
text: 'Agree to ',
style: TextStyle(color: Colors.black),
children: <TextSpan>[
TextSpan(
text: 'Term and Condition',
style: TextStyle(
color: middlePurple,
decoration:
TextDecoration.underline),
recognizer: TapGestureRecognizer()
..onTap = () {
showDialog(
context: context,
builder: (context) {
return TandCDialog();
},
);
},
),
TextSpan(
text:
' and contract while Requesting this Franchise!'),
],
),
),
)
],
),
SizedBox(height: 5),
SizedBox(
width: double.infinity,
child: RaisedButton(
child: Text(
"Accept Add On Project",
style: TextStyle(
fontSize: 18,
color: Colors.white,
),
),
color: middlePurple,
onPressed: () {
acceptAddOnProject(true, _scaffoldKey);
},
),
),
SizedBox(
width: double.infinity,
child: OutlineButton(
child: Text(
"Declient",
style: TextStyle(
fontSize: 18,
),
),
onPressed: () {
acceptAddOnProject(false, _scaffoldKey);
},
),
),
],
),
),
],
),
),
);
} else if (snapshot.hasError) {
print("error ${snapshot.error}");
return Center(
child: Text(
"Something went wrong, While getting data from the server."));
} else {
return Center(child: SingleChildScrollView());
}
},
),
Flutter doesn't recognize the two paths as the same since they differ in upper vs lower case. Fix your imports so that they reference the same file.