Set the default value for dropdown menu - flutter

How do i set the default value for the drop down menu to ghana amongst a list of countries
const Center(child: CountryDropdown()),
Padding(
padding: AppDimensions.padding.defaultHorizontal(),
child: CountriesListDropdown(
onUpdateNationality: (CountryModel? country) {
kentry = country?.name ?? "Ghana";
},
),
),
SizedBox(height: _size.height * (30 / 812)),
Center(

Give value parameter to dropdown widget like this:
DropdownButton(
underline: Container(),
dropdownColor: themeData.cardColor,
borderRadius: BorderRadius.circular(15),
//give default value here
value: "give you default value here",
items: [],
onChanged: (){}
)

Related

Flutter - PopupMenuButton - add an item manually after adding items from a list

I have a PopupMenuButton which displays items from a List.
List<Subject> subjects = [
Subject(
name: 'English',
iconFile: 'english.jpg',
),
Subject(
name: 'Mathematics',
iconFile: 'maths.jpg',
),
Subject(
name: 'Business Studies',
iconFile: 'business.jpg',
),
];
Below is PopupMenuButton code where the list is used to generate the menu items:
child: PopupMenuButton<Subject>(
color: Color.fromARGB(255, 95, 115, 231),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
onSelected: _changeSubject,
itemBuilder: (BuildContext context) {
return subjects.map((Subject subject) {
return PopupMenuItem<Subject>(
value: subject,
child: Text(subject.name),
);
}).toList();
},
),
This works as intended. Now I want to add another item "Sign Out" below "Business Studies" (as in this image link -> PopupMenuButton) and a divider between them. I don't want to add "Sign Out" to the subjects list. Is it possible to add another PopupMenuItem manually after all the generated items?
`
Subject signOutSubject = Subject(
name: 'Sign Out',
iconFile: 'signOut.jpg',
);
add to the end of the toList() function
toList()..add(PopupMenuItem<Subject>(
value: signOutSubject,
child: Text(signOutSubject.name),
);)
`
You can do like this.
result image
return PopupMenuButton(
color: const Color.fromARGB(255, 95, 115, 231),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
itemBuilder: (context) => <PopupMenuEntry>[
...subjects
.map((s) => PopupMenuItem(value: s, child: Text(s.name)))
.toList(),
const PopupMenuDivider(),
PopupMenuItem(
onTap: () {},
value: "LogOut",
child: const Text('LogOut'),
),
],
);

How to validate a form that has cards to select from and the user should obligatorily select one of them?

I have a code whereby the genders of a pet is listed in two separate cards and when the user taps on one of them, it changes color to indicate that it has been selected and is saved in the database. However, the app is letting the user continue to the next page without choosing any one of the values. I want to do a validation whereby the user will have to choose one of the cards to be able to move forward. How can I do this please?
Here is my code:
Expanded(
child: GridView.count(
crossAxisCount: 2,
primary: false,
scrollDirection: Axis.vertical,
children: List.generate(petGenders.length, (index) {
return GestureDetector(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0)),
color:
selectedIndex == index ? primaryColor : null,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
petGenders[petKeys[index]],
SizedBox(
height: 15.0,
),
Text(
petKeys[index],
style: TextStyle(
color: selectedIndex == index
? Colors.white
: null,
fontSize: 18.0,
fontWeight: FontWeight.w600),
),
],
),
),
),
onTap: () {
setState(() {
widget.pet.gender = petKeys[index];
selectedIndex = index;
});
});
}),
),
),
The model:
Map<String, Image> genders() => {
"Male":
Image(image: AssetImage('Assets/images/male.png'), width: 50),
"Female":
Image(image: AssetImage('Assets/images/female.png'), width: 50)
};
Take one variable
bool isGenderSelected = false;
Then change its value to true on tap of card like
onTap: () {
setState(() {
isGenderSelected = true;
widget.pet.gender = petKeys[index];
selectedIndex = index;
});
});
Now check if it's true then only allow the user to go next page or show some message to the user
Scenario like this, I prefer using nullable selectedValue. In this case, I will create nullable int to hold and switch between selection.
int? selectedIndex;
And using color will be like
color: selectedIndex==index? SelectedColor:null,
you can replace null with inactive color.
For validation part, do null check on selectedIndex .
if(selectedIndex!=null){.....}

New Textfield created appear with previous textfield's value in flutter

I have this Widget to register. Inside I want to ask for 6 inputs to register, but as not too much space on the screen, I splitted in 2 pair of 3. I show three at first in a form and when the user press the continue button I show the other 3. However, when I press the continue button, the new 3 pair of TextField appear with the same value of the previous ones. And they move position a little under. I don't know why it happens since each of those 6 fields is different Widget function.
I created two variables form1 and form2 to hold the different forms
#override
void initState() {
super.initState();
form1 = <Widget>[
firstForm(),
Text("Or Sign Up with social media"),
SizedBox(
height: 20,
),
socialMediaButtons(),
SizedBox(
height: 50,
),
Text("Have an account? Login")
];
form2 = <Widget>[
secondForm(),
Text("Or Sign Up with social media"),
SizedBox(
height: 20,
),
socialMediaButtons(),
SizedBox(
height: 50,
),
Text("Have an account? Login")
];
}
All the text field have the same format as the text field below, I only changed the variable for their respecting field.
Widget firstNameField() {
return TextFormField(
initialValue: "",
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "First Name",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => firstName = val);
},
);
}
I combined the text fields in two widgets (firstForm and secondForm). (Shown firstForm but it is the same format as second, just called the functions for the other widgets).
Widget firstForm() {
return Column(
children: <Widget>[
emailPassField(),
SizedBox(
height: 50,
),
continueButton(),
SizedBox(
height: 50,
),
],
);
}
Then this is the continue button widget which when pressed. show the second form. I change the step variable to 2 to go to the second form.
Widget continueButton() {
return ButtonTheme(
minWidth: 185.0,
height: 48.0,
child: RaisedButton(
color: Colors.black,
textColor: Colors.white,
child: Text("continue"),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
onPressed: () => setState(() => step = 2),
));
}
When the variable step is changed, I created this function (getForm) to be called and to show the correct form array variable for the children of the column.
#override
Widget build(BuildContext context) {
return Material(
child: Expanded(
child: Stack(
children: <Widget>[
// banner with picture
Positioned(
child: banner(),
),
// Login Elements Container
Positioned(
child: Container(
margin: EdgeInsets.only(top: 300.0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 5,
blurRadius: 20,
offset: Offset(0, 0))
],
borderRadius: BorderRadius.only(
topRight: Radius.circular(50),
topLeft: Radius.circular(50))),
child: Center(
child: Column(
children: getForm(step),
),
),
),
)
],
),
),
);
}
//functions for switching forms
getForm(int form) {
if (form == 1) {
return form1;
} else if (form == 2) {
return form2;
}
}
This is how the first step of the form appear.
first form
If I don't enter any data in the text fields and press the continue button, the second form with the correct text fields will appear as shown in this below image. You can see that they have the correct hint text.
second form
However if I enter some data on the first step of the form (seen in second form with data step 1), and then press the continue button, in the second step, the text fields will move down a little bit and the same value entered in the previous text fields will appear in the others too(second form with data step 2). can someone help me please, I don't what's going on there? I hope you understand the code and be able to help me please.
second form with data step 1
second form with data step 2
You need to create a TextEditingController for each TextFormField.
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
...
final _cityController = TextEditingController();
...
// initState
...
// dispose of all TextEditingControllers
#override
void dispose {
_emailController.dispose();
...
_cityController.dispose();
super.dispose();
}
// do this for every TextFormField
Widget firstNameField() {
return TextFormField(
// pass the corresponding controller, no need to set initial value if empty
controller: _firstNameController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "First Name",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => firstName = val);
},
);
}
Use a unique TextEditingcontroller for each textfield...by this way the values won't overlap each others textfield value.

flutter getx show dropdown using Provider, Repository, MVC

I am new to Flutter, Any one share your idea to show dropdown using getx, I tried listing with List Builder. but don't have idea about dropdown using GetX ( MVC, provider, repository).
First declare a variable in your controller
var selectedRole = 'CONTENT_CREATOR'.obs;
then declare this method
void onSelected(String value) {
selectedRole.value = value;
registrationParam.value.roleType = selectedRole.value;
}
finally call from your UI code like this
Padding(
padding: const EdgeInsets.only(right: 8, left: 16),
child: Obx(
() => DropdownButton(
underline: SizedBox(),
isExpanded: true,
hint: Text('Select a role'),
value: _regController.selectedRole.value,
items: [
DropdownMenuItem(
value: "CONTENT_CREATOR",
child: Text("Content Creator")),
DropdownMenuItem(
value: "PR", child: Text("PR Agency")),
DropdownMenuItem(
value: "JOURNALIST",
child: Text("Journalist"))
],
onChanged: (val) {
_regController.onSelected(val);
},
),
)),
**Your initial value must be from a value of DropdownMenuItem

add separate values to DropDownButton

I have a widget with a item builder. In the item builder I want to create Drop down for each item.
For the value property of this DropdownMenuItem i use
SaleRef _selectedRef;
The problem is when I declare this SaleRef _selectedRef; inside the itemBuilder the value does not change after selecting a item.
When I declare it outside this widget but in the class it changes the value of every dropdown
What can I do to select separate values on every drop down ?
This is the code for creating the items
ListView.separated(
itemBuilder: (context, index) {
return Row(
children: <Widget>[
Container(
height: 40,
width: MediaQuery.of(context).size.width * 1 / 5,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.circular(25.0),
border: Border.all(
color: Colors.grey,
style: BorderStyle.solid,
width: 0.80),
),
child: DropdownButton<SaleRef>(
hint: Text(" Select Ref"),
value: _selectedRef,
onChanged: (SaleRef value) {
setState(() {
_selectedRef = value;
print(_selectedRef.refID);
});
},
items: _filteredSaleRef.map((SaleRef ref) {
return DropdownMenuItem<SaleRef>(
value: ref,
child: Row(
children: <Widget>[
Text(
" " + ref.refName,
style: TextStyle(color: Colors.black),
),
],
),
);
}).toList(),
),
),
],
);
},
separatorBuilder: (context, index) {
return Divider(height: 16);
},
itemCount: filteredShopItem.length,
)
When I declare it like this
class _AssignRefPageState extends State<AssignRefPage>
with {
SaleRef _selectedRef;
This happens after selecting a value
When I declare it like this inside the builder like this
itemBuilder: (context, index) {
SaleRef _selectedRef;
return Row(
This is what I get it's always the hint even after I select a one
The problem is you are using the same variable for every dropdownbutton and when you try to declare it in the ListView itemBuilder and you call setState the whole Widget is built setting it to null again
What you can do is create a List of values(the size should be number of dropdownbuttons you have)
Like this
class _AssignRefPageState extends State<AssignRefPage>
with {
List<SaleRef>_selectedRef = List.generate(numberOfDropDowns, (index) => SaleRef());
Then use the array in your setState
DropdownButton<SaleRef>(
hint: Text(" Select Ref"),
value: _selectedRef,
onChanged: (SaleRef value) {
setState(() {
_selectedRef[index] = value;
print(_selectedRef[index].refID); //<- The index is from itemBuilder
});
}
As #Josteve-Adekanbi said the problem was using the same variable
Creating an array with a size outside the class helped me solve my problem
List<SaleRef> _selectedRef = new List(filteredShopItem.length);
Then I used it like this
DropdownButton<SaleRef>(
hint: Text(" Select Ref"),
value: _selectedRef[index],
onChanged: (SaleRef value) {
setState(() {
_selectedRef[index] = value;
print(_selectedRef[index].refID);
});
}