from dropdownmenu to dropdownsearch in flutter - flutter

I was using normal dropdown menu in my project with small amount of data fetched from my api, but now i have menu which could reach hundred of values and make it hard to select an item.
That's why i wanted to use DropDownSearch but instead i get an error
Normal dropdown code which works very fine
DropdownButton(
showSearchBox: true,
showSelectedItem: true,
items: data3.map((item) {
return new DropdownMenuItem(
child: Text(item['first_name']+" "+ item['last_name']),
value: item['emp_code'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection3 = newVal.toString();
});
},
value: _mySelection3,
),
data3 = [{emp_code: 111, first_name: adnen, last_name: hamouda}, {emp_code: 666, first_name: ahmed, last_name: ahmed 99}....
this is the result: normal dropdown
But when i tried to convert it to dropDownSearch i got this result: search dropdown
I want to show the first_name and last_name like the normal dropdown but save the value of their 'emp_code' which i will be using in another api later. How can i fix it ?
DropdownSearch(
mode: Mode.DIALOG,
showSearchBox: true,
items: data3.map((item) {
return new DropdownMenuItem(
child: Text(item['first_name']+" "+ item['last_name']),
value: item['emp_code'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
print(data3);
_mySelection3 = newVal.toString();
});
},
selectedItem: _mySelection3,
),

Here is the way I found to use searchable dropdown lists.
I tried dropdown_search package at first, but it seems the documentation and examples related with the latest version (5.0.2) are depreciated.
Later on, I moved to dropdown_button2 and I am happy the way the DropdownButtonFormField2 was implemented, because it is very similar which I have done to the flutter DropdownButtonFormField implementation, so far.
Have a look at the Flutter bundled DropdownButtonFormField example:
return DropdownButtonFormField<SetorTemp>(
decoration: const InputDecoration(
labelText: 'Setor institucional'),
isExpanded: true,
icon: const Icon(Icons.arrow_downward),
items: snapshot.data!
.map((SetorTemp rtItem) =>
DropdownMenuItem<SetorTemp>(
value: rtItem,
child: Text(
'${rtItem.nome} (${rtItem.sigla})',
softWrap: true,
),
))
.toList(),
hint: Text(
'${selectedSetorTemp.nome} (${selectedSetorTemp.sigla})'),
onChanged: (SetorTemp? newValue) {
setState(() {
// do your logic here!
selectedSetorTemp = newValue;
});
},
);
And the DropdownButtonFormField2 using dropdown_button2 package
return DropdownButtonFormField2<SetorTemp>(
decoration: const InputDecoration(
labelText: 'Setor institucional'),
isExpanded: true,
icon: const Icon(Icons.arrow_downward),
items: snapshot.data!
.map((SetorTemp rtItem) =>
DropdownMenuItem<SetorTemp>(
value: rtItem,
child: Text(
'${rtItem.nome} (${rtItem.sigla})',
softWrap: true,
),
))
.toList(),
hint: Text(
'${selectedSetorTemp.nome} (${selectedSetorTemp.sigla})'),
onChanged: (SetorTemp? newValue) {
setState(() {
// Do your logic here!
selectedSetorTemp = newValue;
});
},
// Search implementation using dropdown_button2 package
searchController: searchContentSetor,
searchInnerWidget: Padding(
padding: const EdgeInsets.only(
top: 8,
bottom: 4,
right: 8,
left: 8,
),
child: TextFormField(
controller: searchContentSetor,
decoration: InputDecoration(
isDense: false,
contentPadding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 8,
),
labelText: 'Setor institucional',
hintText: 'Parte do nome do setor...',
counterText: '',
hintStyle: const TextStyle(fontSize: 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
searchMatchFn: (rtItem, searchValue) {
return (rtItem.value.nome
.toLowerCase()
.contains(searchValue.toLowerCase()));
},
//This to clear the search value when you close the menu
onMenuStateChange: (isOpen) {
if (!isOpen) {
searchContentSetor.clear();
}
},
);
They are similar at first:
However, after clicking they will show their differences from the initial implementation:
To the dropdown_button2 package:
The selectedSetorTemp variable is of the type SetorTemp and the model I have used is:
class SetorTemp {
final int id;
final String? nome;
final String? sigla;
SetorTemp({required this.id, this.nome, this.sigla});
factory SetorTemp.fromJson(Map<String, dynamic> json) {
return SetorTemp(
id: json['id'] as int,
nome: json['nome'] as String,
sigla: json['sigla'] as String,
);
}
Map<String, dynamic> toJson() => {
'nome': nome,
'sigla': sigla,
};
}

Related

add multiple dropdown value to a List in flutter

In my flutter app I've created a dropdown. initially there is only one dropdown but the user can add more. the items of these dropdowns are the same. but the selected results has to be different. but my code is returning the last selected value. so how can I add it on list?
Model
class DropModel {
String? selected;
DropModel({this.selected});
setData(list) {
for (int i = 0; i < list.length; i++) {
selected = list;
}
}
}
initialize
List<String>? selCat;
DropModel selDrop = DropModel();
dropdown widget
DropdownButtonFormField2 _generatedDropDown(
List<String> category, String? selected, int index) {
final group = _GroupControllers();
return DropdownButtonFormField2(
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
),
),
isExpanded: true,
hint: const Text(
'Select Category',
style: TextStyle(fontSize: 14),
),
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.black45,
),
iconSize: 30,
buttonHeight: 60,
buttonPadding: const EdgeInsets.only(left: 20, right: 10),
items: category
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
))
.toList(),
validator: (value) {
if (value == null) {
return 'Please select Catagory.';
}
},
onChanged: (value) {
//Do something when changing the item if you want.
setState(() {
// selDrop.setData(value.toString());
selected = value.toString();
selDrop.selected = selected;
selCat!.insert(index, selected.toString());
});
},
onSaved: (value) {
//selDrop.setData(value.toString());
selected = value.toString();
selDrop.selected = selected;
selCat!.insert(index, selected.toString());
},
);
}
result looped
print(".................${selDrop.selected}"); // returns the last added/ selected value
print(".................${selCat}"); //returns null
the traditional List returns null and the model returns the last added/selected value. how can i add multiple dropdown selected values to a List? each has different values. in a textfield I could create dynamic TextEditingController but how can I manage dropdowns

Flutter : Right overflowed by 70 pixels

i m new to flutter and am trying to make a Responsive app , i have a textfield and i wanted to add a dropdown list next to it it s working but it shows a error " right overflowed by 150 pixels" even tho i m using the Expanded widget in the child . the error is in both dropdownlists
thank you for ur help in advance
import '../Classes/demandes.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../data/menu_item.dart';
import '../Classes/menu.dart';
import '../data/logout.dart';
class Demandes extends StatefulWidget {
#override
_demande createState() => _demande();
}
class _demande extends State<Demandes> {
String dropdownValue = 'Assets';
String dropdownValue1 = 'Locations';
Future<Demandes?> submitData(String description, ASSETNUM, location,
DESCRIPTION_LONGDESCRIPTION) async {
var respone = await http.post(
Uri.parse(
'http://9080/maxrest/rest/mbo/sr/?_lid=azizl&_lpwd=max12345m&_format=json'),
body: {
"description": description,
"ASSETNUM": ASSETNUM,
"location": location,
"DESCRIPTION_LONGDESCRIPTION": DESCRIPTION_LONGDESCRIPTION,
});
var data = respone.body;
print(data);
if (respone.statusCode == 201) {
dynamic responseString = respone.body;
azizFromJson(responseString);
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Demande de service Cree")));
} else
return null;
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("error")));
return null;
}
late Demandes? _demandes;
TextEditingController descriptionController = TextEditingController();
TextEditingController ASSETNUMController = TextEditingController();
TextEditingController locationController = TextEditingController();
TextEditingController DESCRIPTION_LONGDESCRIPTIONController =
TextEditingController();
Widget DescriptionTextField() {
return TextField(
decoration: InputDecoration(
// labelText: "Description",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
),
controller: descriptionController,
);
}
Widget AssetTextField() {
return TextField(
decoration: InputDecoration(
// labelText: "Asset",
border: OutlineInputBorder(),
),
controller: ASSETNUMController,
);
}
Widget DeatialsTextField() {
return TextField(
decoration: InputDecoration(
// labelText: "Details",
border: OutlineInputBorder(),
),
maxLines: 10,
controller: DESCRIPTION_LONGDESCRIPTIONController,
);
}
Widget LocationTextField() {
return TextField(
decoration: InputDecoration(
// labelText: "Location",
border: OutlineInputBorder(),
),
controller: locationController,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Creation Demande de service'),
actions: [
PopupMenuButton<MenuItem>(
onSelected: (item) => onSelected(context, item),
itemBuilder: (context) =>
[...MenuItems.itemsFirst.map(buildItem).toList()],
)
],
),
body: ListView(
padding: EdgeInsets.all(8),
// ignore: prefer_const_literals_to_create_immutables
children: [
ListTile(
title: Text("Description"),
),
DescriptionTextField(),
ListTile(
title: Text("Details"),
),
DeatialsTextField(),
ListTile(title: Text("Asset")),
Row(
children: <Widget>[
Expanded(
child: AssetTextField(),
),
const SizedBox(
width: 20,
),
Expanded(
child: DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.blue),
underline: Container(
height: 2,
color: Color.fromARGB(255, 0, 140, 255),
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>[
'Assets',
'100014 moteur 3',
'100027 Système de freinage 1',
'12500 Overhead Crane #2',
'13110 Feeder System',
'13120 Bottom Sealing System',
'13130 Stripper System',
'13140 Conveyor System- Pkg. Dept.',
'13141 Elevator Rails And Drainpan Assembly',
'13142 Carton Escapement Assembly #2',
'13143 Chain Wash Assembly',
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)),
],
),
ListTile(
title: Text("Location"),
),
Row(
children: <Widget>[
Expanded(
child: LocationTextField(),
),
const SizedBox(
width: 20,
),
Expanded(
child: DropdownButton<String>(
value: dropdownValue1,
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.blue),
underline: Container(
height: 2,
color: Color.fromARGB(255, 0, 140, 255),
),
onChanged: (String? newValue) {
setState(() {
dropdownValue1 = newValue!;
});
},
items: <String>[
'Locations',
'100014 moteur 3',
'10002 7 Système de freinage 1',
'12500 Overhead Crane #2',
'13110 Feeder System',
'13120 Bottom Sealing System',
'13130 Stripper System',
'13140 Conveyor System- Pkg. Dept.',
'13141 Elevator Rails And Drainpan Assembly',
'13142 Carton Escapement Assembly #2',
'13143 Chain Wash Assembly',
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)),
],
),
const SizedBox(
width: 20,
),
Padding(padding: EdgeInsets.all(10)),
ElevatedButton(
onPressed: (() async {
String description = descriptionController.text;
String ASSETNUM = ASSETNUMController.text;
String location = locationController.text;
String DESCRIPTION_LONGDESCRIPTION =
DESCRIPTION_LONGDESCRIPTIONController.text;
Demandes? data = await submitData(description, ASSETNUM,
location, DESCRIPTION_LONGDESCRIPTION);
setState(() {
_demandes = data;
});
}),
child: Text("submit "),
)
],
));
}
}
Ok the only thing that you have to write is this :
Expanded(
child: DropdownButton<String>(
value: dropdownValue,
isExpanded: true, // this
[...]
),
),
Like the documentation say :
Set the dropdown's inner contents to horizontally fill its parent.
By default this button's inner width is the minimum size of its
contents. If [isExpanded] is true, the inner width is expanded to fill
its surrounding container.

TextFormField input text overflow with DropdownButtonFormField, Flutter

I have layout issues because the text from the dropdown menu that you choose can't fit inside the TextFormField and I can't seem to fix this issue. I have tried adding the overflow: TextOverflow.ellipsis property but that only changes for the dropdown labels, still when I choose one, they can't fit inside the TextFormField.
When you press the dropdown button, it shows like this:
and with the TextOverflow.elipsis property:
which is fine, but I still have the layout issue because of the chosen text that is now displayed inside the textformfield:
How can I add the same property to the TextFormField, or any sort of solution to this issue?
The code:
Row(
children: [
Expanded(
child: DropdownButtonFormField<String>(
decoration:
kTextFieldDecoration.copyWith(
hintText: 'Legal status',
labelText: 'Legal status',
),
value: _legalStatus,
items: [
'Sole proprietorship',
'Partnerships',
'Limited Liability Company (LLC)',
'Corporation',
'Small Business Corporation (S-Corporation)'
]
.map((label) => DropdownMenuItem(
child: Text(
label.toString(),
),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_legalStatus = value;
print(value);
});
},
validator: (thisValue) {
if (thisValue == null) {
return 'Please choose your legal status';
}
return null;
},
),
),
SizedBox(
width: 16.0,
),
Container(
width: 120.0,
child: DropdownButtonFormField<String>(
decoration:
kTextFieldDecoration.copyWith(
hintText: 'Year established',
labelText: 'Year established',
),
value: _yearEstablished,
items: items // a list of numbers that are Strings
.map((label) => DropdownMenuItem(
child:
Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_yearEstablished = value;
print(value);
});
},
validator: (thisValue) {
if (thisValue == null) {
return 'Please choose your company year of establishment';
}
return null;
},
),
),
],
),
Thanks in advance for your help!
You need to use isExpanded property of DropDownFormField to solve this error.
Row(
children: [
Expanded(
child: DropdownButtonFormField<String>(
isExpanded: true,
decoration:
kTextFieldDecoration.copyWith(
hintText: 'Legal status',
labelText: 'Legal status',
),
value: _legalStatus,
items: [
'Sole proprietorship',
'Partnerships',
'Limited Liability Company (LLC)',
'Corporation',
'Small Business Corporation (S-Corporation)'
]
.map((label) => DropdownMenuItem(
child: Text(
label.toString(),
),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_legalStatus = value;
print(value);
});
},
validator: (thisValue) {
if (thisValue == null) {
return 'Please choose your legal status';
}
return null;
},
),
),
SizedBox(
width: 16.0,
),
Container(
width: 120.0,
child: DropdownButtonFormField<String>(
decoration:
kTextFieldDecoration.copyWith(
hintText: 'Year established',
labelText: 'Year established',
),
value: _yearEstablished,
items: items // a list of numbers that are Strings
.map((label) => DropdownMenuItem(
child:
Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_yearEstablished = value;
print(value);
});
},
validator: (thisValue) {
if (thisValue == null) {
return 'Please choose your company year of establishment';
}
return null;
},
),
),
],
),
You need to use selectedItemBuilder parameter which will control how the selected item will be displayed on the button. Then, TextOverflow.ellipsis will work with you as expected. Here's how to use it:
selectedItemBuilder: (BuildContext context) {
return items.map<Widget>((String item) {
return Text(item, overflow: TextOverflow.ellipsis,);
}).toList();
},

How to add autofill dropdown in flutter?

I've made a dropdown of cities and city list is coming from API. When user clicks on GPS button, it will auto fill the dropdown field. How should I auto fill the city name in dropdown? I tried by using dropdown inside textfield
TextFormField(
controller: city,
decoration:InputDecoration(
border:InputBorder.none,
prefix: DropdownButtonFormField<String>(
decoration: InputDecoration.collapsed(
hintText: 'select',
hintStyle: TextStyle(fontSize: 12,color: Colors.grey.shade600),
),
value:type,
validator: (value) => value == null? 'please select': null,
onChanged: (String newValue) {
setState(() {
type = newValue;
});
},
items: List?.map((item){
return DropdownMenuItem(
onTap: (){
selectedCity=item['city'];
// print(selectedCity);
},
value: item['id'].toString(),
child: Padding(
padding: const EdgeInsets.only(left:15.0,top: 13.0),
child: Text(item['city'],style: TextStyle(fontSize: 12,color: Colors.grey.shade600),),
),
);
})?.toList()??[]
),
),
),
You can use ready-made auto-complete packages.
Some examples:
https://pub.dev/packages/autocomplete_textfield
https://pub.dev/packages/dropdownfield

Multiple Dependent dropdown in flutter

I am trying to build multiple dependent dropdown on flutter. The second one depend on 1st one. here is the code to the dropdown I have implemented.
Container(
child: new DropdownButton<String>(
underline: SizedBox(
height: 1,
),
hint: new Text("Select Faculty"),
value: facultyId,
items: faculty.map((item) {
return new DropdownMenuItem(
child: new Text(item['name']),
value: item['id'].toString(),
);
}).toList(),
onChanged: (faculty == null)
? null
: (String newValue) {
setState(() {
filteredbatch.clear();
facultyId = newValue;
for (var item in allbatch) {
if (item['facultyId'].toString() == newValue){
filteredbatch.add(item);
disableBatch = false;
}
}
});
print(facultyId);
},
),
),
Container(
child: new DropdownButton<String>(
underline: SizedBox(
height: 1,
),
disabledHint: new Text("Select Faculty First"),
hint: Text("Select Batch"),
value: batchId,
onChanged: disableBatch
? null
: (String newValue) {
setState(() {
batchId = newValue;
disableSection = false;
});
print(batchId);
},
items: filteredbatch.map((item) {
return DropdownMenuItem(
child: Text(item['name']),
value: item['id'].toString(),
);
}).toList()),
),
Whenever I select one dropdown item from first one, it enables 2nd dropdown and lets me to select an item from that dropdown. And when I select an item from 2nd dropdown and go back to change first dropdown, it throws error that dropdown requires one item with respective value. 0 or 2 found. I am lost here. How do I resolve this error?
What is going on here is quite simple. Let's say "allbatch" has these values:
faculty: foo , which has batchids: foo1, foo2, foo3
faculty: bar , which has batchids: bar1, bar2, bar3.
When you select foo in the 1st dropdown a new "filteredbatch" is created and it only contains foo1,foo2,foo3. You then select foo3 in your 2nd dropdown and everything is still working fine...
BUT when you change your 1st dropdown to bar, then "filteredbatch" only contains:bar1, bar2, bar3 and your second dropdown value is still set to foo3 which can not be found in the newly generated "filteredbatch", and then you get that error you are seeing.
To fix this simply set batchId to null before changing the "filteredbatch" in your 1st dropdown onChanged method:
setState(() {
//fix
batchId = null;
//end of fix
filteredbatch.clear();
facultyId = newValue;
for (var item in allbatch) {
if (item['facultyId'].toString() == newValue){
filteredbatch.add(item);
disableBatch = false;
}
}
});
Your 2nd dropdown will revert back to hint text and the app user will have to select a new batchId.
If you have any more questions feel free to ask.
Flutter Dropdown Button FormField Dependent
List<String> dataList = ["A", "B", "C"];
List<String> dataListA = ["A1", "A2", "A3", "A4", "A5"];
List<String> dataListB = ["B1", "B2", "B3", "B4", "B5"];
List<String> dataListC = ["C1", "C2", "C3", "C4", "C5"];
String? valueItem;
List<String> listItem = [];
// DropdownButtonFormField
Container(
margin: const EdgeInsets.only(bottom: p20),
child: DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'Data list',
labelStyle: const TextStyle(),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0)),
contentPadding: const EdgeInsets.only(left: 5.0),),
value: valueItem,
isExpanded: true,
items: dataList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),);
}).toSet().toList(),
onChanged: (value) {
setState(() {
valueItem= value!;
if (valueItem=="A") {
listItem= dataListA;
} else if (valueItem== "B") {
listItem= dataListB;
} else if (valueItem== "C") {
listItem= dataListC;
}
});
},
),
),
// Second DropdownButtonFormField
Container(
margin: const EdgeInsets.only(bottom: p20),
child: DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'List dependent',
labelStyle: const TextStyle(),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0)),
contentPadding: const EdgeInsets.only(left: 5.0),),
value: ListItem,
isExpanded: true,
items: listItem.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);}).toSet().toList(),
onChanged: (value) {
setState(() {
your_value = value!;
});
},
),
),