Getting Unexptected null value with Responsive datatable Flutter - flutter

I have implemented this widget 'Responsive datatable' to my Flutter web app.
But I am having some issues and getting this error:
The following TypeErrorImpl was thrown building ResponsiveDatatable(dirty, dependencies: [MediaQuery], state: _ResponsiveDatatableState#5acd2):Unexpected null value.
It works and I am getting data inside my Datatable when I scale my browser to tablet size, but when I click on fullscreen the error shows.
Here is the my code:
class UsersPage extends StatefulWidget {
static const String id = "users_page";
UsersPage({Key? key}) : super(key: key);
#override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State<UsersPage> {
late List<DatatableHeader> _headers;
List<int> _perPages = [5, 10, 15, 100];
int _total = 100;
int? _currentPerPage = 5;
int _currentPage = 1;
bool _isSearch = false;
List<Map<String, dynamic>> _source = [];
List<Map<String, dynamic>> _selecteds = [];
String _selectableKey = "id";
String? _sortColumn;
bool _sortAscending = true;
bool _isLoading = true;
bool _showSelect = true;
UserServices _userServices = UserServices();
List<UserModel> _users = <UserModel>[];
List<UserModel> get users => _users;
Future _loadFromFirebase() async {
_users = await _userServices.getAllUsers();
}
List<Map<String, dynamic>> _getUsersData() {
_isLoading = true;
List<Map<String, dynamic>> temps = [];
var i = _users.length;
print(i);
// ignore: unused_local_variable
for (UserModel userData in _users) {
print(userData.name);
print(userData.email);
temps.add({
"id": userData.uid,
"email": userData.email,
"name": userData.name,
});
i++;
}
return temps;
}
_initializeData() async {
_isLoading = true;
await _loadFromFirebase();
_source.addAll(_getUsersData());
print(_source);
}
onSort(dynamic value) {
_sortColumn = value;
_sortAscending = !_sortAscending;
if (_sortAscending) {
_source
.sort((a, b) => b["$_sortColumn"].compareTo(a["$_sortColumn"]));
} else {
_source
.sort((a, b) => a["$_sortColumn"].compareTo(b["$_sortColumn"]));
}
}
onChanged(int value) {
_currentPerPage = value;
}
previous() {
_currentPage = _currentPage >= 2 ? _currentPage - 1 : 1;
}
next() {
_currentPage++;
}
#override
void initState() {
super.initState();
/// set headers
_headers = [
DatatableHeader(
text: "ID",
value: "id",
show: true,
sortable: true,
textAlign: TextAlign.center),
DatatableHeader(
text: "Name",
value: "name",
show: true,
flex: 2,
sortable: true,
editable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "SKU",
value: "email",
show: true,
sortable: true,
textAlign: TextAlign.center),
];
_initializeData();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(0),
constraints: BoxConstraints(
maxHeight: 700,
),
child: Card(
elevation: 1,
shadowColor: Colors.black,
clipBehavior: Clip.none,
child: ResponsiveDatatable(
title: !_isSearch
? ElevatedButton.icon(
onPressed: () {},
icon: Icon(Icons.add),
label: Text("ADD CATEGORY")) : null,
actions: [
if (_isSearch)
Expanded(
child: TextField(
decoration: InputDecoration(
prefixIcon: IconButton(
icon: Icon(Icons.cancel),
onPressed: () {
setState(() {
_isSearch = false;
});
}),
suffixIcon: IconButton(
icon: Icon(Icons.search), onPressed: () {})),
)),
if (!_isSearch)
IconButton(
icon: Icon(Icons.search),
onPressed: () {
setState(() {
_isSearch = true;
});
})
],
headers: _headers,
source: _source,
selecteds: _selecteds,
showSelect: _showSelect,
autoHeight: true,
onTabRow: (data) {
print(data);
},
onSort: onSort,
sortAscending: _sortAscending,
sortColumn: _sortColumn,
isLoading: _isLoading,
onSelect: (value, item) {
print("$value $item ");
if (value!) {
setState(() => _selecteds.add(item));
} else {
setState(
() => _selecteds.removeAt(_selecteds.indexOf(item)));
}
},
onSelectAll: (value) {
if (value!) {
setState(() => _selecteds =
_source.map((entry) => entry).toList().cast());
} else {
setState(() => _selecteds.clear());
}
},
footers: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Text("Rows per page:"),
),
if (_perPages != null)
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: DropdownButton(
value: _currentPerPage,
items: _perPages
.map((e) => DropdownMenuItem(
child: Text("$e"),
value: e,
))
.toList(),
onChanged: (value) {}),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Text(
"${_currentPage} - ${_currentPage} of ${_total}"),
),
IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 16,
),
onPressed: previous,
padding: EdgeInsets.symmetric(horizontal: 15),
),
IconButton(
icon: Icon(Icons.arrow_forward_ios, size: 16),
onPressed: next,
padding: EdgeInsets.symmetric(horizontal: 15),
)
],
),
),
),
],
),
);
}
}

Related

Unable to empty stored string of a variable after textEditingController.clear()

I am trying to build an animated search widget. When I use this widget in a different screen, I am storing the text of the textEditingController searchController of this search widget in a String variable searchText. The searchText variable is updating fine when I assign it the value of the searchController.text during the onChanged function call of the widget. However, when I click on the icon button of the search widget, I am clearing the searchController but it is not updating the value of the searchText variable. What I understand is that the clear() action is not a part of the onChanged() call.
How do I update the value of the searchText variable when the searchController.clear() is called in the onPressed call of the icon button? I am implementing Tween animation in the onPressed function of the icon button, so I am not sure if I can/should be using it to update the value of the string variable.
My Code
girls_screen.dart
import 'package:animation_search_bar/animation_search_bar.dart';
import 'package:flutter/material.dart';
import 'package:switch_circle_color/model/girls.dart';
import 'package:switch_circle_color/screens/gender.dart';
import 'package:switch_circle_color/screens/girls_cart.dart';
import 'package:switch_circle_color/screens/search_widget.dart';
import 'package:switch_circle_color/screens/selected_girl_details.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import '../global_variables/global_variables.dart';
int distance = 15;
int age = 25;
String sortCriterion = "distance";
bool isSingle = false;
bool isSerious = false;
int count = 0;
String searchText = "";
List<Girls> allGirls = [
Girls("Reshmita", 25, 33, "Married", "Serious"),
Girls("Ankita", 17, 26, "Single", "Serious"),
Girls("Rupali", 42, 28, "Single", "Casual"),
Girls("Monica", 50, 24, "Single", "Casual"),
Girls("Sakshi", 9, 27, "Married", "Casual"),
];
List<Girls> filteredGirlsbyDistance = [];
List<Girls> filteredGirlsbyAge = [];
List<Girls> filteredGirls = [];
List<Girls> filteredGirlsbySerious = [];
List<Girls> filteredGirlsbySingle = [];
//List<Girls> girlsCart = [];
void addGirlToCart(Girls girl) {
girlsCart.add(girl);
cartValue = cartValue + girl.age;
}
void removeGirlsfromCart(Girls girl) {
girlsCart.remove(girl);
cartValue = cartValue - girl.age;
}
String selectedGirlName = "";
int? selectedGirlDistance;
void populateFilteredGirls(int dis, int ag) {
filteredGirlsbyDistance.clear();
filteredGirlsbyAge.clear();
filteredGirlsbySingle.clear();
filteredGirlsbySerious.clear();
filteredGirls.clear();
//int len = filteredGirls.length;
for (int i = 0; i < allGirls.length; i++) {
if (allGirls[i].distance <= dis) {
filteredGirlsbyDistance.add(allGirls[i]);
}
}
filteredGirls = filteredGirlsbyDistance;
for (int i = 0; i < filteredGirls.length; i++) {
if (filteredGirls[i].age <= ag) {
filteredGirlsbyAge.add(filteredGirls[i]);
}
}
filteredGirls = filteredGirlsbyAge;
//len = filteredGirls.length;
if (isSingle == true) {
for (int i = 0; i < filteredGirls.length; i++) {
if (filteredGirls[i].status.toLowerCase() == "single") {
filteredGirlsbySingle.add(filteredGirls[i]);
}
}
filteredGirls = filteredGirlsbySingle;
}
if (isSerious == true) {
for (int i = 0; i < filteredGirls.length; i++) {
if (filteredGirls[i].lookingFor.toLowerCase() == "serious") {
filteredGirlsbySerious.add(filteredGirls[i]);
}
}
filteredGirls = filteredGirlsbySerious;
}
//filteredGirls = filteredGirls.toSet().toList();
}
class GirlsResultGrid extends StatefulWidget {
GirlsResultGrid({Key? key}) : super(key: key);
#override
State<GirlsResultGrid> createState() => _GirlsResultGridState();
}
class _GirlsResultGridState extends State<GirlsResultGrid> {
//late final GlobalKey<AnimationLimiterState> _key
#override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(5.0),
child: AnimationLimiter(
key: ValueKey("list $count"),
child: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 5,
mainAxisSpacing: 5,
childAspectRatio: 2,
children: List.generate(filteredGirls.length, (index) {
return AnimationConfiguration.staggeredGrid(
columnCount: 2,
position: index,
duration: const Duration(milliseconds: 375),
child: SlideAnimation(
child: FadeInAnimation(
child: ListTile(
leading: InkWell(
child: const Icon(Icons.girl_outlined),
onTap: () {
removeGirlsfromCart(filteredGirls[index]);
},
),
trailing: InkWell(
child: Text("${filteredGirls[index].distance} km away"),
onTap: () {
addGirlToCart(filteredGirls[index]);
},
),
title: Text("${filteredGirls[index].name}"),
subtitle: Text(
"${filteredGirls[index].age} years old, ${filteredGirls[index].status}, ${filteredGirls[index].lookingFor}"),
onTap: () {
// setState(() {
// selectedGirlName = filteredGirls[index].name;
// selectedGirlDistance = filteredGirls[index].distance;
// });
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SelectedGirlDetails(
girl: filteredGirls[index],
)));
},
),
),
),
);
}),
//itemCount: ,
//itemBuilder: (BuildContext context, int index) {
),
),
),
);
}
}
class GirlsScreen extends StatefulWidget {
GirlsScreen({Key? key}) : super(key: key);
#override
State<GirlsScreen> createState() => _GirlsScreenState();
}
class _GirlsScreenState extends State<GirlsScreen> {
TextEditingController searchTextEditingController = TextEditingController();
void changeDistance(double num) {
setState(() {
distance = num.round();
populateFilteredGirls(distance, age);
count++;
});
}
void changeAgeLimit(double a) {
setState(() {
age = a.round();
populateFilteredGirls(distance, age);
count++;
});
}
#override
void initState() {
super.initState();
//filteredGirls = allGirls;
distance = 20;
age = 28;
sortCriterion = "distance";
isSingle = false;
isSerious = false;
(sortCriterion == "distance")
? allGirls.sort((a, b) => a.distance.compareTo(b.distance))
: allGirls.sort((a, b) => a.age.compareTo(b.age));
populateFilteredGirls(distance, age);
}
// Widget buildResult(BuildContext context) {
// }
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Padding(padding: EdgeInsets.all(10)),
// ElevatedButton(
// onPressed: () {
// Navigator.push(context,
// MaterialPageRoute(builder: (context) => GenderScreen()));
// },
// child: Text("Go to Gender Screen")),
// Padding(padding: EdgeInsets.all(30)),
SearchWidget(
searchController: searchTextEditingController,
onChanged: (p0) {
setState(() {
searchText = p0;
});
},
),
Text("Girl searched is: $searchText"),
Padding(padding: EdgeInsets.all(10)),
Text("Set max distance"),
Padding(padding: EdgeInsets.all(10)),
Slider(
min: 1.0,
max: 100.0,
divisions: 100,
activeColor: Colors.green,
inactiveColor: Colors.orange,
label: 'Set distance value',
value: distance.toDouble(),
onChanged: (value) {
changeDistance(value);
},
),
Padding(padding: EdgeInsets.all(10)),
Text("Current distance is $distance kms"),
Padding(padding: EdgeInsets.all(10)),
Text("Set max age"),
Padding(padding: EdgeInsets.all(10)),
Slider(
min: 18.0,
max: 60.0,
divisions: 42,
activeColor: Colors.green,
inactiveColor: Colors.orange,
label: 'Set age limit',
value: age.toDouble(),
onChanged: (value) {
changeAgeLimit(value);
},
),
Padding(padding: EdgeInsets.all(10)),
Text("Age limit is $age years"),
Padding(padding: EdgeInsets.all(10)),
Text("Sort by:"),
Padding(padding: EdgeInsets.all(7.5)),
ListTile(
//minLeadingWidth: 30,
title: Text("Age"),
leading: Radio(
value: "age",
groupValue: sortCriterion,
onChanged: (value) {
setState(() {
sortCriterion = value.toString();
allGirls.sort((a, b) => a.age.compareTo(b.age));
populateFilteredGirls(distance, age);
count++;
});
},
),
),
Padding(padding: EdgeInsets.all(7.5)),
ListTile(
//minLeadingWidth: 30,
title: Text("Distance"),
leading: Radio(
value: "distance",
groupValue: sortCriterion,
onChanged: (value) {
setState(() {
sortCriterion = value.toString();
allGirls.sort((a, b) => a.distance.compareTo(b.distance));
populateFilteredGirls(distance, age);
count++;
});
},
),
),
Padding(padding: EdgeInsets.all(10)),
Text("Is Single?"),
Padding(padding: EdgeInsets.all(2.5)),
InkWell(
onTap: () {
setState(() {
isSingle = !isSingle;
populateFilteredGirls(distance, age);
count++;
});
},
child: (isSingle == false)
? Icon(Icons.check_box_outline_blank)
: Icon(Icons.check_box),
),
Padding(padding: EdgeInsets.all(5)),
Text("Is Serious?"),
Padding(padding: EdgeInsets.all(2.5)),
InkWell(
onTap: () {
setState(() {
isSerious = !isSerious;
populateFilteredGirls(distance, age);
count++;
});
},
child: (isSerious == false)
? Icon(Icons.check_box_outline_blank)
: Icon(Icons.check_box),
),
Padding(padding: EdgeInsets.all(10)),
//buildResult(context),
GirlsResultGrid(),
Padding(padding: EdgeInsets.all(25)),
ElevatedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => GirlsCart()));
},
child: Text("Go to Girls Cart")),
Padding(padding: EdgeInsets.all(25)),
],
),
));
}
}
search_widget.dart
import 'package:flutter/material.dart';
class SearchWidget extends StatefulWidget {
Function(String)? onChanged;
TextEditingController? searchController;
VoidCallback? onTap;
SearchWidget({
Key? key,
this.onChanged,
this.searchController,
this.onTap,
}) : super(key: key);
#override
State<SearchWidget> createState() => _SearchWidgetState();
}
class _SearchWidgetState extends State<SearchWidget>
with SingleTickerProviderStateMixin {
late Animation<double> animation;
late AnimationController animController;
bool isForward = false;
//TextEditingController searchController = TextEditingController();
#override
void initState() {
// TODO: implement initState
super.initState();
animController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
);
final curvedAnimation =
CurvedAnimation(parent: animController, curve: Curves.easeOutExpo);
animation = Tween<double>(begin: 0, end: 150).animate(curvedAnimation)
..addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Material(
child: Padding(
padding: const EdgeInsets.all(25.0),
child: Container(
width: 220,
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
width: animation.value,
decoration: BoxDecoration(
color: Colors.black87,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50),
bottomLeft: Radius.circular(50),
),
),
child: Padding(
padding: EdgeInsets.only(left: 20, bottom: 5),
child: TextField(
//autofocus: true,
controller: widget.searchController,
onChanged: widget.onChanged,
cursorColor: Colors.white54,
style: TextStyle(color: Colors.white54, fontSize: 12),
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Search girls...",
hintStyle: TextStyle(color: Colors.white30),
),
),
),
),
Container(
width: 50,
height: 53,
decoration: BoxDecoration(
color: Colors.black87,
borderRadius: animation.value > 1
? BorderRadius.only(
topLeft: Radius.circular(0),
bottomRight: Radius.circular(50),
bottomLeft: Radius.circular(0),
topRight: Radius.circular(50),
)
: BorderRadius.circular(50),
),
child: IconButton(
onPressed: () {
if (!isForward) {
animController.forward();
isForward = true;
} else if (isForward &&
widget.searchController!.text != "") {
widget.searchController!.clear();
} else {
animController.reverse();
isForward = false;
}
},
icon: (!isForward)
? Icon(
Icons.search,
color: Colors.white54,
)
: Icon(
Icons.close_rounded,
color: Colors.white54,
),
),
),
],
),
),
),
);
}
}
Video for reference
https://vimeo.com/735839961
Realized the solution. I added a Voidcallback parameter to the widget, which is called once the cross icon button is tapped on.
In girls_screen.dart
SearchWidget(
searchController: searchTextEditingController,
onChanged: (p0) {
setState(() {
searchText = p0;
});
},
onTap: () {
if (searchText != "") {
setState(() {
searchText = "";
});
}
},
),
In search_widget.dart
child: IconButton(
onPressed: () {
if (!isForward) {
animController.forward();
isForward = true;
} else if (isForward &&
widget.searchController!.text != "") {
widget.searchController!.clear();
} else {
animController.reverse();
isForward = false;
}
widget.onTap!();
},

How to refresh my datatable when I have made changes without hot restarting?

I have implemented this widget: Responisve Datatable and used this Github Responsive Datatable as source.
I am facing a challange when I do some changes in my Database I need to refresh my browser or hot restart to see the changes. I can't find any solution to my problem.
I want to have a Button to refresh my Datatable, but I don't know how to set it up.
Here is my code:
Class:
class UserTableProvider with ChangeNotifier {
List<DatatableHeader> userTableHeader = [
DatatableHeader(
text: "Ansattnr",
value: "empnumber",
show: true,
flex: 1,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Navn",
value: "name",
show: true,
flex: 6,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Epost",
value: "email",
show: true,
flex: 4,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "",
value: "uid",
show: false,
sortable: true,
textAlign: TextAlign.center),
DatatableHeader(
text: "Tlf",
value: "tlfnumber",
show: true,
flex: 2,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Eget verktøy",
value: "owntool",
show: false,
sortable: true,
textAlign: TextAlign.left),
];
final List<int> perPages = [10, 20, 50, 100];
int total = 100;
int? currentPerPage = 10;
int currentPage = 1;
List<bool>? expanded;
String? searchKey = "empnumber";
bool isSearch = false;
List<Map<String, dynamic>> sourceOriginal = [];
List<Map<String, dynamic>> sourceFiltered = [];
List<Map<String, dynamic>> source = [];
List<Map<String, dynamic>> selecteds = [];
// ignore: unused_field
final String selectableKey = "id";
String? sortColumn;
bool sortAscending = true;
bool isLoading = true;
final bool showSelect = true;
final UserServices _userServices = UserServices();
List<UserModel> _users = <UserModel>[];
List<UserModel> get users => _users;
Future _loadFromFirebase() async {
_users = await _userServices.getAllUsers();
}
List<Map<String, dynamic>> _getUsersData() {
isLoading = true;
List<Map<String, dynamic>> temps = [];
var i = users.length;
if (kDebugMode) {
print(i);
}
// ignore: unused_local_variable
for (UserModel userData in users) {
if (kDebugMode) {
print(userData.name);
}
if (kDebugMode) {
print(userData.email);
}
temps.add({
"empnumber": userData.empnumber,
"email": userData.email,
"name": userData.name,
"uid": userData.uid,
"owntool": userData.owntool,
"tlfnumber": userData.tlfnumber,
});
i++;
}
return temps;
}
_initData() async {
await _loadFromFirebase();
mockPullData();
notifyListeners();
}
mockPullData() async {
expanded = List.generate(currentPerPage!, (index) => false);
isLoading = true;
Future.delayed(const Duration(seconds: 3)).then((value) {
sourceOriginal.clear();
sourceOriginal.addAll(_getUsersData());
sourceFiltered = sourceOriginal;
total = sourceFiltered.length;
source = sourceFiltered.getRange(0, _users.length).toList();
isLoading = false;
notifyListeners();
});
}
resetData({start: 0}) async {
isLoading = true;
var expandedLen =
total - start < currentPerPage! ? total - start : currentPerPage;
Future.delayed(const Duration(seconds: 0)).then((value) {
expanded = List.generate(expandedLen as int, (index) => false);
source.clear();
source = sourceFiltered.getRange(start, start + expandedLen).toList();
isLoading = false;
notifyListeners();
});
}
filterData(value) {
isLoading = true;
try {
if (value == "" || value == null) {
source = sourceOriginal;
} else {
sourceFiltered = sourceOriginal
.where((data) => data[searchKey!]
.toString()
.toLowerCase()
.contains(value.toString().toLowerCase()))
.toList();
}
total = sourceFiltered.length;
var _rangeTop = total < currentPerPage! ? total : currentPerPage!;
expanded = List.generate(_rangeTop, (index) => false);
source = sourceFiltered.getRange(0, _rangeTop).toList();
} catch (e) {
print(e);
}
isLoading = false;
notifyListeners();
}
UserTableProvider.init() {
_initData();
}
}
Page:
class _UsersPageState extends State<UsersPage> {
var nameController = TextEditingController();
#override
Widget build(BuildContext context) {
final UserTableProvider usertablesProvider = Provider.of<UserTableProvider>(context);
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(0),
constraints: BoxConstraints(
maxHeight: 700,
),
child: Card(
elevation: 1,
shadowColor: Colors.black,
clipBehavior: Clip.none,
child: ResponsiveDatatable(
title: TextButton.icon(
onPressed: () => {
addUserDialog(context),
},
icon: Icon(Icons.add),
label: Text("Legg til bruker"),
),
reponseScreenSizes: [ScreenSize.xs],
actions: [
if (usertablesProvider.isSearch)
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Søk på ansattnr..',
prefixIcon: IconButton(
icon: Icon(Icons.cancel),
onPressed: () {
setState(() {
usertablesProvider.isSearch = false;
});
}),
suffixIcon: IconButton(
icon: Icon(Icons.search), onPressed: () {})),
onSubmitted: (value) {
usertablesProvider.filterData(value);
},
)),
if (!usertablesProvider.isSearch)
IconButton(
icon: Icon(Icons.search),
onPressed: () {
setState(() {
usertablesProvider.isSearch = true;
});
}),
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
//Here I want to refresh my datatable....
}),
],
headers: usertablesProvider.userTableHeader,
source: usertablesProvider.source,
selecteds: usertablesProvider.selecteds,
showSelect: usertablesProvider.showSelect,
autoHeight: false,
onSort: (value) {
setState(() => usertablesProvider.isLoading = true);
setState(() {
usertablesProvider.sortColumn = value;
usertablesProvider.sortAscending = !usertablesProvider.sortAscending;
if (usertablesProvider.sortAscending) {
usertablesProvider.sourceFiltered.sort((a, b) =>
b["${usertablesProvider.sortColumn}"].compareTo(a["${usertablesProvider.sortColumn}"]));
} else {
usertablesProvider.sourceFiltered.sort((a, b) =>
a["${usertablesProvider.sortColumn}"].compareTo(b["${usertablesProvider.sortColumn}"]));
}
var _rangeTop = usertablesProvider.currentPerPage! < usertablesProvider.sourceFiltered.length
? usertablesProvider.currentPerPage!
: usertablesProvider.sourceFiltered.length;
usertablesProvider.source = usertablesProvider.sourceFiltered.getRange(0, _rangeTop).toList();
usertablesProvider.searchKey = value;
usertablesProvider.isLoading = false;
});
},
expanded: usertablesProvider.expanded,
sortAscending: usertablesProvider.sortAscending,
sortColumn: usertablesProvider.sortColumn,
isLoading: usertablesProvider.isLoading,
onTabRow: (data){
updateUserDialog(context);
print(data);
nameController.text = data['name'];
},
onSelect: (value, item) {
print("$value $item ");
if (value!) {
setState(() => usertablesProvider.selecteds.add(item));
} else {
setState(
() => usertablesProvider.selecteds.removeAt(usertablesProvider.selecteds.indexOf(item)));
}
},
onSelectAll: (value) {
if (value!) {
setState(() => usertablesProvider.selecteds =
usertablesProvider.source.map((entry) => entry).toList().cast());
} else {
setState(() => usertablesProvider.selecteds.clear());
}
},
footers: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Text("Rader per side:"),
),
if (usertablesProvider.perPages.isNotEmpty)
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: DropdownButton<int>(
value: usertablesProvider.currentPerPage,
items: usertablesProvider.perPages
.map((e) => DropdownMenuItem<int>(
child: Text("$e"),
value: e,
))
.toList(),
onChanged: (dynamic value) {
setState(() {
usertablesProvider.currentPerPage = value;
usertablesProvider.currentPage = 1;
usertablesProvider.resetData();
});
},
isExpanded: false,
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child:
Text("${usertablesProvider.currentPage} - ${usertablesProvider.currentPerPage} of ${usertablesProvider.total}"),
),
IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 16,
),
onPressed: usertablesProvider.currentPage == 1
? null
: () {
var _nextSet = usertablesProvider.currentPage - usertablesProvider.currentPerPage!;
setState(() {
usertablesProvider.currentPage = _nextSet > 1 ? _nextSet : 1;
usertablesProvider.resetData(start: usertablesProvider.currentPage - 1);
});
},
padding: EdgeInsets.symmetric(horizontal: 15),
),
IconButton(
icon: Icon(Icons.arrow_forward_ios, size: 16),
onPressed: usertablesProvider.currentPage + usertablesProvider.currentPerPage! - 1 > usertablesProvider.total
? null
: () {
var _nextSet = usertablesProvider.currentPage + usertablesProvider.currentPerPage!;
setState(() {
usertablesProvider.currentPage = _nextSet < usertablesProvider.total
? _nextSet
: usertablesProvider.total - usertablesProvider.currentPerPage!;
usertablesProvider.resetData(start: _nextSet - 1);
});
},
padding: EdgeInsets.symmetric(horizontal: 15),
)
],
),
),
),
])
);
}
updateUserDialog(BuildContext context){
return showDialog(context: context, builder: (context) {
return Dialog(
child: Container(
child: SizedBox(
width: 600,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Endre bruker', style: TextStyle(
fontWeight: FontWeight.bold
),),
SizedBox(
height: 10,
),
TextField(
controller: nameController,
decoration: const InputDecoration(
labelText: 'Navn',
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)
)
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)
)
),
),
ElevatedButton(
onPressed: () async {
var name = nameController.text.trim();
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
FirebaseAuth auth = FirebaseAuth.instance;
User? user = auth.currentUser;
await firebaseFirestore.collection('users').doc(user!.uid).update({
'navn': name,
});
nameController.text = '';
},
child: const Text('Save')),
const SizedBox(
height: 10,
),
],
),
),
),
);
});
}

Error: RangeError (end): Invalid value: Not in inclusive range 0..1: 10 - creating a userstable

I want to create a panel in which I can see all user data which are stored in my firebase.
For this task I decided to use the responsive_table:^0.2.0+2 code. (https://pub.dev/packages/responsive_table) This is a table with hard coded data.
For a better overview I decided to divide the code in the page-layout file and a methods/variables file.
DataPage is my overview page in which I have my page layout and TestTable is the page for the methods and variables.
Before I used my firebase to connect my data to the table, I tried to use hard coded data which actually worked. But after I have implemented the connection to my firebase I get the error (when I am running the code):
Error: RangeError (end): Invalid value: Not in inclusive range 0..2: 10
at Object.throw_ [as throw] (http://localhost:51303/dart_sdk.js:5646:11)
at RangeError.checkValidRange (http://localhost:51303/dart_sdk.js:136032:21)
at [dartx.getRange] (http://localhost:51303/dart_sdk.js:18141:25)
at test_table.TestTable.init.mockPullData (http://localhost:51303/packages/bestfitnesstrackereu/pages/user_administration/test_table.dart.lib.js:227:63)
at mockPullData.next (<anonymous>)
at http://localhost:51303/dart_sdk.js:43211:33
at _RootZone.runUnary (http://localhost:51303/dart_sdk.js:42983:58)
at _FutureListener.thenAwait.handleValue (http://localhost:51303/dart_sdk.js:37734:29)
at handleValueCallback (http://localhost:51303/dart_sdk.js:38329:49)
at _Future._propagateToListeners (http://localhost:51303/dart_sdk.js:38367:17)
at [_completeWithValue] (http://localhost:51303/dart_sdk.js:38196:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:51303/dart_sdk.js:38232:35)
at Object._microtaskLoop (http://localhost:51303/dart_sdk.js:43360:13)
at _startMicrotaskLoop (http://localhost:51303/dart_sdk.js:43366:13)
at http://localhost:51303/dart_sdk.js:38600:9
Also I get a permanent loading symbole (the blue bar below the headers):
I can't find the reason, why I am getting this error. I hope you can help me.
Edit:
I just found out, that the page is working. When I click on "Rows per page" and select any number (10,20,50,100), then the page refresh and shows the users in my firebase. It is just an initialize problem.
Now I just need to find out where the problem is and fix it.
Edit 2:
I changed initializeData() methode from:
usersTableSource = sourceFiltered.getRange(0, currentPerPage).toList();
to:
usersTableSource = sourceFiltered.getRange(0, _users.length).toList();
Now the initialisation won't need the minimum amount of currentPerPage as content.
PROBLEM SOLVED
DataPage.dart code:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:responsive_table/responsive_table.dart';
import 'package:bestfitnesstrackereu/pages/user_administration/test_table.dart';
class DataPage extends StatefulWidget {
DataPage({Key key}) : super(key: key);
#override
_DataPageState createState() => _DataPageState();
}
class _DataPageState extends State<DataPage> {
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
final TestTable testTable = Provider.of<TestTable>(context);
return Scaffold(
appBar: AppBar(
title: Text("RESPONSIVE DATA TABLE"),
),
drawer: Drawer(
child: ListView(
children: [
ListTile(
leading: Icon(Icons.home),
title: Text("home"),
onTap: () {},
),
ListTile(
leading: Icon(Icons.storage),
title: Text("data"),
onTap: () {},
)
],
),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(0),
constraints: BoxConstraints(
maxHeight: 700,
),
child: Card(
elevation: 1,
shadowColor: Colors.black,
clipBehavior: Clip.none,
child: ResponsiveDatatable(
title: TextButton.icon(
onPressed: () => {},
icon: Icon(Icons.add),
label: Text("new item"),
),
reponseScreenSizes: [ScreenSize.xs],
actions: [
if (testTable.isSearch)
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Enter search term based on ' +
testTable.searchKey
.replaceAll(new RegExp('[\\W_]+'), ' ')
.toUpperCase(),
prefixIcon: IconButton(
icon: Icon(Icons.cancel),
onPressed: () {
setState(() {
testTable.isSearch = false;
});
testTable.initializeData();
}),
suffixIcon: IconButton(
icon: Icon(Icons.search), onPressed: () {})),
onSubmitted: (value) {
testTable.filterData(value);
},
)),
if (!testTable.isSearch)
IconButton(
icon: Icon(Icons.search),
onPressed: () {
setState(() {
testTable.isSearch = true;
});
})
],
headers: testTable.headers,
source: testTable.usersTableSource,
selecteds: testTable.selecteds,
showSelect: testTable.showSelect,
autoHeight: false,
dropContainer: (data) {
if (int.tryParse(data['id'].toString()).isEven) {
return Text("is Even");
}
return _DropDownContainer(data: data);
},
onChangedRow: (value, header) {
/// print(value);
/// print(header);
},
onSubmittedRow: (value, header) {
/// print(value);
/// print(header);
},
onTabRow: (data) {
print(data);
},
onSort: testTable.onSort,
expanded: testTable.expanded,
sortAscending: testTable.sortAscending,
sortColumn: testTable.sortColumn,
isLoading: testTable.isLoading,
onSelect: testTable.onSelected,
onSelectAll: testTable.onSelectAll,
footers: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Text("Rows per page:"),
),
if (testTable.perPages.isNotEmpty)
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: DropdownButton<int>(
value: testTable.currentPerPage,
items: testTable.perPages
.map((e) => DropdownMenuItem<int>(
child: Text("$e"),
value: e,
))
.toList(),
onChanged: testTable.onChanged,
isExpanded: false,
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child:
Text("$testTable.currentPage - $testTable.currentPerPage of $testTable.total"),
),
IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 16,
),
onPressed: testTable.previous,
padding: EdgeInsets.symmetric(horizontal: 15),
),
IconButton(
icon: Icon(Icons.arrow_forward_ios, size: 16),
onPressed: testTable.next,
padding: EdgeInsets.symmetric(horizontal: 15),
)
],
),
),
),
])),
floatingActionButton: FloatingActionButton(
onPressed: testTable.initializeData,
child: Icon(Icons.refresh_sharp),
),
);
}
}
class _DropDownContainer extends StatelessWidget {
final Map<String, dynamic> data;
const _DropDownContainer({Key key, #required this.data}) : super(key: key);
#override
Widget build(BuildContext context) {
List<Widget> _children = data.entries.map<Widget>((entry) {
Widget w = Row(
children: [
Text(entry.key.toString()),
Spacer(),
Text(entry.value.toString()),
],
);
return w;
}).toList();
return Container(
/// height: 100,
child: Column(
/// children: [
/// Expanded(
/// child: Container(
/// color: Colors.red,
/// height: 50,
/// )),
/// ],
children: _children,
),
);
}
}
TestTable.dart code:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:responsive_table/responsive_table.dart';
import '../../datamodels/user_model.dart';
import '../../services/user_services.dart';
class TestTable with ChangeNotifier {
List<int> perPages = [10, 20, 50, 100];
int total = 100;
int currentPerPage = 10;
List<bool> expanded;
String searchKey = "id";
int currentPage = 1;
bool isSearch = false;
List<Map<String, dynamic>> sourceOriginal = [];
List<Map<String, dynamic>> sourceFiltered = [];
List<Map<String, dynamic>> usersTableSource = [];
List<Map<String, dynamic>> selecteds = [];
// ignore: unused_field
String selectableKey = "id";
String sortColumn;
bool sortAscending = true;
bool isLoading = true;
bool showSelect = true;
var random = new Random();
List<DatatableHeader> headers = [
DatatableHeader(
text: "UID",
value: "uid",
show: true,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Benutzername",
value: "username",
show: true,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "E-Mail",
value: "email",
show: true,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Vorname",
value: "first name",
show: true,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Nachname",
value: "last name",
show: true,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Geburtsdatum",
value: "birthday",
show: true,
sortable: true,
textAlign: TextAlign.left),
DatatableHeader(
text: "Geschlecht",
value: "gender",
show: true,
sortable: true,
textAlign: TextAlign.left),
];
UserServices _userServices = UserServices();
List<UserModel> _users = <UserModel>[];
List<UserModel> get users => _users;
Future _loadFromFirebase() async {
_users = await _userServices.getAllUsers();
}
List<Map<String, dynamic>> _getUsersData() {
List<Map<String, dynamic>> temps = [];
var i = _users.length;
print(i);
// ignore: unused_local_variable
for (UserModel userData in _users) {
temps.add({
"uid": userData.uid,
"username": userData.username ,
"email": userData.email ,
"first name": userData.firstName ,
"last name": userData.lastName ,
"birthday": userData.birthday ,
"gender": userData.gender ,
});
i++;
}
return temps;
}
initializeData() async {
mockPullData();
}
mockPullData() async {
expanded = List.generate(currentPerPage, (index) => false);
isLoading = true;
notifyListeners();
await _loadFromFirebase();
sourceOriginal.clear();
sourceOriginal.addAll(_getUsersData());
sourceFiltered = sourceOriginal;
total = sourceFiltered.length;
usersTableSource = sourceFiltered.getRange(0, currentPerPage).toList();
isLoading = false;
notifyListeners();
}
resetData({start: 0}) async {
isLoading = true;
notifyListeners();
var _expandedLen =
total - start < currentPerPage ? total - start : currentPerPage;
expanded = List.generate(_expandedLen as int, (index) => false);
usersTableSource.clear();
usersTableSource = sourceFiltered.getRange(start, start + _expandedLen).toList();
isLoading = false;
notifyListeners();
//hier future weggemacht
}
filterData(value) {
isLoading = true;
notifyListeners();
try {
if (value == "" || value == null) {
sourceFiltered = sourceOriginal;
} else {
sourceFiltered = sourceOriginal
.where((data) => data[searchKey]
.toString()
.toLowerCase()
.contains(value.toString().toLowerCase()))
.toList();
}
total = sourceFiltered.length;
var _rangeTop = total < currentPerPage ? total : currentPerPage;
expanded = List.generate(_rangeTop, (index) => false);
usersTableSource = sourceFiltered.getRange(0, _rangeTop).toList();
} catch (e) {
print(e);
}
isLoading = false;
notifyListeners();
}
onSort(dynamic value){
isLoading = true;
notifyListeners();
sortColumn = value;
sortAscending = !sortAscending;
if (sortAscending) {
sourceFiltered.sort((a, b) =>
b["$sortColumn"].compareTo(a["$sortColumn"]));
} else {
sourceFiltered.sort((a, b) =>
a["$sortColumn"].compareTo(b["$sortColumn"]));
}
var _rangeTop = currentPerPage < sourceFiltered.length
? currentPerPage
: sourceFiltered.length;
usersTableSource = sourceFiltered.getRange(0, _rangeTop).toList();
searchKey = value;
isLoading = false;
notifyListeners();
}
onSelected(bool value, Map <String, dynamic> item){
print("$value $item ");
if (value) {
selecteds.add(item);
} else {
selecteds.removeAt(selecteds.indexOf(item));
}
notifyListeners();
}
onSelectAll(bool value){
if (value) {
selecteds = usersTableSource.map((entry) => entry).toList().cast();
} else {
selecteds.clear();
}
notifyListeners();
}
onChanged(int value){
currentPerPage = value;
currentPage = 1;
resetData();
notifyListeners();
}
previous(){
currentPage == 1
? null
: () {
var nextSet = currentPage - currentPerPage;
currentPage = nextSet > 1 ? nextSet : 1;
resetData(start: currentPage - 1);
};
notifyListeners();
}
next(){
currentPage + currentPerPage - 1 > total
? null
: () {
var nextSet = currentPage + currentPerPage;
currentPage = nextSet < total
? nextSet
: total - currentPerPage;
resetData(start: nextSet - 1);
};
notifyListeners();
}
TestTable.init() {
initializeData();
}
}
it's related to loop range try to pass range as per data length see this post you will find you answer
var arr = [1, 2, 3];
for (var i=0; i < 4; i++) {
print(arr[i]);
}
check out boundary of data length

Fill up form with existing data is not working in flutter

I start flutter recently. I want to fill up the form with existing data but the two dropdown is not filled up by existing data. I struggled for couple of hours to fix this but no luck. Here is my complete code:
import 'package:awesome_select/awesome_select.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/data/service.dart';
import '../common/bottom_navigation.dart';
import '../common/floating_button.dart';
import '../widget/TextInput.dart';
class NewPickupPoint extends StatefulWidget {
static const String routeName = '/newPickupPointPage';
const NewPickupPoint({Key? key}) : super(key: key);
#override
State<NewPickupPoint> createState() => _NewPickupPointState();
}
class _NewPickupPointState extends State<NewPickupPoint> {
final _formKey = GlobalKey<FormState>();
TextEditingController nameController = TextEditingController();
TextEditingController addressController = TextEditingController();
bool showform = false;
List<S2Choice<int>> districts = [];
List<S2Choice<int>> areas = [];
List userPickupPoint = [];
bool loadingDistrict = false;
bool loadingUpazilla = false;
bool loadingExistingData = false;
int districtId = 0;
int areaId = 0;
void initState() {
super.initState();
Service().getPickupAddress(context).then((response) {
setState(() {
nameController.text = response['title'];
addressController.text = response['street'];
districtId = response['district'];
areaId = response['upazilla'];
loadingExistingData = true;
});
});
updateDistrictList();
updateAreaList(districtId);
}
updateDistrictList() async {
var _futureOfList = Service().getDistrictList();
List list = await _futureOfList;
for (var i = 0; i < list.length; i++) {
setState(() {
districts
.add(S2Choice<int>(value: list[i]['id'], title: list[i]['name']));
loadingDistrict = true;
});
}
}
updateAreaList(int? value) async {
var _futureOfList = await Service().getAreaList(districtId, context);
List list = await _futureOfList;
List<S2Choice<int>> areaList = [];
setState(() {
list.forEach((element) {
areaList
.add(S2Choice<int>(value: element['id'], title: element['name']));
});
print(areaList);
});
setState(() {
areas = areaList;
});
}
setDistrictList() async {
var _futureOfList = Service().getDistrictList();
List list = await _futureOfList;
for (var i = 0; i < list.length; i++) {
setState(() {
districts
.add(S2Choice<int>(value: list[i]['id'], title: list[i]['name']));
});
}
}
#override
Widget build(BuildContext context) {
bool keyboardIsOpen = MediaQuery.of(context).viewInsets.bottom != 0;
return Scaffold(
appBar: AppBar(
title: Text('Add new pickup point'),
),
body: SingleChildScrollView(
child: new Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
// Card For Showing user pickup addresse
Padding(
padding: MediaQuery.of(context).viewInsets,
child: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 30.0),
child: TextInput(
inputController: nameController,
label: 'Name of the pickup point',
icon: Icons.edit,
),
),
if (loadingDistrict && loadingExistingData)
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 30.0),
child: SmartSelect<int>.single(
modalFilter: true,
modalFilterAuto: true,
tileBuilder: (context, state) => S2Tile<dynamic>(
//https://github.com/akbarpulatov/flutter_awesome_select/blob/master/example/lib/features_single/single_chips.dart
title: const Text(
'District',
),
value: state.selected?.toWidget() ?? Container(),
leading: Icon(Icons.list_outlined),
onTap: state.showModal,
),
title: 'District',
placeholder: 'Select',
choiceItems: districts,
onChange: (state) {
setState(() {
districtId = state.value!;
updateAreaList(state.value).then((value) {
setState(() {});
});
});
},
selectedValue: districtId,
),
),
if (loadingExistingData)
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 30.0),
child: SmartSelect<int>.single(
modalFilter: true,
modalFilterAuto: true,
tileBuilder: (context, state) => S2Tile<dynamic>(
//https://github.com/akbarpulatov/flutter_awesome_select/blob/master/example/lib/features_single/single_chips.dart
title: const Text(
'এলাকা',
),
value: state.selected?.toWidget() ?? Container(),
leading: Icon(Icons.list_outlined),
onTap: state.showModal,
),
title: 'Area',
placeholder: 'Select',
choiceItems: areas,
onChange: (state) =>
setState(() => areaId = state.value!),
selectedValue: areaId,
),
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 30.0),
child: TextInput(
inputController: addressController,
label: 'Detail Address',
icon: Icons.map_outlined),
),
Text(
'For example: House 118/D, Road: 05, Mohanagar Project, Dhaka',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey,
fontSize: 10,
),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_savePickupPoint(context);
}
},
child: Text('Save'),
)
],
),
),
),
]),
),
),
bottomNavigationBar: BottomNavigation(),
floatingActionButton: Visibility(
visible: !keyboardIsOpen,
child: Padding(
padding: EdgeInsets.only(
top: 45,
),
child: floating(context),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
void _savePickupPoint(BuildContext context) {
Service().addPickupPoint(nameController.text, districtId, areaId,
addressController.text, context);
}
}
You have two options.
By setting the initial value of a formcontrol
TextFormField(
initialValue: 'The value you want to show',
)
By setting the controller value immediately after geeting the value. If can be in the Init method or before the builder method
_yourController.text = "The value you want to show";

image picker is not uploading image and it will send the null value to the backend

I've one page on that page there is one add button and it will add the widget as much users want but when I am uploading image it will not upload. and when I press the add button it will already upload the image on the next generated widget. and also it is not giving me the value of that images.
Here is the image it will upload image on the click of the image add button but it's not uploading. and also when I am adding multipart it will send the value as null to the backend side
Here is code i've tried.
class BspUnlicensedSignupPage extends StatefulWidget {
static const String routeName = "/bspUnlicensedSignup";
final BspSignupCommonModel bspSignupCommonModel;
BspUnlicensedSignupPage({
Key key,
#required this.bspSignupCommonModel,
}) : super(key: key);
#override
_BspUnlicensedSignupPageState createState() =>
_BspUnlicensedSignupPageState();
}
class _BspUnlicensedSignupPageState extends State<BspUnlicensedSignupPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
List<Object> images = List<Object>();
Future<File> _imageFile;
bool autovalidate = false;
bool informationislegitimate = false;
DateTime expirydate1 = DateTime.now();
DateTime expirydate2 = DateTime.now();
final format = DateFormat("yyyy-MM-dd");
final format2 = DateFormat("yyyy-MM-dd");
String type2 = 'Passport';
List<String> _type = <String>[
'',
'Passport',
'Driving License',
'Voter ID card',
'Ration Card',
'Aadhar',
'Other Id',
];
String type = 'Passport';
// Map<String, String> _formdata = {};
var _myWidgets = List<Widget>();
int _index = 1;
final Map<int, String> identification1Values = Map();
final Map<int, String> documentValues = Map();
final Map<int, DateTime> expiryDateValues = Map();
final Map<int, String> issuingAuthority = Map();
final Map<int, String> identificationPicturesValues = Map();
final List<TextEditingController> _documentControllers = List();
final List<TextEditingController> _issuingauthoritytype = List();
final List<TextEditingController> _expiryDate = List();
final List<TextEditingController> _issuingauthority = List();
final List<List<Object>> _identificationpictures = List();
#override
void initState() {
super.initState();
setState(() {
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
});
}
void _add() {
// TextEditingController controller = TextEditingController();
setState(() {
int keyValue = _myWidgets.length;
_myWidgets = List.from(_myWidgets)
..add(Column(
key: Key("$keyValue"),
children: <Widget>[
SizedBox(height: 10),
Container(
// padding: EdgeInsets.fromLTRB(18,5,18,18),
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 15,
),
],
),
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Align(
alignment: Alignment.topRight,
child: GestureDetector(
child: Icon(Icons.close),
onTap: () {
print("CLose pressed");
setState(() {
_myWidgets = List.from(_myWidgets)
..removeAt(keyValue);
});
},
),
),
SizedBox(
height: 10,
),
Column(
children: <Widget>[
SizedBox(
height: 20,
),
_buildidentificationtype1(keyValue),
_builddocumentnumber1(keyValue),
_builddate(keyValue),
_buildissuingauthority1(keyValue),
_buildidentificationpictures(keyValue),
],
),
],
)
],
),
)
],
));
});
}
bool isClicked = false;
Widget _buildidentificationtype1(int keyValue) {
TextEditingController controller = TextEditingController();
_issuingauthoritytype.add(controller);
return FormBuilder(
autovalidate: autovalidate,
child: FormBuilderCustomField(
attribute: "Business type",
validators: [FormBuilderValidators.required()],
formField: FormField(
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
prefixIcon: Icon(Icons.location_on),
labelText : 'Business type',
),
isEmpty: type == '',
child: new DropdownButtonHideUnderline(
child: new DropdownButton(
value: type,
isDense: true,
onChanged: (String newValue) {
setState(() {
type = controller.text = newValue;
field.didChange(newValue);
});
},
items: _type.map(
(String value) {
return new DropdownMenuItem(
value: value,
child: new Text(value),
);
},
).toList(),
),
),
);
},
)),
);
}
Widget _builddocumentnumber1(int keyValue) {
TextEditingController controller = TextEditingController();
_documentControllers.add(controller);
return new TudoTextWidget(
controller: controller,
prefixIcon: Icon(FontAwesomeIcons.idCard),
labelText : 'Document Number'
onSaved: (val) {
setState(() {
documentValues[keyValue] = val;
});
// _licenseno = val;
},
);
}
Widget _builddate(int keyValue) {
TextEditingController controller = TextEditingController();
_expiryDate.add(controller);
return DateTimeField(
format: format,
autocorrect: true,
autovalidate: autovalidate,
controller: controller,
readOnly: true,
// validator: (date) => date == null ? 'Please enter valid date' : null,
decoration: InputDecoration(
labelText: "Expiry Date",
hintText: "Expiry Date",
prefixIcon: Icon(
FontAwesomeIcons.calendar,
size: 24,
)),
onShowPicker: (context, currentValue) {
return showDatePicker(
context: context,
firstDate: DateTime.now(),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime(2100));
},
);
}
Widget _buildissuingauthority1(int keyValue) {
TextEditingController controller = TextEditingController();
_issuingauthority.add(controller);
return new TudoTextWidget(
prefixIcon: Icon(FontAwesomeIcons.idCard),
labelText: 'Issuning authority',
validator: (val) => Validators.validateName(val, "Issuing Authority"),
onSaved: (val) {
setState(() {
issuingAuthority[keyValue] = val;
});
// _illusingauthority = issuingAuthority[keyValue] = val;
},
controller: controller,
);
}
Widget _buildidentificationpictures(int keyValue) {
return GridView.count(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 5,
childAspectRatio: 1,
children: List.generate(images.length, (index) {
if (images[index] is ImageUploadModel) {
ImageUploadModel uploadModel = images[index];
return Card(
clipBehavior: Clip.antiAlias,
child: Stack(
children: <Widget>[
Image.file(
uploadModel.imageFile,
width: 300,
height: 300,
),
Positioned(
right: 5,
top: 5,
child: InkWell(
child: Icon(
Icons.remove_circle,
size: 20,
color: Colors.red,
),
onTap: () {
setState(() {
images.replaceRange(index, index + 1, ['Add Image']);
_identificationpictures.add(images);
});
},
),
),
],
),
);
} else {
return Card(
child: IconButton(
icon: Icon(Icons.add),
onPressed: () {
_onAddImageClick(index);
},
),
);
}
}),
);
}
Future _onAddImageClick(int index) async {
setState(() {
_imageFile = ImagePicker.pickImage(source: ImageSource.gallery);
getFileImage(index);
});
}
void getFileImage(int index) async {
// var dir = await path_provider.getTemporaryDirectory();
_imageFile.then((file) async {
setState(() {
ImageUploadModel imageUpload = new ImageUploadModel();
imageUpload.isUploaded = false;
imageUpload.uploading = false;
imageUpload.imageFile = file;
imageUpload.imageUrl = '';
images.replaceRange(index, index + 1, [imageUpload]);
});
});
}
Widget _buildinformationislegitmate() {
return TudoConditionWidget(
text:
"Above entered Identity information is legitimate and accurate to my knowledge",
);
}
#override
Widget build(BuildContext context) {
final appBar = AppBar(
title: Text("BSP Unlicensed Details"),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
NavigationHelper.navigatetoBack(context);
},
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
_add();
});
},
),
],
centerTitle: true,
);
final bottomNavigationBar = Container(
color: Colors.transparent,
height: 56,
//margin: EdgeInsets.symmetric(vertical: 24, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(Icons.close),
label: Text('Clear'),
color: Colors.redAccent,
textColor: Colors.black,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {},
),
new FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Next'),
color: colorStyles["primary"],
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () async {
setState(() {
autovalidate = !autovalidate;
});
if (_formKey.currentState.validate()) {
List<Licensed> listOfLicenses = new List<Licensed>();
BspSignupCommonModel model = widget.bspSignupCommonModel;
for (var i = 0; i < _myWidgets.length; i++) {
String document = _documentControllers[i].text;
String issuingAuthorityType = _issuingauthoritytype[i].text;
String expiryDate = _expiryDate[i].text;
String issuingAuthority = _issuingauthority[i].text;
// String picture = _identificationpictures[i].text;
print('Document: $document');
print('IssuingAuthorityType: $issuingAuthorityType');
print('ExpiryDate: $expiryDate');
print('IssuingAuthority: $issuingAuthority');
print('Picture: ${_identificationpictures.length}');
print(_myWidgets.length);
Licensed licensed = new Licensed(
bspLicenseNumber: document,
bspAuthority: issuingAuthority,
bspExpiryDate: expiryDate,
bspIssuing: issuingAuthorityType,
);
licensed.bspLicenseNumber = _documentControllers[i].text;
licensed.bspExpiryDate = _expiryDate[i].text;
licensed.bspIssuing = _issuingauthoritytype[i].text;
licensed.bspAuthority = _issuingauthority[i].text;
listOfLicenses.add(licensed);
}
model.unlicensed = listOfLicenses;
print(model.toJson());
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BspLicensedSignupTermsPage(
bspSignupCommonModel: model),
));
}
}),
],
),
);
return new Scaffold(
appBar: appBar,
bottomNavigationBar: bottomNavigationBar,
floatingActionButton: new FloatingActionButton.extended(
onPressed: () {
_add();
},
label: Text(
"Add License",
style: TextStyle(color: Colors.white, fontSize: 16),
),
icon: Icon(
Icons.add,
size: 28,
color: Colors.white,
),
),
body: Container(
height: double.infinity,
width: double.infinity,
child: Form(
autovalidate: autovalidate,
key: _formKey,
child: Stack(
children: <Widget>[
Column(
children: <Widget>[
Expanded(
child: SizedBox(
child: ListView(
padding: const EdgeInsets.all(18.0),
children: _myWidgets,
),
),
),
_buildinformationislegitmate(),
],
)
],
)),
),
);
}
}
The problem seems to be that you are using the same list images for every item, you could try to use a Map that has the lists for each item.
I suggest you to try to create a separate widget with the entire card so it can handle it's own state.