I am fetching data from firebase's real-time database to show in flutter charts but after function calling the value returned is still null/0. When getDuration() is called the data is shown inside the function but it is not returning. As I am new to Flutter, I don't understand the problem occurring.
If I hard code the values, then it shows on the chart but if I call function then it doesn't display bars.
My database looks like this:
I am fetching duration under the date to show inside the flutter chart on the y-axis with weekdays as the x-axis.
My code for flutter chart:
void initState() {
getSeizureHistory();
//Charts
setState(() {
var data = [
addcharts(sevenDay.substring(0, 2), getDuration(seven),
charts.ColorUtil.fromDartColor(const Color(0xffe8e5af))),
addcharts(sixDay.substring(0, 2), getDuration(six),
charts.ColorUtil.fromDartColor(const Color(0xffe8e5af))),
addcharts(fiveDay.substring(0, 2), getDuration(five),
charts.ColorUtil.fromDartColor(const Color(0xffe8e5af))),
addcharts(fourDay.substring(0, 2), getDuration(four),
charts.ColorUtil.fromDartColor(const Color(0xffe8e5af))),
addcharts(threeDay.substring(0, 2), getDuration(three),
charts.ColorUtil.fromDartColor(const Color(0xffe8e5af))),
addcharts(twoDay.substring(0, 2), getDuration(two),
charts.ColorUtil.fromDartColor(const Color(0xffe8e5af))),
addcharts(oneDay.substring(0, 2), getDuration(one.toString()),
charts.ColorUtil.fromDartColor(const Color(0xffe8e5af))),
];
var series = [
charts.Series(
domainFn: (addcharts addcharts, _) => addcharts.weeks,
measureFn: (addcharts addcharts, _) => addcharts.duration,
colorFn: (addcharts addcharts, _) => addcharts.barColor,
id: 'addcharts',
data: data,
),
];
chartdisplay = charts.BarChart(
series,
animationDuration: Duration(microseconds: 2000),
);
});
}
getDuration() function:
int _duration = 0;
int getDuration(String date) {
//print("Date $date");
//load the data from firebase and add to the list
fb.reference()
..child(cuser.uid)
.child('Seizure_history')
.child(date)
.once()
.then((DataSnapshot snapshot) {
var data = snapshot.value;
list = List();
if (data != null) {
data.forEach((key, value) {
EventList seizure_history = new EventList(
seiz_duration: value['duration'],
dateTime: value['datetime'],
key: key,
);
list.add(seizure_history);
setState(()
{
_duration = int.parse(list[0].seiz_duration);
});
print("Duration $_duration");
return _duration;
});
}
});
}
Inside widget:
Center(
child: Container(
height: size.width * 0.80,
width: size.width * 0.90,
padding: EdgeInsets.all(11.0),
child: Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text(
"Seizure Duration",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 12,
color: const Color(0xff232425),
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
Expanded(
child: chartdisplay,
)
],
),
),
),),
),
addcharts class:
class addcharts {
final String weeks;
final int duration;
final charts.Color barColor;
addcharts(this.weeks, this.duration, this.barColor);
}
On console, it is showing:
But on charts, it is still null:
Related
Why do I keep getting 'Instance of...' when I'm trying to get a String. What's wrong with the function?
Future<string?> counter() async {
Future.delayed(const Duration(seconds: 5), () {
context.watch<FoodCount>().display(widget.food).toString();
return widget.food.quantity.toString();
});
int count = widget.food.quantity;
// print(count);
return count;
}
This is what I'm trying to do:
class FoodQuantity extends StatefulWidget {
final Food food;
FoodQuantity(this.food);
#override
State<FoodQuantity> createState() => _FoodQuantityState();
}
class _FoodQuantityState extends State<FoodQuantity> {
final int amount = 0;
String getCurrency() {
var format = NumberFormat.simpleCurrency(name: 'NGN');
return format.currencySymbol;
}
Future<int> counter() async {
final int result = await Future.delayed(const Duration(seconds: 5), () {
int result = context.read<FoodCount>().display(widget.food);
return result;
});
return result;
}
#override
Widget build(BuildContext context) {
return Container(
width: double.maxFinite,
height: 40,
child: Stack(
children: [
Align(
alignment: const Alignment(-1, 0), //0.3
child: Container(
width: 120,
height: double.maxFinite,
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(30),
),
child: Row(
children: [
const SizedBox(width: 15), //Spacing
Text(
getCurrency(),
style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.bold),
),
Text(
widget.food.price.toString(),
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
)
],
),
),
),
Align(
alignment: const Alignment(1, 0), //0.3
child: Container(
height: double.maxFinite,
width: 120,
decoration: BoxDecoration(
color: Color(0xff453658),
borderRadius: BorderRadius.circular(30),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
if (context.read<Counter>().count != 0) {
context.read<Counter>().decrement();
// widget.food.quantity--;
userOrders.remove(widget.food);
context.read<FoodCount>().decrement(widget.food);
setState(() {});
} else {
context.read()<Counter>();
}
},
child: const Text(
'-',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
),
Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: Text(
counter().toString(),
// context
// .watch<FoodCount>()
// .display(widget.food)
// .toString(),
// widget.food.quantity.toString(),
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
GestureDetector(
onTap: () {
context.read<Counter>().increment();
context.read<FoodCount>().increment(widget.food);
// widget.food.quantity++;
userOrders.add(widget.food);
setState(() {});
},
child: const Text(
'+',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
],
),
);
}
}
I made a provider class FoodCount that monitors the value quantity of object type Food. The async function is supposed to simply return the quantity of the Food provided to it
Provider:
class FoodCount with ChangeNotifier {
int increment(Food food) {
food.quantity++;
int foodCount = food.quantity;
notifyListeners();
return foodCount;
}
int decrement(Food food) {
food.quantity--;
int foodCount = food.quantity;
notifyListeners();
return foodCount;
}
int display(Food food) {
int count = food.quantity;
notifyListeners();
return count;
}
void update() {
notifyListeners();
}
}
Food:
class Food {
String imgUrl;
String desc;
String name;
String waitTime;
num score;
int price;
int quantity;
bool favourited;
List<Map<String, String>> ingredients;
String about;
bool highlight;
Food(this.imgUrl, this.desc, this.name, this.waitTime, this.score, this.price,
this.quantity, this.ingredients, this.about, this.favourited,
{this.highlight = false});
}
Future.delayed is by itself a Future, so you cannot track it without an await to keep the result.
Take a look here, how you can make it, then take care of the difference about a sequential method and a Future method;
Future<String?> counter() async {
// Future.delayed is by itself a future, so you connot track it without an await to get the result
final String result = await Future.delayed(const Duration(seconds: 5), () {
var a = "I'm a Future after 5 seconds" ;
return a;
});
return result;
// Here is not the result you want because this method might be not a Future I think
// int count = widget.food.quantity;
// print(count);
// return count;
}
Or
Future<String?> counter2() async {
return await Future.delayed(const Duration(seconds: 5), () {
var a = "I'm a Future after 5 seconds" ;
return a;
});
// Here is not the result you want because this method might be not a Future I think
// int count = widget.food.quantity;
// print(count);
// return count;
}
When you work with Future and you want to get value from it, you should use await or then()
try to use this code:
await Future.delayed(const Duration(seconds: 5), () {
context.watch<FoodCount>().display(widget.food).toString();
return widget.food.quantity.toString();
});
First off, here's a tip: you're using Future.delayed as a way to get a value after a delay. Try splitting that up into two parts. Instead of
Future.delayed(const Duration(seconds: 5), () {
context.watch<FoodCount>().display(widget.food).toString();
return widget.food.quantity.toString();
});
int count = widget.food.quantity;
Try
await Future.delayed(const Duration(seconds: 5));
context.watch<FoodCount>().display(widget.food.toString());
return widget.food.quantity.toString();
Secondly, the other users are right: when you receive a Future<String>, you can't actually get to the String without awaiting it. Problem is, you can use await in an async function, and build is not async. Conceptually, think of it as "you need to wait 5 seconds for the delay, but your user needs a UI now".
You can solve this using FutureBuilder, which allows you to return some widget until the future finishes.
// In your State class:
late final Future<int> futureCounter; // the future containing your data
#override
void initState() {
// Start your counter now, before the UI loads
futureCounter = counter();
super.initState();
}
// in your build:
Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: FutureBuilder(
future: futureCounter,
builder: (context, snapshot) => Text(
snapshot.hasData ? snapshot.data : "Loading...",
)
style: const TextStyle(fontWeight: FontWeight.bold),
),
);
I tried to fetch data from firestore to chip widgets but then show "LateInitializationError". And also chips should be can multi selection(select many chips). And also how to align 4 chips in a row like this example?I my code I think chips are show like ListView.
error..
I mean like this..
my code..
class uitry extends StatefulWidget {
const uitry({Key? key}) : super(key: key);
#override
State<uitry> createState() => _uitryState();
}
#override
Future<List<Words12>> fetchRecords() async {
var records = await FirebaseFirestore.instance.collection('12words').get();
return mapRecords(records);
}
List<Words12> mapRecords(QuerySnapshot<Map<String, dynamic>> records) {
var _list = records.docs
.map(
(words12) => Words12(
id: words12.id,
wordName: words12['wordName'],
categoryName: words12['categoryName'],
),
)
.toList();
return _list;
}
late int defaultChoiceIndex;
#override
void initState() {
initState();
defaultChoiceIndex = 0;
}
child: SizedBox(
width: width * 0.94,
height: height * 0.30,
child: FutureBuilder<List<Words12>>(
future: fetchRecords(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<Words12> data = snapshot.data ?? [];
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return (ChoiceChip(
label: Text(data[index].wordName),
selected: defaultChoiceIndex == index,
selectedColor: Colors.deepPurple,
onSelected: (value) {
setState(() {
defaultChoiceIndex =
value ? index : defaultChoiceIndex;
});
},
// backgroundColor: color,
elevation: 1,
padding: const EdgeInsets.symmetric(
horizontal: 5.0),
));
},
);
}
}),
),
#override
void initState() {
initState();
defaultChoiceIndex = 0;
}
Should be:
#override
void initState() {
super.initState();
defaultChoiceIndex = 0;
}
I believe it will initialize your defaultChoiceIndex then.
For the alignment of chips: Wrap your ChoiceChip in the ListView.builder in a Row(), with a mainAxisAlignment of your choosing:
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ChoiceChip(etc.),
],
),
I tried it .Now it working..
code
SizedBox(
width: width * 0.94,
height: height * 0.30,
child: Column(
children: <Widget>[
const SizedBox(height: 16),
Wrap(
children: hobbyList.map(
(hobby) {
bool isSelected = false;
if (selectedHobby!.contains(hobby)) {
isSelected = true;
}
return GestureDetector(
onTap: () {
if (!selectedHobby!.contains(hobby)) {
if (selectedHobby!.length < 50) {
selectedHobby!.add(hobby);
setState(() {});
print(selectedHobby);
}
} else {
selectedHobby!.removeWhere(
(element) => element == hobby);
setState(() {});
print(selectedHobby);
}
},
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 5, vertical: 4),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 5, horizontal: 12),
decoration: BoxDecoration(
color: isSelected
? HexColor('#F5F185')
: HexColor('#D9D9D9'),
borderRadius:
BorderRadius.circular(18),
border: Border.all(
color: isSelected
? HexColor('#F5F185')
: HexColor('#D9D9D9'),
width: 2)),
child: Text(
hobby,
style: TextStyle(
color: isSelected
? Colors.black
: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w600),
),
),
),
);
},
).toList(),
),
],
),
),
class _uitryState extends State<uitry> {
List<String> hobbyList = [
'Shopping',
'Brunch',
'Music',
'Road Trips',
'Tea',
'Trivia',
'Comedy',
'Clubbing',
'Drinking',
'Wine',
];
List<String>? selectedHobby = [];
I have a widget on a screen that receives its data from API calls. The API call is made inside the init method of the Navigation Bar so that continuous API calls can be prevented when going back and forth between screens. Although this works fine, I'm facing a real challenge in trying to get the state of the widget updated when new data is added to that particular API that the widget relies on for displaying data. I would therefore need to know how to display the updated data that I added to the Database by making a post request on a different screen. The only way this happens now is by way of reloading the entire app or by killing it. Any help will be appreciated.
This is the NavBar where the API is getting called. I usually make all the API calls at once here and something I have done here too.
NavBar
class CustomBottomNavigationState extends State<CustomBottomNavigation> {
bool isLoading = true;
int index = 2;
final screens = [
MenuScreen(),
LeaveScreen(),
// TaskList(),
HomeScreen(),
// PaySlipScreen(),
TaskList(),
Claimz_category(),
// ClaimzScreen()
];
#override
void initState() {
// TODO: implement initState
Provider.of<LeaveRequestViewModel>(context, listen: false)
.getLeaveRequest()
.then((value) {
Provider.of<AnnouncementViewModel>(context, listen: false)
.getAllAnouncements()
.then((value) {
Provider.of<TodaysTaskList>(context, listen: false)
.getTodaysTasks() //This is the API call in question
.then((value) {
setState(() {
isLoading = false;
});
});
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
final items = ['The icons are stored here'];
// TODO: implement build
return SafeArea(
child: Scaffold(
body: isLoading
? const Center(
child: CircularProgressIndicator(),
)
: screens[index],
extendBody: true,
bottomNavigationBar: Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(200),
topRight: Radius.circular(200)),
boxShadow: [
BoxShadow(
color: Colors.transparent,
blurRadius: 10,
offset: Offset(1, 2))
]),
child: CurvedNavigationBar(
items: items,
index: index,
height: 60,
color: const Color.fromARGB(255, 70, 70, 70),
backgroundColor: Colors.transparent,
onTap: (index) => setState(() {
this.index = index;
})),
),
),
);
}
}
ToDoList widget(This the widget where the updates never reflect without reloading)
class ToDoListState extends State<ToDoList> {
#override
Widget build(BuildContext context) {
final toDoList = Provider.of<TodaysTaskList>(context).getToDoList; //This is the getter method that stores the data after it has been fetched from API
// TODO: implement build
return ContainerStyle(
height: SizeVariables.getHeight(context) * 0.35,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(
top: SizeVariables.getHeight(context) * 0.015,
left: SizeVariables.getWidth(context) * 0.04),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
// color: Colors.red,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
'To do list',
style: Theme.of(context).textTheme.caption,
),
),
),
],
),
),
SizedBox(height: SizeVariables.getHeight(context) * 0.01),
Padding(
padding: EdgeInsets.only(
left: SizeVariables.getWidth(context) * 0.04,
top: SizeVariables.getHeight(context) * 0.005,
right: SizeVariables.getWidth(context) * 0.04),
child: SizedBox(
height: SizeVariables.getHeight(context) * 0.25,
child: Container(
// color: Colors.red,
child: toDoList['today'].isEmpty
? Center(
child: Lottie.asset('assets/json/ToDo.json'),
)
: ListView.separated(
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => Row(
children: [
Icon(Icons.circle,
color: Colors.white,
size:
SizeVariables.getWidth(context) * 0.03),
SizedBox(
width:
SizeVariables.getWidth(context) * 0.02),
FittedBox(
fit: BoxFit.contain,
child: Text(
toDoList['today'][index]['task_name'], //This is where it is used
overflow: TextOverflow.ellipsis,
style: Theme.of(context)
.textTheme
.bodyText1),
)
],
),
separatorBuilder: (context, index) => Divider(
height: SizeVariables.getHeight(context) * 0.045,
color: Colors.white,
thickness: 0.5,
),
itemCount: toDoList['today'].length > 4
? 4
: toDoList['today'].length),
),
),
)
],
),
);
}
}
The other widget where the date gets added
class _TaskListState extends State<TaskList> {
#override
Widget build(BuildContext context) {
var floatingActionButton;
return Scaffold(
backgroundColor: Colors.black,
floatingActionButton: Container(
....
....,
child: FloatingActionButton(
backgroundColor: Color.fromARGB(255, 70, 69, 69),
onPressed: openDialog, //This is the method for posting data
child: Icon(Icons.add),
),
),
),
body: Container(
....
....
....
),
);
}
Future<dynamic> openDialog() => showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor: Color.fromARGB(255, 87, 83, 83),
content: Form(
key: _key,
child: TextFormField(
controller: taskController,
maxLines: 5,
style: Theme.of(context).textTheme.bodyText1,
decoration: InputDecoration(
border: InputBorder.none,
),
validator: (value) {
if (value!.isEmpty || value == '') {
return 'Please Enter Task';
} else {
input = value;
}
},
),
),
actions: [
InkWell(
onTap: () async {
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate:
DateTime.now().add(const Duration(days: 365)))
.then((date) {
setState(() {
_dateTime = date;
});
print('Date Time: ${dateFormat.format(_dateTime!)}');
});
},
child: const Icon(Icons.calendar_month, color: Colors.white)),
TextButton(
child: Text(
"Add",
style: Theme.of(context).textTheme.bodyText1,
),
onPressed: () async {
Map<String, dynamic> _data = {
'task': taskController.text,
'task_date': dateFormat.format(_dateTime!).toString()
};
print(_data);
if (_key.currentState!.validate()) {
await Provider.of<ToDoViewModel>(context, listen: false)
.addToDo(_data, context) //This is the post method
.then((_) {
Navigator.of(context).pop();
Provider.of<TodaysTaskList>(context, listen: false)
.getTodaysTasks(); //I did this here again to re-initialize the data. I was under the impression that the new data would get initialized for the widget to reflect it on the other screen.
});
}
},
),
],
),
);
void add() {
Navigator.of(context).pop();
}
}
The Get API Call
class TodaysTaskList with ChangeNotifier {
Map<String, dynamic> _getToDoList = {};
Map<String, dynamic> get getToDoList {
return {..._getToDoList};
}
Future<void> getTodaysTasks() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var response = await http.get(Uri.parse(AppUrl.toDoList), headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ${localStorage.getString('token')}'
});
if (response.statusCode == 200) {
_getToDoList = json.decode(response.body);
} else {
_getToDoList = {};
}
print('TO DO LIST: $_getToDoList');
notifyListeners();
}
}
Please let me know for additional input.
i think it's because you didn't call the provider to update your state correctly
as i see that you declare new variable to store your provider like this
final toDoList = Provider.of<TodaysTaskList>(context).getToDoList;
then you use it like this
Text(
toDoList['today'][index]['task_name'], //This is where it is used
overflow: TextOverflow.ellipsis,
style: Theme.of(context)
.textTheme
.bodyText1),
)
it's not updating the state, you should wrap the widget that need to be updated with Consumer
Consumer<TodaysTaskList>(
builder: (context, data, child) {
return _Text(
data.[your_list]['today'][index]['task_name'],
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyText1),
);
},
);
I have a simple list and I am filter the list by date range picker. All is working fine its showing result also that list is filter success but on ListView builer its showing this error.
Class 'WhereIterable<Object>' has no instance method '[]'.
My code
Future<List> getCustomerList() async {
print(widget.data);
// print('check running');
final storage = new FlutterSecureStorage();
String uUid = await storage.read(key: "uUid");
CollectionReference _collectionRef =
FirebaseFirestore.instance.collection('Transaction');
QuerySnapshot querySnapshot = await _collectionRef.get();
// Get data from docs and convert map to List
List allData = querySnapshot.docs
.where((element) => element['CustomerID'] == widget.data['customerID'])
.map((doc) => doc.data())
.toList();
print(allData);
restore = allData;
backrestore = allData;
setState(() {
show = true;
});
}
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () async {
final List<DateTime> picked =
await DateRangePicker.showDatePicker(
context: context,
initialFirstDate: new DateTime.now(),
initialLastDate: (new DateTime.now())
.add(new Duration(days: 6)),
firstDate: new DateTime(2015),
lastDate:
new DateTime(DateTime.now().year + 2));
if (picked != null && picked.length == 2) {
print(picked);
selectedDate = picked[0];
DateTime endDate = picked[1];
List<DateTime> days = [];
var filterData = backrestore;
DateTime date = DateTime.parse(
filterData[0]['lastupdate'].toDate().toString());
print(date);
for (int i = 0;
i <= endDate.difference(selectedDate).inDays;
i++) {
days.add(selectedDate.add(Duration(days: i)));
}
print(days);
final filteredItemsToAdd = filterData.where((item) =>
days.contains(DateTime.parse(
item['lastupdate'].toDate().toString())));
print(filteredItemsToAdd.length);
print(filteredItemsToAdd);
setState(() {
restore = filteredItemsToAdd;
});
}
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xffE5E7E9)
),child: Padding(
padding: const EdgeInsets.all(13.0),
child: Text('Date'),
))),
),
Container(
height: Height * 0.5,
child: ListView.builder(
shrinkWrap: true,
itemCount: restore.length,
itemBuilder: (BuildContext context, int index) {
DateTime date = DateTime.parse(
restore[index]['lastupdate'].toDate().toString());
// print(DateFormat('dd-MMM-yyy').format(date)); // prints 2019-04-16
// print('List length ${snapshot.data.length}');
return Padding(
padding: const EdgeInsets.only(left: 13, right: 13),
child: Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Colors.grey, width: .5)),
),
child: Padding(
padding: const EdgeInsets.all(13.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
DateFormat('dd MMM yyy').format(date).toString(),
style: TextStyle(fontFamily: 'PoppinsMedium'),
),
Row(
children: [
Text(
restore[index]['give'].toString(),
style: TextStyle(
fontFamily: 'PoppinsMedium',
color: Colors.green),
),
SizedBox(
width: 60,
),
Text(
restore[index]['take'].toString(),
style: TextStyle(
fontFamily: 'PoppinsMedium',
color: Colors.red),
),
],
)
],
),
),
),
);
},
),
),
You can see I am fetching list then saving on object. And on DateRange picker I am changing the new value by setState but dont know why its showing this error.
I believe this code causes the problem
List allData = querySnapshot.docs
.where((element) => element['CustomerID'] == widget.data['customerID'])
.map((doc) => doc.data())
.toList();
element has type QueryDocumentSnapshot. Replace element['CustomerID'] by element.data()['customID'].
What I am trying to achieve is to update change from another widget after looking after these posts Trigger a function from a widget to a State object, How to set state from another widget?, How to force Flutter to rebuild / redraw all widgets?.I tried all these solutions but because of my tree its did not worked and after many reflections
I am thinking of ValueListenableBuilder using to pass the State from child to child, child to parent, and parent to the child I want to update because InheritedWidget seems to don't fit my need more over the widget will be constantly change and I think my tree make things difficult to use Stream to achieve what I want.I don't know if it's the best way to do that passing the State from child to child, child to parent, and parent to the child I want to update .this is my tree and what I am trying to achieve
The ScrollableExhibitionSheet class is a StatefulWidget;
this is the code of the Raisedbutton inside the cardcontent:
Transform.translate(
offset: Offset(48 * widget.offset, 0),
child: RaisedButton(
color: Colors.green, //Color(0xFF162A49),
child: Transform.translate(
offset: Offset(24 * widget.offset, 0),
child: Text('Reserve'),
),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
onPressed: ()async {
SharedPreferences preferences = await SharedPreferences.getInstance();
String stringValue = preferences.getString('token');
print("Token $stringValue");
Dio dio = Dio(
BaseOptions(
baseUrl:base,
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Token $stringValue',
},
));
response4 = await dio.post(
"/orders/",
data: {
"product":widget.id,
"paiment_status": false,
"timing_paiement": false,
"reserve_status": true,
"description": "",
"price":widget.price,
"number":_counter,
"relaypoint":1
});
setState(() {
print(response4.statusCode);
//ScrollableExhibitionSheet();
});
if(_counter !=0){
if(response4.statusCode == 200 || response4.statusCode == 201){
Flushbar(
flushbarPosition: FlushbarPosition.TOP,
title: "XXXXXXXXXX",
message:"${widget.name} X${_counter}",
duration: Duration(seconds: 3)
)
..show(context);
}
setState(()async{
_counter =0;
print(response4.statusCode);
getDataFromUi();
//prices(_counter,widget.price);
//sum = sum + (_counter *widget.price);
});
}else{
Flushbar(
flushbarPosition: FlushbarPosition.TOP,
title: "XXXXXXXXX",
message:"xxxxxxxxxxxxxxxx",
duration: Duration(seconds: 3)
)
..show(context);
}
//ApiData.add_orders(context,widget.id,widget.price,widget.name,_counter);
},
),
),
and this is the code of the cardcontent class:
class CardContent extends StatefulWidget {
final int id;
final String name;
final String date;
final int price;
final double offset;
Function callback;
CardContent(
{Key key,
this.callback,
#required this.id,
#required this.name,
#required this.date,
#required this.price,
#required this.offset})
: super(key: key);
#override
_CardContentState createState() => _CardContentState();
}
class _CardContentState extends State<CardContent> {
num _counter = 0;
num _defaultValue = 0;
Response response4;
//Count2Bloc count1Bloc;
final number = new ValueNotifier(0);
getDataFromUi() async {
await ApiData.getDataorders();
}
#override
Widget build(BuildContext context) {
void add() {
setState(() {
_counter++;
});
}
//bool loading = false;
void minus() {
setState(() {
if (_counter != 0)
_counter--;
});
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Transform.translate(
offset: Offset(8 * widget.offset, 0),
child: Text(widget.name, style: TextStyle(fontSize: 20),
overflow: TextOverflow.ellipsis,
maxLines:1,
),
),
SizedBox(height: 6),
Transform.translate(
offset: Offset(32 * widget.offset, 0),
child: Text(
widget.date,
style: TextStyle(color: Colors.grey,fontSize: 12),
overflow: TextOverflow.ellipsis,
maxLines:1,
),
),
Spacer(),
new Row(
mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Transform.translate(
offset: Offset(32 * widget.offset, 0),
child:GestureDetector(
onTap: minus,
child: new Icon(
const IconData(0xe15b, fontFamily: 'MaterialIcons'),
color: Colors.black,size: 30,),
),
),
SizedBox(width: 5,),
Transform.translate(
offset: Offset(32 * widget.offset, 0),
child:new Text('$_counter',
style: new TextStyle(fontSize: 14.0)
),
),
SizedBox(width: 5,),
Transform.translate(
offset: Offset(32 * widget.offset, 0),
child:GestureDetector(
onTap: add,
child: new Icon(Icons.add, color: Colors.black,size: 30)
),
),
SizedBox(width: 16,)
],
),
Spacer(),
Row(
children: <Widget>[
Transform.translate(
offset: Offset(48 * widget.offset, 0),
child: RaisedButton(
color: Colors.green, //Color(0xFF162A49),
child: Transform.translate(
offset: Offset(24 * widget.offset, 0),
child: Text('Reserve'),
),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
onPressed: ()async {
SharedPreferences preferences = await SharedPreferences.getInstance();
String stringValue = preferences.getString('token');
print("Token $stringValue");
Dio dio = Dio(
BaseOptions(
baseUrl:base, //"http://digixpress.herokuapp.com/api/",
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Token $stringValue',
},
));
response4 = await dio.post(
"/orders/",
data: {
"product":widget.id,
"paiment_status": false,
"timing_paiement": false,
"reserve_status": true,
"description": "",
"price":widget.price,
"number":_counter,
"relaypoint":1
});
setState(() {
print(response4.statusCode);
//ScrollableExhibitionSheet();
});
if(_counter !=0){
if(response4.statusCode == 200 || response4.statusCode == 201){
Flushbar(
flushbarPosition: FlushbarPosition.TOP,
title: "Panier",
message:"${widget.name} X${_counter}",
duration: Duration(seconds: 3)
)
..show(context);
}
setState(()async{
_counter =0;
print(response4.statusCode);
getDataFromUi();
//prices(_counter,widget.price);
//sum = sum + (_counter *widget.price);
});
}else{
Flushbar(
flushbarPosition: FlushbarPosition.TOP,
title: "Aucune commande",
message:"renseignez le nombre de plats/boissons",
duration: Duration(seconds: 3)
)
..show(context);
}
//ApiData.add_orders(context,widget.id,widget.price,widget.name,_counter);
},
),
),
Spacer(),
Transform.translate(
offset: Offset(32 * widget.offset, 0),
child: Text(
'${widget.price} Fcfa',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
),
SizedBox(width:16),
],
)
],
),
);
}
}