Updating dropdown value without rebuild all widget tree Flutter - flutter

this is my first question at StackOverflow, I'm a flutter and dart newbie so I hope to get some help from here.
I'm coding an app that use a TableCalendar to make appointments, I load data in some dates in the calendar using the "events" property, so when I pick any date, if that date has data I load its data in a Dropdown button, I'm using a Stream broadcast() to listen to every time I pick a date so dropdown items change according to the date.
Up to this point I have no problem, the problem is when my dropdown items are ready and I try to pick another value inside the dropdown menu, since the value needs to be updated using OnChanged property, I need to call the setState, but when I do that all the widget tree is rebuilt, and if I don't use the setState obviously the value doesn't change.
I need to update only the dropdown menu item without redrawing all the widget trees keeping the actual state of all the other widgets except the dropdown value and I've been looking from here and there for any solution but I don't find it.
The TableCalendar and the DropdownButton are inside a Listview, the data source is a JSON file, I'm using a Future Builder to build the ListView and a StreamBuilder to build the DropdownButton.
This is the dropdown code:
StreamBuilder(
stream: streamHora.stream,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return DropdownButton<String>(
icon: Icon(Icons.arrow_drop_down),
style: _textStyle(Colors.black, 15.0),
items: [],
onChanged: (value) {},
value: "",
);
}
return DropdownButton<String>(
icon: Icon(Icons.arrow_drop_down),
style: _textStyle(Colors.black, 15.0),
items: snapshot.data,
onChanged: (String value) {
setState(() {
_dropdownHoraValue = value;
});
},
value: _dropdownHoraValue,
);
},
),
Any idea or suggestion will be very appreciated.

Related

hive is giving me empty list upon listening to changes made to an open box

I have a hive box opened in the main.dart and set it to a global variable so am able to access it from all other classes.
Now in one of my classes (settingsView.dart) which is a StatefulWidget am able to put data in the box in the form Map<String,Map<String,dynamic>>. To be specific the Map<String,dynamic> can be a Map<String,String> or Map<String,List>. e.g.
{"1A":{"num_on_roll": "34", "subjects": ["Mathematics","English","Science",...]}}
Now am also retrieving or reading this data and to display it in the UI the "num_on_roll" value in a Text widget and "subjects" value in a Wrap.
NOW THE PROBLEM.
The first ("num_on_roll") is always updated in the UI successfully but the "subjects" values in the Wrap are never updated unless I do hot restart or quit application and start it afresh, by so doing all data will be displayed successfully.
I have tried using ValueListenableBuilder to listen for changes in the box.
"class_constants" is the specific for the stored data which is Map<String,Map<String,dynamic>>.
ValueListenableBuilder(
valueListenable: Hive.box("mainDB").listenable(keys: ["class_constants"]),
builder: (context,Box box,child) {
var clsConst = box.get("class_constants", defaultValue: {});
return Wrap(
children: List.generate(
isPresent
? clsConst[classes[tab]]["subjects"].length
: selectedSubjects.length,
(index) => Text(
"${isPresent ? clsConst[classes[tab]]["subjects"][index] : selectedSubjects[index]}, ",
style: const TextStyle(
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic),
)),
);
}
),
Why is it that the data is store successfully but not displaying some part?
Please help me out.
I found the proper solution myself.
Hive has problem retrieving growable list immediately it has been put in the box. Even you must await it else it can't store!
So trick is to change growable list to non-growable list.
List list = [];
list.add(1);
list.add(2);
list.add(3);
// non-growable
List tempList = List.generate( list.length, (_)=> list[_], growable: false);
mainDB!.put('key',tempList)
;

Can I get a logic/code for highlighting the desired value in the list view builder in flutter

[
Can I get a logic/code for highlighting just the selected value from this list view which is inside a container and it is scrollable also that the axis is set to Horizontal.
I have used a list view builder to align the same and also generated the list of numbers.
Please check the sample image of the widget attached.
Blockquote
]1
It's hard to tell you exactly how to do it without any code examples, and I'm also not sure what you mean by selected. Is that already decided before building the list, or is it decided when the user selects from the list?
If it is already decided, you can pass a value from the parent component that tells the list to highlight a certain value.
If a user is selecting the value to highlight, you can use a combination of setState and onTap with GestureDetector. Here's a potential rough skeleton:
int selectedIndex?;
ListView.builder(
itemCount: litems.length,
itemBuilder: (BuildContext ctx, int index) {
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: Container(
backgroundColor: selectedIndex == index ? highlightedColor : undefined;
child: {{child content}}
),
);
}
)

How do i modify the data of an existing variable in flutter?

I want to make an editable TextWidget in flutter but I don't really know how to go around it, I did some research, but still can't find a good solution.
Here's my sample code below.
I have a variable called
int qty = 1;
and so I called the variable in TextWidget
Column(
children: [
Text(
"${qty}",
style: TextStyle(),
)
],
),
I want to have these features that make user tab on the value to change it if they want, upon tap, a pop-up dialog will show to give the user the ability to change the existing value to whatever the user wants.
Please if anyone knows how, please help.
You will need a statfull widget to call setState and make the UI update with the new value stored in your qty variable. (I'am assuming that you are not using any state managment).
I wrote a possible solution for what you need.
Let look into some considerations:
Text will show whatever is in the qty as long we call setState after (or do it inside) we change the value of qty.
You need some widget to detect your tap. If you want to the text be 'clicable' then it should be wraped inside that widget.
The onTap/onPress call back of that widget should show a new widget. For this you can use the already made showDialog() and pass it a Dialog Widget. in here you will put your ui for that.
In some point of that UI you need to introduce the new value. So you can use a simple TextField that will save the introduced value, where you can assign it to qty, without forgetting to call setState! Note that it deal with strings, so you neet to do an int.parse() ou double.parse accordingly to you qty var type.
And I think that's it.
The could be other ways of doing it. This is a good and simple approach for your need.
I wrote a piece of code to help or somelse how is trying to do it:
InkWell(
// can be gesture detector, button, etc
onTap: () => showDialog(
context: context,
builder: (context) => Dialog(
child: Container(
color:
Colors.white60, // change it accordingly to you
height: 80, // change it accordingly to you
width: 200, // change it accordingly to you
child: Column(
children: [
const Text('Change your value here'),
TextField(
decoration:
InputDecoration(hintText: qty.toString()),
onChanged: (insertValue) => setState(() {
qty = int.parse(insertValue);
}),
// you can use other callBack function (like onComplete,
// onSaved), wich is more eficient than calling setState eveytime,
// but you have to do the needed adtaptions. Like onSave
// needs a key to call the save function. is easy just google it.
),
],
)),
)),
child: Text(
"${qty}",
),
),
What you are probably looking is a DropdownButton.
You would have something like this:
int qty = 1;
List<int> listOfValues = [1,2,3,4];
and then in your column you would have
DropdownButton<int>(
// This are the list of items that will appear in your dropdown menu.
// items is all the options you want your users to be able to select from,
// and it take a list of `DropdownMenuItem`. So instead of creating a `DropdownMenuItem`
// for each of the items in `listOfValues`, we iterate through it and return
// a `DropdownMenuItem`
items: listOfValues
.map((item) => DropdownMenuItem<int>(
value: item,
child: Text('$item'),
))
.toList(),
value: qty,
onChanged: (value) {
if (value != null) {
setState(() {
qty = value;
});
}
},
),
For more information on DropDownButton, check the following links:
https://api.flutter.dev/flutter/material/DropdownButton-class.html
https://www.youtube.com/watch?v=K8Y7sWZ7Q3s
Note: In a scenario where you want to increase the quantity of an item, like in a shopping cart, maybe having a button increment qty by 1 would be better.

Flutter dropdownButton setState on change not updating dropdown text after selection to show selected item

I created a dropdownButton to allow users to select from a dropdown list which will be populated from an API. For now I am populating using a list I created.
Currently the button is displaying the items from my list but after a selection has been made the list doesnt show the selected item and still shows the hint text. What I would like to happen is after a selection has been made then the dropdownButton shows the item that was selected instead of the hint text.
in the onChanged method I added a setState in hopes of updating the _selectedValue variable to the value that was selected and displaying it in the dropdownButton.
I also added a print statement in my setState method and that does trigger and show me the value within the value variable.
Here is my code.
List<DropdownMenuItem<int>> listItems = [DropdownMenuItem(child: Text("2016"), value: 2016,), DropdownMenuItem(child: Text("2021"), value: 2021,)];
int _selectedValue;
body: DropdownButton(
value: _selectedValue,
items: listItems,
hint: Text("Select Year"),
onChanged: (int value){
setState(() {
_selectedValue = value;
print(value);
});
},
),
Your code is fine, but the problem is maybe you are initializing the _selectedValue inside the build() method. So that whenever you call set state the widget rebuilds and initialize again with the default value.
int _selectedValue;
#override
Widget build(BuildContext context) {
return DropdownButton(
value: _selectedValue,
items: listItems,
hint: Text("Select Year"),
onChanged: (int value){
setState(() {
_selectedValue = value;
print(value);
});
},
),
In case anyone else is having this issue, I had the same issue and it was driving me nuts and I was using setState() appropriately etc., It was 100% where I was defining the "initialValue" property.
I was defining it right inside the build method. That did not work, even though I had the same setup in a sister module and it indeed did work. Not sure why that is.
Once I changed the definition of that variable to the state class, it worked like a charm. Hope it saves some, some cycles.

How to change displayed data the best way in Flutter

i want to change displayed data in Flutter? I wrote a function changeDataForTest (only a function for testing the event), which should change the data displayed in Text.
But if I click on this, it isn't changed. The value of the displayed string only changes, if i add (context as Element).reassemble(); after calling the method. Is this the normal way to go, or is there a smoother way to solve my problem?
dynamic changeDataForTest(neuerWert) {
this.data = neuerWert;
}
Column(
children: [
Center(
child: Text(
this.data + this.wiegehts,
),
),
FlatButton(
textColor: Color(0xFF6200EE),
onPressed: () {
changeDataForTest('neuerWert');
(context as Element).reassemble();
},
)
],
)
Thanks
Lukas
If you're using only a small widget, you could use a StatefulWidget using the method:
setState(() {
// change your variable
})
If your widget is complex and has lots of different possible variables, I'll not recommend using setState as this method calls the build method every time is being used.
One simple and fast option, is to use ValueNotifier:
final myVariable = ValueNotifier(false); // where you can replace 'false' with any Object
and then, using it this way:
ValueListenableBuilder(
valueListenable: myVariable,
builder: (context, value, child) {
return Text(value); // or any other use of Widgets
},
);
myVariable.value = true; // if you're looking for to change the current value
finally, if you logic is truly complex and you need to scale, I'll recommend to use a StateManagement library like:
Provider
Riverpod
BloC
Others
You can find those libraries and examples over: https://pub.dev