How do I save different Textfield values without creating endless TextEditingController - flutter

I am working on a ToDo app an am trying to create five Text() widgets that hold the value of one TextformField(). I don't want to create lots of controllers, because the user is able to add more ToDo-fields through the press of a button. I always encounter the problem, that all Text() widgets hold the same string. Does anyone have an idea how I could store different strings through one TextEditingController and pass it to different Text() widgets in a compact code?
You can see the concept and problem below.
Thank you for helping me out!

The best solution is to create a widget, which is responsible for one TODO row (contains one Text widget and one TextEditingController). Then, instead of adding a Text widget and a TextEditingController, you can add a new instance of your new widget to the list of fields on the screen.

You can check this code.
TextEditingController test = TextEditingController();
Column(
children: [
TextField(
controller: test,
),
RaisedButton(
child: Text("abc"),
onPressed: () {
setState(() {
test.text = test.text + "abc";
});
},
),
RaisedButton(
child: Text("efg"),
onPressed: () {
setState(() {
test.text = test.text + "efg";
});
},
)
],
)

Related

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.

Is it fine to use .obs on Widgets after assing to var?

Hey am Wondering is it fine to use ".obs" to widget like this :
var name= Text("foo").obs;
return name.value;
using .obs on whole widgets like this:
Rx<Widget> textWidget = Text("test").obs;
will work fine, as you can try in this exmaple:
// ...
child: Obx(
() => controller.textWidget.value,
),
and every time you assign a value to it, it will update, but this will cuase very unecessary recreating of that Text widget, since each time, a new Text widget will set in your UI, which may cause perferemnce issue.
instead you should declare primitive types as Rx observales then assignig them inside your UI widgets:
final textVal = "test".ons;
child: Obx(
() => Text(controller.textVal.value),
),

How to change a state of a widget that is generated from list in flutter

My problem is simple. I was building a ListTile from the list of documents I get from firebase by iterating through the results. The ListTile contains a leading icon, a title, and a trailing favorite IconButton. The list tile shows perfectly as I want it to. But the problem arises when I try to change the color of the IconButton while a user taps on it. For some reason, the code I wrote isn't doing the trick. What i tried to do was to set the value of the IconButton's color by a ternary which uses a class variable named isFavorited. What i wanted it to do is change the color of the IconButton when i tap on that same IconButton. Here is my code block:
// Builds a tile for each brought up names of taxistops
if (retrievedData.isNotEmpty) {
retrievedData.forEach((element) {
if (element.contains(query) ||
element.contains(query.toUpperCase()) ||
element.contains(query.toLowerCase())) {
ListTile listTile = ListTile(
leading: Icon(Icons.local_taxi),
title: Text(element),
trailing: IconButton(
icon: isFavorited
? Icon(
Icons.star,
color: Colors.amber[400],
)
: Icon(Icons.star_border),
onPressed: () => {
setState(() {
isFavorited = true;
}),
addToFavorite()
},
),
onTap: () => close(context, element),
);
searchedTiles.add(listTile);
}
});
}
Any help is appreciated! Thank you in advance!
I think the problem is because you are adding the widget in the list you should preview it directly inside the widget father (ListView) so it can do the setState correctly and not inside a list you created as a data structure to store elements.
I think that's the issue if it still doesn't work I would need to see how you are showing the list.

Add more children to Wrap widget in Dart

I have some Buttons wrapped inside a Card and I need to add more when I have to.
I tried with Wrap.children.add but it doesn't work, no error displayed, nothing changes.
Do you know how I can solve this?
I'm new in Flutter and dart so maybe I'm doing something stupid, I know.
I created a global variable called _MyWrap and my idea is to add Buttons to it when a Button is pressed.
"_getrandomButton" creates a new Button with a text inside(language) and "addRaisedButton" uses that function to create and add buttons to "Wrap" when the button is pressed.
A button that creates other "Buttons" inside a Wrap, this is it.
Code :
Wrap _MyWrap = new Wrap (children: <Widget>[]);
Widget build(BuildContext context) {
.
.
.
child: new Stack(
children: <Widget>[
new ListView(
children: <Widget>[
_addLanguage(),
],
.
.
.
Widget _addLanguage(){
RaisedButton _getrandomButton(String language){
//creates a RaisedButton
}
Future addRaisedButton(String name_) async{
setState(() {
_MyWrap.children.add(_getrandomButton(name_));
});
}
.
.
.
child : RaisedButton(
onPressed: (){
addRaisedButton("English");
},
You should keep a List of names.
And in the build render the names List.
Then setState just add a new name to the list of names.
A new build is triggered and it will take the new list of names.

Jumping to a new page in PageView.builder after the additon of a new page doesn't seem to work as expected [Flutter]

I have a simple layout that consists of a PageView.builder widget that contains several pages. The contents of each page are simple, they contain a Container and a Text widget inside of it.
cards is a List of type String and the Pageview.builder widget has an itemCount that's based on the length of this List. The value of the Text in each page is assigned using this List.
List<String> cards = [];
Now, whenever I add a new value to cards List, a variable newPage is used to store the last index position in the List after that element has been added.
After doing this, setState(() {}); is called so that the UI along with the PageView update to reflect the changes made in the List.
The PageView widget does reflect the changes and a new page does get added to it.
However, the problem arises when I try to jump to newly added page right after calling setState.
The error indicates that the index value that jumpToPage is trying to use is out of range in the PageView
cards.add("New card");
newPage = cards.length - 1;
setState(() {});
card_PageController.jumpToPage(newPage);
So, after trying to figure something out, I added a Timer after the setState, so that the framework get's some time to properly update the UI elements.
I'm using a small value of 50 milliseconds in the Timer function and jumping to the new page after the timer gets over.
cards.add("New card");
newPage = cards.length - 1;
setState(() {});
Timer(Duration(milliseconds: 50), () {
card_PageController.jumpToPage(newPage);
})
The addition of a Timer seems to solve the problem and there were no errors after it's addition. However, I'm not sure if this is the right way of tackling this problem.
I'd like to know as to why is this happening, as shouldn't calling jumpToPage directly after setState work without the use of a Timer?
Also, does setState infact take some time to finish updating the UI, even though it isn't async, and that due to this reason the referenced index is invalid? And could this problem have been tackled in a better way?
From the code you shared I can't detect an issue. Especially because I've reproduced what you said you wanted to achieve and it works without issue. Take a look at the code below:
class PageCards extends StatefulWidget {
#override
_PageCardsState createState() => _PageCardsState();
}
class _PageCardsState extends State<PageCards> {
PageController _pageController = PageController();
List<String> cards = [
'page 0',
'page 1',
'page 2',
];
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: PageView.builder(
controller: _pageController,
itemCount: cards.length,
itemBuilder: (context, index){
return Center(
child: Text(cards[index]),
);
}
),
),
RaisedButton(
child: Text('Add page'),
onPressed: () => addCard(),
),
],
);
}
void addCard(){
setState(() {
cards.add('page ${cards.length}');
});
_pageController.jumpToPage(cards.length - 1);
}
}