Show value of dropdown with empty value at the beginning - flutter

I would like that in my dropdown at the beginning no value is entered. only if I select the value it should be displayed in the dropdown. if I comment out "value: _selected" is not filled but after the onChanged also nothing is filled.
FormField<Device>(
initialValue: _selected,
builder: (field) {
return InputDecorator(
decoration: InputDecoration(
labelText: widget.labelText,
border: const OutlineInputBorder(),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<Device>(
value: _selected,
isDense: true,
isExpanded: true,
items: widget.list
.map<DropdownMenuItem<Device>>((Device value) {
return DropdownMenuItem<Device>(
value: value,
child:
Text('${value.inventarnr} - ID: ${value.id}'),
);
}).toList(),
onChanged: (value) {
setState(() {
_selected = value;
});
},
),
),
);
},
),

Below worked example for your reference.
initializing default dropdown value
String phaseInitialValue = "Select dropdown";
declare a class to get the user selected value from dropdown.
I have using temporary json data...
List<Phase> phaseList = phaseJsonList.phaseList;
Phase phase = Phase("","");
FormField full code :
FormField(
initialValue: phaseInitialValue,
builder: (field) {
return InputDecorator(
decoration: const InputDecoration(
labelText: "Dropdown",
border: OutlineInputBorder(),
),
child: DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text(
phaseInitialValue,
style: const TextStyle(
fontWeight: FontWeight.w400,
color: Color.fromRGBO(179, 179, 179, 1.0),
fontSize: 15.0,
fontStyle: FontStyle.normal
),
),
isExpanded: true,
iconSize: 30.0,
iconEnabledColor:
const Color.fromRGBO(0, 0, 0, 1.0),
style: const TextStyle(
color: Color.fromRGBO(0, 0, 0, 1)),
dropdownColor:
const Color.fromRGBO(255, 255, 255, 1.0),
borderRadius: BorderRadius.circular(5),
items: phaseList.map(
(phaseData) {
return DropdownMenuItem<Phase>(
value: phaseData,
child: Text(phaseData.phaseName),
);
},
).toList(),
onChanged: (Phase? newData) {
setState(() {
phase = newData!;
phaseInitialValue = newData.phaseName!;
},
);
},
),
),
);
},
),
if user changed the value from dropdown i have retrieve that from onChanged property. there i changed inital text to user selected object...
you can able to fetch actual id as well as object...
have a good day!!!

Related

How to avoid filling the same value in these 2 form fields in flutter

UI
I want to build a form that is used to fill in the departure station and destination station. But I haven't implemented a way to prevent the user from filling in the same value in the 2 fields. And this is my code
Form(
key: _formKey,
child: Column(
children: [
// Stasiun Keberangkatan Form
DropdownSearch<String>(
validator: (value) {
if (value == null) {
return 'please input station';
}
return null;
},
popupProps: const PopupProps.menu(
showSelectedItems: true,
showSearchBox: true,
),
items: stationsToStName(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
filled: true,
fillColor: const Color.fromRGBO(37, 37, 37, 0.1),
//hintText: "Stasiun keberangkatan",
hintText: "Departure Station",
hintStyle:
const TextStyle(fontFamily: 'Inter', fontSize: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(
width: 0,
style: BorderStyle.none,
),
),
prefixIcon: const Padding(
padding: EdgeInsets.all(8.0),
child: Image(
height: 33,
image: AssetImage(
'assets/images/icon_departureSt.png'),
),
),
),
),
onChanged: (newvalue) {
setState(() {
stKeberangkatan = newvalue!; //updated
});
},
),
const SizedBox(height: 11),
// Destination Form
DropdownSearch<String>(
validator: (value) {
if (value == null) {
return 'please input station';
}
return null;
},
popupProps: const PopupProps.menu(
showSelectedItems: true,
showSearchBox: true,
),
items: stationsToStName(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
filled: true,
fillColor: const Color.fromRGBO(37, 37, 37, 0.1),
//hintText: "Stasiun tujuan",
hintText: "Destination Station",
hintStyle:
const TextStyle(fontFamily: 'Inter', fontSize: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(
width: 0,
style: BorderStyle.none,
),
),
hintMaxLines: 2,
prefixIcon: const Padding(
padding: EdgeInsets.all(11.0),
child: Image(
height: 33,
image: AssetImage(
'assets/images/icon_destinationSt.png'),
),
),
),
),
onChanged: (newvalue) {
setState(() {
stTujuan = newvalue!; //updated
});
},
),
const SizedBox(height: 35),
// "Submit" Button
SizedBox(
width: size.width,
height: 48,
child: ElevatedButton(
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all<Color>(Colors.white),
backgroundColor:
MaterialStateProperty.all<Color>(primColor),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
side: const BorderSide(color: primColor)))),
onPressed: () {
if (_formKey.currentState != null &&
_formKey.currentState!.validate()) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BestRoute(
stKeberangkatan: stKeberangkatan,
stTujuan: stTujuan,
)),
);
}
},
child: const Text("Submit",
style: TextStyle(
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
fontSize: 14))),
),
],
),
),
I want to apply alert or validator if user fill in same value when click submit button
For example, the user fills in station A for departure station and destination station. And I want to avoid that. and I want to apply alert or validator if user fill in same value when click submit button
How can I implement that?
You can create two variables, one called departure and the other called destination. Then when the user selects a value from the dropdown, use setState((){}) to put the value in the variables.
Finally, when the user clicks on submit button, check if the value of destination and departure are different and only then allow the user to proceed.

How to use ValueListenableBuilder and the ValueNotifier on my radio button so when the radio Button is checked,it displays the formfield

So i wrapped my formfield in a visble widget to hide and display the textformfield when the radio button is checked but i works fine but the you somethime have to double click it is want to use ValueListenableBuilder and the ValueNotifier to also archive this.
Visibility(
visible: _isVisible,
child: Container(
width: 396,
height: 73,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Color(0xff000000).withOpacity(0.08),
offset: Offset(0, 2),
blurRadius: 6,
),
],
color: Color(0xffFAFAFA),
borderRadius: BorderRadius.circular(17)),
child: Padding(
padding: const EdgeInsets.fromLTRB(15, 25, 0, 0),
child: TextFormField(
enabled: _character == SingingCharacter.unchecked
? true
: false,
onSaved: (Value) => print(hello),
decoration: InputDecoration(
hintStyle: TextStyle(
fontFamily: "Proxima Nova",
fontWeight: FontWeight.w300,
),
border: InputBorder.none,
labelStyle: TextStyle(
color: Color(0xffFAFAFA),
),
),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r"[0-9]+|\s"))
],
controller: kiloMeter,
validator: (value) {
if (value != null && value.isEmpty || value != 1000) {
return 'Please enter your Kilometer';
}
return null;
},
),
),
),
),
Create a valueNotifer with bool like
final ValueNotifier<bool> _visiBilityNotifier = ValueNotifier(false);
And usecase will be
ValueListenableBuilder<bool>(
valueListenable: _visiBilityNotifier,
builder: (context, value, child) {
return value ? Text("VisibleWidgget") : const SizedBox.shrink();
},
)
To update the value use
_visiBilityNotifier.value = yourNewValue; //true or false
You can direct value(wont refresh UI)
_visiBilityNotifier.value

Conditional statement for DropdownButtonFormFields in registeration form

Still a newbie with flutter and was wondering if someone could help me with a problem I'm having. I am trying to create a registeration form with email, password, password confirmation, a county and a zip code. (County and zip code forms are the drop down button form fields) I have successfully coded all else except for the zip code drop down. I would need it to be conditional on the county selection. (In a way that if I select a specific county in cali, it would only display that selected county's zip codes and nothing else). Also if someone would know a quick fix to make the dropdown button form fields empty unless clicked on. My current adaptation on it isn't very functional, since you can just leave the option unanswered, when it's supposed to be mandatory. Thank you in advance :)
Existing code below
(I only have the string for one county zip codes) (Also deleted the irrelevant firebase related code for this post)
class RegisterPage extends StatefulWidget {
const RegisterPage({Key? key}) : super(key: key);
#override
State<RegisterPage> createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
// dropdown area
_MyFormStateArea(){
selectedArea = dropdownListArea[0];
}
var selectedArea = '';
final dropdownListArea = <String>['', 'LA', 'San Francisco'...'Santa Barbara'];
// dropdown zipcode
_MyFormStateZip(){
selectedZip = dropdownListZip[0];
}
var selectedZip = '';
final dropdownListZip = <String>['', '90001', '90002', '90003',..., '91609'];
// editing Controller
final emailEditingController = new TextEditingController();
final passwordEditingController = new TextEditingController();
final confirmPasswordEditingController = new TextEditingController();
#override
Widget build(BuildContext context) {
// email field
final emailField = TextFormField(
autofocus: false,
controller: emailEditingController,
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value!.isEmpty) {
return ("Please enter email.");
}
// reg expression for email validation
if (!RegExp("^[a-zA-Z0-9+_.-]+#[a-zA-Z0-9.-]+.[a-z]")
.hasMatch(value)) {
return ("Please enter a working email.");
}
return null;
},
onSaved: (value) {
emailEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.mail_outline_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Email",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
);
// password field
final passwordField = TextFormField(
autofocus: false,
controller: passwordEditingController,
obscureText: true,
validator: (value) {
RegExp regex = new RegExp(r'^.{6,}$');
if (value!.isEmpty) {
return ("A password required.");
}
if(!regex.hasMatch(value)) {
return ("Please enter other password (Min. 6 characters)");
}
},
onSaved: (value) {
passwordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
));
// confirm password field
final confirmPasswordField = TextFormField(
autofocus: false,
controller: confirmPasswordEditingController,
obscureText: true,
validator: (value)
{
if(confirmPasswordEditingController.text != passwordEditingController.text)
{
return "Passwords don't match";
}
return null;
},
onSaved: (value) {
confirmPasswordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password again",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
);
// area dropdown
final areaField = DropdownButtonFormField(
value: selectedArea,
items: dropdownListArea.map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedArea = value;
}
});
},
decoration: InputDecoration(
labelText: 'County',
prefixIcon: Icon(Icons.location_city_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// zip code field
final zipCodeField = DropdownButtonFormField(
value: selectedZip,
items: dropdownListZip.map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedZip = value;
}
});
},
decoration: InputDecoration(
labelText: 'Zip Code',
prefixIcon: Icon(Icons.location_on_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// sign up button
final signUpButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(30),
color: Colors.white,
child: MaterialButton(
padding: EdgeInsets.fromLTRB(20, 15, 20, 15),
minWidth: MediaQuery.of(context).size.width,
onPressed: () {
signUp(emailEditingController.text, passwordEditingController.text);
},
child: Text("Sign Up", textAlign: TextAlign.center,
style: TextStyle(fontSize: 20,
color: Colors.lightBlue[900],
fontWeight: FontWeight.bold)
),
),
);
return Scaffold(
backgroundColor: Color(0xFFAED8E6),
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => FrontPage()));
},
icon: Icon(Icons.arrow_back),
color: Colors.lightBlue[900],
),
),
body: Center(
child: SingleChildScrollView(
child: Container(
color: Color(0xFFAED8E6),
child: Padding(
padding: const EdgeInsets.fromLTRB(36, 20, 36, 30),
child: Form(
key: _formKey,
child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 170,
child: Image.asset("assets/AR_logoBold.png",
fit: BoxFit.contain
)),
SizedBox(height: 40,),
emailField,
SizedBox(height: 25,),
passwordField,
SizedBox(height: 25,),
confirmPasswordField,
SizedBox(height: 25,),
areaField,
SizedBox(height: 25,),
zipCodeField,
SizedBox(height: 35,),
signUpButton,
SizedBox(height: 15,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("You already own an account? "),
GestureDetector(onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage()));
},
child: Text("Login",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Colors.lightBlue[900])
),)
],
)
],
)),
),
),
),
),
);
}
}
First you should initalize the selectedArea and selectedZip with the first Entry of your List: = dropdownListZip.first and the first entry should not be an empty String
To get only zips that belong to the choosen area you need to know them. At the moment you have two independent lists.
Better you use a map like:
Map<String, List<String>> zipmap = Map('LA': ['9000','9001','9002], 'San Francisco': ['9003', '9004']);
Than you can only display zips that belong to the area quite easy.
Take a look at: Flutter Documentation for Map
Map<String, List<String>> zipmap = Map('LA': ['9000','9001','9002], 'San Francisco': ['9003', '9004']);
final areaField = DropdownButtonFormField(
value: selectedArea,
items: zipmap.keys.toList().map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedArea = value;
}
});
},
decoration: InputDecoration(
labelText: 'County',
prefixIcon: Icon(Icons.location_city_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// zip code field
final zipCodeField = DropdownButtonFormField(
value: selectedZip,
items: zipmap[selectedArea].map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedZip = value;
}
});
},
decoration: InputDecoration(
labelText: 'Zip Code',
prefixIcon: Icon(Icons.location_on_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);

How to set initial default value in drop down flutter

I've one drop down and there some value inside the drop-down button and I need to by default selected value. you can seel below piece of snippet where you can find the drop-down value. I need it always there is by default selected value Normal. hope you understand the question.
FormBuilder(
autovalidate: autovalidate,
child: FormBuilderCustomField(
attribute: "Select Address",
validators: [
FormBuilderValidators.required(),
],
formField: FormField(
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
errorText: field.errorText,
filled: false,
isDense: true,
border: InputBorder.none,
icon: Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: colorStyles['primary_light'],
),
child: Icon(
Icons.business_center,
color: colorStyles['primary'],
),
),
),
isEmpty: _typeValue == [],
child: new DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text("Service Type"),
isExpanded: true,
items: [
"normal",
"urgent",
"emergency",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),
value: field.value,
onChanged: (value) {
field.didChange(value);
_serviceType = value;
},
),
),
);
},
)),
);
Just Asign on initState()
selectedDropDownValue = "normal";
In DropDown, asign selectedDropDownValue to value, and update on onChanged callback
new DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text("Service Type"),
isExpanded: true,
items: [
"normal",
"urgent",
"emergency",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),
value: selectedDropDownValue, //asign the selected value
onChanged: (value) {
setState((){
selectedDropDownValue = value; //on selection, selectedDropDownValue i sUpdated
});
},
),
),
);

Flutter: how to set the height of a dropdown in Flutter

I have a dropdown list in my flutter app that has about 30 items in it. When it is selected I see the values but it takes up whole screen.
How can I control the height of the selected list so that it does not overlay the entire screen (maybe show 10 items with a scroll)
Here is my code
Widget buildCategoryFormField(candidateModel) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Job category"),
SizedBox(
height: 5,
),
FormField(
builder: (FormFieldState state) {
return InputDecorator(
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
),
// hintText: "firstname *",
// labelText: "job category",
errorText: state.hasError ? state.errorText : null,
labelStyle: TextStyle(
color: Colors.grey,
),
),
isEmpty: _selectedjobCategory == '',
child: new DropdownButtonHideUnderline(
child: new DropdownButton(
style: TextStyle(fontSize: 18, color: Palette.GREY),
value: _selectedjobCategory,
isDense: true,
onChanged: (String newValue) {
setState(() {
_selectedjobCategory = newValue;
state.didChange(newValue);
});
},
items: JOB_CATEGORY.map((String value) {
return new DropdownMenuItem(
value: value,
child: new Text(value),
);
}).toList(),
),
),
);
},
validator: (val) => validateJobCategory(val),
),
],
);
}
You can define menuMaxHeight on DropdownButton to set maximum height of the expanded dropdown list items.
Expanded(
/// LayoutBuilder can be used to fetch the parent widget's dimensions
child: LayoutBuilder(builder: (context, constraints) {
return Center(
child: DropdownButton<String>(
/// Set dropdown list max height
menuMaxHeight: constraints.maxHeight,
value: dropdownValue,
items: dropdownItems,
),
);
}
)
Adding pagination to the dropdown list is feasible, but this will require creating a custom DropdownButton class. Design-wise, it would be better to break the list into smaller chunks (i.e. by categories) if you'll need to display >50 items in the dropdown.