Flutter- Why I can't see the data inside the Dropdown - flutter

I'm new to Flutter and I can't understand why I can't see the data inside the DropDownButton even tho the lists that I use to create the DropDownButton have the data inside them. Can anyone explain to me why is this happening? The only clue I have is that the DropDownButton starts the creation before I create the list from which is taking the data.
The problem is that my dropdown list is empty.
I provide the entire code below.
Code :
import 'package:flutter/material.dart';
import 'ListOfClienti.dart';
class CreateClient extends StatefulWidget {
#override
_CreateClientState createState() => _CreateClientState();
}
class _CreateClientState extends State<CreateClient> {
String ClientCod = '';
String currentClient = '';
List<String> listNameOfClients = [];
List<DropdownMenuItem<String>> actualList2 = [];
void getClientsName() {
for (var i = 0; i <= ListDatabase.length - 1; i++) {
var name = ListDatabase[i].nome;
print(name);
listNameOfClients.add(name);
}
}
void createListWithClientName() {
for (String oneByOneClient in listNameOfClients) {
var VariableToInsert2 = DropdownMenuItem(
child: Text(oneByOneClient),
value: oneByOneClient,
);
actualList2.add(VariableToInsert2);
}
}
//Method that allows me to create the DropDownButton
DropdownButton<String> createNameMachine() {
return DropdownButton(
items: actualList2,
style: TextStyle(
color: Colors.black,
fontFamily: 'Keqima',
fontSize: 15,
),
value: currentClient,
onChanged: (clientSelected) {
setState(() {
currentClient = clientSelected;
});
},
);
}
#override
Widget build(BuildContext context) {
return Container(
color: Color(0xff757575),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(16),
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Inserisci il codice cliente',
),
onChanged: (textInsideTheField) {
ClientCod = textInsideTheField;
},
),
),
Padding(
padding: EdgeInsets.all(16),
child: Row(
children: <Widget>[
FlatButton(
onPressed: () {
getClientsName();
createListWithClientName();
print(actualList2.length);
},
child: Text(
'Clienti : ',
style: TextStyle(
fontSize: 20,
fontFamily: 'Keqima',
),
),
),
SizedBox(
width: 20,
),
createNameMachine(),
],
),
),
],
),
),
);
}
}

To fix this problem I had to change to things :
Thing: I had to change the List from this List listNameOfClients = []; to this List listNameOfClients = [''];
I had to integrate the setState and inside to call the functions.
setState(() {
getClientsName();
createListWithClientName();
});

Related

Display searched Item base on user input

I'm trying to display a result item following the user input in the text field, but I receive all the items. There were some methods I tried, but they didn't work and I encountered some errors.
here is my source code
import 'dart:convert';
import 'package:ebook_flutter_app/constant.dart';
import 'package:ebook_flutter_app/model/image.dart';
import 'package:ebook_flutter_app/model/text_value.dart';
import 'package:ebook_flutter_app/screens/show_item.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
import '../widgets/showImage.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
SearchScreenState createState() => SearchScreenState();
}
class SearchScreenState extends State<SearchScreen> {
List textValues = [];
List original = [];
List result = [];
TextEditingController txtQuery = TextEditingController();
List<TextValue> textValueList = [];
List<MyImage> myImageList = [];
List<TextValue> getCatList(List<TextValue> inputList, String query) {
List<TextValue> outputList =
inputList.where((item) => item.title == query).toList();
//textValueList = outputList;
//var myList = outputList;
return outputList;
}
List<MyImage> getImageList(List<MyImage> inputList, String query) {
List<MyImage> outputList =
inputList.where((o) => o.id_num!.toString() == query).toList();
// myImageList = outputList;
return outputList;
}
#override
void initState() {
super.initState();
txtQuery.addListener(() {
if (isNumeric(txtQuery.text) == true) {
loadImage();
searchById(txtQuery.text);
print('I\'m using search option for loading Image.... ');
} else {
loadData();
search(txtQuery.text);
print('I\'m using search option for loading Data....');
}
});
}
void loadData() async {
String jsonStr = await rootBundle.loadString('assets/db/text_value.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
setState(() {});
}
void loadImage() async {
String jsonStr = await rootBundle.loadString('assets/db/image_db.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
print('load Image is running....');
setState(() {});
}
void search(String query) {
if (query.isEmpty) {
textValues = original;
setState(() {});
return;
}
query = query.toLowerCase();
print(query);
//List result = [];
textValues.forEach((element) {
var name = element["name"].toString().toLowerCase();
var description = element["description"].toString().toLowerCase();
if (name.contains(query) || description.contains(query)) {
result.add(element);
// textValueList.add(element);
// print('textValueList is $textValueList');
}
});
textValues = result;
setState(() {});
}
void searchById(String query1) {
if (query1.isEmpty) {
textValues = original;
print('query1 is .....$query1');
setState(() {});
return;
}
print('query1 is $query1');
//List result = [];
textValues.forEach((element) {
var id_num = element["id_num"].toString();
var img_num = element["img_num"].toString();
if (id_num.contains(query1)) {
result.add(element);
// myImageList.add(element);
// print('mYImageList is $myImageList');
print('result is......$result');
}
});
textValues = result;
print('textValues is .....$textValues');
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(2),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: txtQuery,
onChanged: (value) {
setState(() {});
},
textDirection: TextDirection.rtl,
decoration: InputDecoration(
hintText: "جست وجو...",
hintTextDirection: TextDirection.rtl,
hintStyle: TextStyle(
color: Colors.black,
fontSize: 18,
fontFamily: 'iran-sans-ds',
decoration: TextDecoration.none,
fontStyle: FontStyle.italic,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
prefixIcon: const Icon(Icons.search),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
txtQuery.text = '';
txtQuery.clear();
},
),
),
keyboardType: TextInputType.text,
),
],
),
),
txtQuery.text.isEmpty
? Container()
: Expanded(
child: ListView.builder(
itemCount: textValues.length,
// isNumeric(txtQuery.text) == true
// ? getImageList(myImageList, txtQuery.text).length
// : getCatList(textValueList, txtQuery.text).length,
itemBuilder: (context, index) {
var textVal = textValues[index];
String description = textVal['description'] ??
'we don\'t have description......';
var id_num = textVal['id_num'].toString() ??
'we don\'t have id_num......';
var img_num = textVal['img_num'].toString() ??
'we don\'t have img_num........... ';
print('id_num is ....$id_num'
' img_num is.....$img_num');
return Card(
margin:
const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Colors.blue[50],
child: Theme(
data: Theme.of(context)
.copyWith(dividerColor: Colors.transparent),
child: InkWell(
onTap: (() => pushNewScreen(
context,
screen: isNumeric(id_num) == false
? ShowItem(
name: textVal['name'],
description:
textVal['description'],
)
: ShowImage(
title: id_num,
image: Myasset(img_num),
),
withNavBar:
true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation:
PageTransitionAnimation.slideRight,
)),
child: ExpansionTile(
title: Text(
isNumeric(id_num) == false
? textVal['name']
: id_num,
textDirection: TextDirection.rtl,
style: const TextStyle(
fontSize: 20.0, color: Colors.black54),
),
childrenPadding: const EdgeInsets.only(
bottom: 20.0,
right: 20.0,
left: 20.0,
top: 5.0),
children: [
isNumeric(id_num) == false
? Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: [
const Text(
'بیشتر',
textDirection:
TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.blue,
fontWeight:
FontWeight.bold),
),
Text(
'${description.substring(0, 39)} ...',
textDirection:
TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.black),
),
])
: Image.asset(
Myasset(img_num),
fit: BoxFit.cover,
width: MediaQuery.of(context)
.size
.width *
0.01,
height: MediaQuery.of(context)
.size
.height *
0.01,
),
],
),
),
),
);
}),
)
]),
);
}
}
Widget _listView(text_value) {
return Expanded(
child: ListView.builder(
itemCount: text_value.length,
itemBuilder: (context, index) {
var textVal = text_value[index];
String description =
textVal['description'] ?? 'we don\'t have description......';
var id_num =
textVal['id_num'].toString() ?? 'we don\'t have id_num......';
var img_num = textVal['img_num'].toString() ??
'we don\'t have img_num........... ';
print('id_num is ....$id_num' ' img_num is.....$img_num');
return Card(
margin: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Colors.blue[50],
child: Theme(
data:
Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: InkWell(
onTap: (() => pushNewScreen(
context,
screen: isNumeric(id_num) == false
? ShowItem(
name: textVal['name'],
description: textVal['description'],
)
: ShowImage(
title: id_num,
image: Myasset(img_num),
),
withNavBar: true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation:
PageTransitionAnimation.slideRight,
)),
child: ExpansionTile(
title: Text(
isNumeric(id_num) == false ? textVal['name'] : id_num,
textDirection: TextDirection.rtl,
style:
const TextStyle(fontSize: 20.0, color: Colors.black54),
),
childrenPadding: const EdgeInsets.only(
bottom: 20.0, right: 20.0, left: 20.0, top: 5.0),
children: [
isNumeric(id_num) == false
? Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
const Text(
'بیشتر',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold),
),
Text(
'${description.substring(0, 39)} ...',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(color: Colors.black),
),
])
: Image.asset(
Myasset(img_num),
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width * 0.01,
height: MediaQuery.of(context).size.height * 0.01,
),
],
),
),
),
);
}),
);
}
I didn't use getCatList & myImageListmethods because I encountered to error when I was using this methods.
How can I fix it?
Inside addListener you're calling loadData() every single time the user enter a character. Try this:
void initState() {
super.initState();
loadData();
txtQuery.addListener(() {
search(txtQuery.text);
});
}
The second thing you could try is use for in instead of forEach
void search(String query) {
if (query.isEmpty) {
textValues = [];
setState(() {});
return;
}
setState(() {
textValues = [
for (var item in yourDataSource)
if (item['key'].contains(query)) item
];
});
}
And you can use textValues in your list
body: ListView.builder(
itemCount: textValues.length,
You can use autocomplete textfield for your problem
check this plugin :
https://pub.dev/packages/auto_complete_search
You don't have any function for onChanged (TextFormField's argument), let's try this:
First edit your search() function
void search(String query) {
if (query.isEmpty) {
setState(() {
textValues = original;
});
return;
}
setState(() {
textValues = original.where( (element) =>
element['name'].contains(query.toLowerCase()).toString().toLowerCase() ||
element['description'].contains(query.toLowerCase()).toString().toLowerCase()
).toList();
});
}
Second edit onChanged argument
onChanged: (value) => search(value)

Flutter with Firebase, Search by multiple queries

I am trying to create a search feature that allows users to search by their username, email, designation or company. I intend to let users have the flexibility of typing any of those into the search bar and search for their target. However, what i am facing is that my code below only calls on the first function and displays results only for username (username is the first function here, can be interchanged with other functions and it will call according to that). my code is below and thanks for all the help in advance.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:ib_club/services/database.dart';
import 'package:ib_club/widgets/widget.dart';
class SearchScreen extends StatefulWidget {
#override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
DatabaseMethods databaseMethods = new DatabaseMethods();
TextEditingController searchTextEditingController =
new TextEditingController();
QuerySnapshot<Map<String, dynamic>> searchSnapshot;
initiateUsernameSearch() {
databaseMethods
.getUserByUsername(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateEmailSearch() {
databaseMethods
.getUserByEmail(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateDesignationSearch() {
databaseMethods
.getUserByDesignation(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateCompanySearch() {
databaseMethods
.getUserByCompany(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateSearch() {
initiateUsernameSearch();
initiateEmailSearch();
initiateDesignationSearch();
initiateCompanySearch();
}
// Create chatroom, send user to conversation screen, pushreplacement
/*createChatroomAndStartConversation(String userUsername) {
List<String> users = [
userUsername,
];
databaseMethods.createChatRoom();
}*/
Widget searchList() {
return searchSnapshot != null
? ListView.builder(
itemCount: searchSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return SearchTile(
userUsername: searchSnapshot.docs[index].data()["username"],
userEmail: searchSnapshot.docs[index].data()["email"],
userDesignation:
searchSnapshot.docs[index].data()["designation"],
userCompany: searchSnapshot.docs[index].data()["company"],
);
})
: Container(
/*child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
const Color(0XffFBD24F))))*/
);
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarMain(context),
body: Container(
child: Column(children: [
SizedBox(
height: 16,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
const Color(0x36FFFFFF),
const Color(0x0FFFFFF)
]),
borderRadius: BorderRadius.circular(40)),
child: TextField(
controller: searchTextEditingController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: "Search User",
hintStyle: TextStyle(color: Colors.white54),
border: InputBorder.none),
),
)),
GestureDetector(
onTap: () {
initiateSearch();
},
child: Container(
height: 45,
width: 45,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
const Color(0x36FFFFFF),
const Color(0x0FFFFFF)
]),
borderRadius: BorderRadius.circular(45)),
child: Icon(Icons.search,
size: 30, color: const Color(0XffFBD24F))),
),
],
),
),
searchList()
]),
));
}
}
class SearchTile extends StatelessWidget {
final String userUsername;
final String userEmail;
final String userDesignation;
final String userCompany;
SearchTile(
{this.userUsername,
this.userEmail,
this.userDesignation,
this.userCompany});
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [const Color(0x36FFFFFF), const Color(0x0FFFFFF)]),
borderRadius: BorderRadius.horizontal()),
child: Row(children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
userUsername,
style: mediumWhiteTextStyle(),
),
Text(
userEmail,
style: mediumWhiteTextStyle(),
),
Text(
userDesignation,
style: mediumWhiteTextStyle(),
),
Text(
userCompany,
style: mediumWhiteTextStyle(),
)
],
),
),
Spacer(),
GestureDetector(
onTap: () {},
child: Container(
decoration: BoxDecoration(
color: const Color(0XffFBD24F),
borderRadius: BorderRadius.circular(30)),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Text(
"Message",
style: mediumTextStyle(),
),
),
)
]),
);
}
}
I could not give a straight answer base on your code but I have a search concept, which I am hoping to help you in any way.
In my case, I always fetch all my item data from firebase and put it in "overallItems" (which is a List of Item Model). From there, I can now start to filter/search my list and return the result.
The concept I use is like this:
List<Item> filterItems() {
//first, I would want to have a temporary holder for a copy of my original items
final List<Item> itemHolder = List<Item>.from(overallItems);
//If user has title input on the search bar
if (titleKeyword.text != '') {
//then this for loop will iterate to all my data
for (final item in List<Item>.from(itemHolder)) {
//will check each title from the list
if (!item.title.toLowerCase().contains(titleKeyword.text.toLowerCase())) {
//elimate items that did not qualify
itemHolder.remove(item);
}
}
}
//so after the first if, itemHolder will be left with the result....
//now, I would also like to search the seller name.
//then, I would just have to repeat the process above
//Searching for Seller Name
if (sellerKeyword.text != '') {
for (final item in List<Item>.from(itemHolder)) {
if (!item.sellerName
.toLowerCase()
.contains(sellerKeyword.text.toLowerCase())) {
itemHolder.remove(item);
}
}
}
//the itemHolder list will have the result
return itemHolder;
}
In the end, we will have the search result after the elimination process.

"The declaration 'setState' isn't referenced." warning for DropdownButton within StatefulWidget

I have a stateful widget in which I put my DropdownButton. Inside DropdownButton's onChange event, I have a setState but it keeps warning me that the declaration 'setState' isn't referenced.
And it's actually not called whenever onChange event is fired.
Any suggestion would be highly appreciated.
Please see the code snippet below for more detailed.
class TypeSetup extends StatefulWidget {
const TypeSetup({Key? key}) : super(key: key);
#override
_TypeSetupState createState() => _TypeSetupState();
}
class _TypeSetupState extends State<TypeSetup> {
var _selectedType;
List<Type>? _types;
#override
void initState() {
super.initState();
loadTypeJson();
}
Future loadTypeJson() async {
String typeJson = await DefaultAssetBundle.of(context)
.loadString("assets/data/types.json");
Iterable typeIter = json.decode(typeJson)["accommodation-types"];
setState(() {
_types = List<Type>.from(typeIter.map((model) => Type.fromJson(model)));
});
}
#override
Widget build(BuildContext context) {
final typeList = _types?.map((model) {
return new DropdownMenuItem<String>(
value: model.type,`enter code here`
child: new Text(model.name),
);
}).toList();
return Container(
padding: EdgeInsets.all(DefaultPalette.defaultPadding),
decoration: BoxDecoration(
color: DefaultPalette.secondaryColor,
borderRadius: const BorderRadius.all(Radius.circular(10)),
),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
"Set up",
style: Theme.of(context).textTheme.subtitle1,
),
SizedBox(
width: double.infinity,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
padding: EdgeInsets.only(left: 16, right: 16),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 1),
borderRadius: BorderRadius.circular(13)),
child: DropdownButton(
hint: Text('Select Type'),
dropdownColor: Colors.white,
icon: Icon(Icons.arrow_drop_down),
iconSize: 30,
isExpanded: true,
underline: SizedBox(),
style: TextStyle(color: Colors.black, fontSize: 22),
value: _selectedType,
onChanged: (newValue) {
setState() {
_selectedType = newValue;
print("Selected type changed.");
}
},
items: typeList,
),
)
)
)
)
]),
);
}
}
You need to call setState like this
setState(() {
_selectedType = newValue;
});

How to add another List of item for DropDownMenu, and then use the items in widget

So I'm trying to make a drop down menu for each options and insert a different List of items each. First of all, because my Dropdownmenu widget shares the same properties for one and another, I extracted the widget to another class name "MenuDropDown". Here is the code for the widget.
import 'package:flutter/material.dart';
import 'List.dart';
class MenuDropDown extends StatefulWidget {
final String dropdownText;
final List<DropdownMenuItem<String>> itemList;
MenuDropDown({this.dropdownText, this.itemList});
#override
_MenuDropDownState createState() => _MenuDropDownState();
}
class _MenuDropDownState extends State<MenuDropDown> {
String selectedItem;
List<DropdownMenuItem> getGroomingTypeList() {
List<DropdownMenuItem<String>> dropdownItems = [];
for (String groomingType in groomingTypeList) {
var newItem = DropdownMenuItem(
child: Text(groomingType),
value: groomingType,
);
dropdownItems.add(newItem);
}
return dropdownItems;
}
List<DropdownMenuItem> getCatBreedsList() {
List<DropdownMenuItem<String>> dropdownItems = [];
for (String catBreed in catBreedsList) {
var newItem = DropdownMenuItem(
child: Text(catBreed),
value: catBreed,
);
dropdownItems.add(newItem);
}
return dropdownItems;
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(0, 8.0, 0, 10.0),
child: Container(
width: 325.0,
height: 50.0,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black45,
offset: Offset(2.5, 5.5),
blurRadius: 5.0,
)
],
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
child: DropdownButtonHideUnderline(
child: DropdownButton(
value: selectedItem,
hint: Padding(
padding: const EdgeInsets.fromLTRB(22.0, 0, 0, 0),
child: Text(
widget.dropdownText,
style: TextStyle(),
),
),
items: widget.itemList,
onChanged: (value) {
setState(() {
selectedItem = value;
});
}),
),
),
);
}
}
above here I created a method to get the list item from the list class that I already created, First it works if I hardcoded the method into the Dropdownmenu's items properties to show the item list, but because I need to use the different list for the different widget, so I think if I try to create a variable of List named itemList, so I can access it from the other class where I can call just the customized variable.
And this is the Stateful widget where i use my Extracted Dropdownmenu widget :
import 'package:flutter/material.dart';
import 'TitleName.dart';
import 'dropdownmenu.dart';
class InformationDetail extends StatefulWidget {
#override
_InformationDetailState createState() => _InformationDetailState();
}
class _InformationDetailState extends State<InformationDetail> {
MenuDropDown _menuDropDown = MenuDropDown();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(25.0, 68.0, 70.0, 26.0),
child: Text(
'Information Detail',
style: TextStyle(fontSize: 35.0),
),
),
Column(
// Wrap Column
children: <Widget>[
Column(
children: <Widget>[
TitleName(
titleText: 'Grooming Type',
infoIcon: Icons.info,
),
MenuDropDown(
dropdownText: 'Grooming Type...',
//I'm trying to implement the list here with a custom variable that contain
a method with different list in dropdownmenu class
itemlist: getGroomingTypeList(),
),
TitleName(
titleText: 'Cat Breeds',
),
MenuDropDown(
dropdownText: 'Cat Breeds...',
),
TitleName(
titleText: 'Cat Size',
infoIcon: Icons.info,
),
MenuDropDown(
dropdownText: 'Cat Size...',
),
TitleName(
titleText: 'Add-On Services',
),
MenuDropDown(
dropdownText: 'Add - On Services...',
),
Container(
margin: EdgeInsets.fromLTRB(0, 15.0, 0, 0),
width: 75.0,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
border: Border.all(
color: Colors.black,
),
borderRadius: BorderRadius.circular(12.0),
),
child: IconButton(
icon: Icon(Icons.arrow_forward),
onPressed: () {
Navigator.of(context)
.pushNamed('/ReservationDetail');
},
),
),
],
),
],
),
],
),
),
),
);
}
}
And this is the list that I want to use for each of dropdown menu widget
const List groomingTypeList = ['Basic Grooming', 'Full Grooming'];
const List catBreedsList = [
'Persia',
'Anggora',
'Domestic',
'Maine Coon',
'Russian Blue',
'Slamese',
'Munchkin',
'Ragdoll',
'Scottish Fold',
];
const List catSizeList = [
'Small Size',
'Medium Size',
'Large Size',
'Extra Large Size',
];
const List addOnServicesList = [
'Spa & Massage',
'Shaving Hair / Styling',
'Injection Vitamis Skin & Coat',
'Cleaning Pet House and Environment',
'Fur Tangled Treatment',
];
I got stuck from there. How to use a different list for each dropdown menu widget that I made, because I already tried to make a constructor, variable, and method so I can use it separately, but instead I got an error that says,
type 'List' is not a subtype of type 'List<DropdownMenuItem>'
I think I implemented it in the wrong way in the first place. I really need help with another solution to these problems. thank you, everyone!
Just check out the code that I have made some changes :
import 'package:flutter/material.dart';
void main() => runApp(InformationDetail());
class InformationDetail extends StatefulWidget {
#override
_InformationDetailState createState() => _InformationDetailState();
}
class _InformationDetailState extends State<InformationDetail> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Container(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(25.0, 68.0, 70.0, 26.0),
child: Text(
'Information Detail',
style: TextStyle(fontSize: 35.0),
),
),
Column(
// Wrap Column
children: <Widget>[
Column(
children: <Widget>[
Text(
'Grooming Type',
),
MenuDropDown(
dropdownText: 'Grooming Type...',
//I'm trying to implement the list here with a custom variable that contain
// a method with different list in dropdownmenu class
type: "groomingType",
),
Text(
'Cat Breeds',
),
MenuDropDown(
dropdownText: 'Cat Breeds...',
type: "catBreeds",
),
Text(
'Cat Size',
),
MenuDropDown(
dropdownText: 'Cat Size...',
type: "catSize",
),
Text(
'Add-On Services',
),
MenuDropDown(
dropdownText: 'Add - On Services...',
type: "addOnServices",
),
Container(
margin: EdgeInsets.fromLTRB(0, 15.0, 0, 0),
width: 75.0,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
border: Border.all(
color: Colors.black,
),
borderRadius: BorderRadius.circular(12.0),
),
child: IconButton(
icon: Icon(Icons.arrow_forward),
onPressed: () {
Navigator.of(context)
.pushNamed('/ReservationDetail');
},
),
),
],
),
],
),
],
),
),
),
),
);
}
}
class MenuDropDown extends StatefulWidget {
final String dropdownText;
final String type;
MenuDropDown({this.dropdownText, this.type});
#override
_MenuDropDownState createState() => _MenuDropDownState();
}
class _MenuDropDownState extends State<MenuDropDown> {
String selectedItem;
List<String> dropdownItems = [];
List<String> groomingTypeList = ['Basic Grooming', 'Full Grooming'];
List<String> catBreedsList = [
'Persia',
'Anggora',
'Domestic',
'Maine Coon',
'Russian Blue',
'Slamese',
'Munchkin',
'Ragdoll',
'Scottish Fold',
];
List<String> catSizeList = [
'Small Size',
'Medium Size',
'Large Size',
'Extra Large Size',
];
List<String> addOnServicesList = [
'Spa & Massage',
'Shaving Hair / Styling',
'Injection Vitamis Skin & Coat',
'Cleaning Pet House and Environment',
'Fur Tangled Treatment',
];
List<String> getListBasedOnName(String value) {
print(value);
switch (value) {
case "groomingType":
return groomingTypeList;
break;
case "catBreeds":
return catBreedsList;
break;
case "catSize":
return catSizeList;
break;
case "addOnServices":
return addOnServicesList;
break;
}
return null;
}
#override
void initState() {
super.initState();
print(widget.type);
dropdownItems = getListBasedOnName(widget.type);
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(0, 8.0, 0, 10.0),
child: Container(
width: 325.0,
height: 50.0,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black45,
offset: Offset(2.5, 5.5),
blurRadius: 5.0,
)
],
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
child: DropdownButtonHideUnderline(
child: DropdownButton(
value: selectedItem,
hint: Padding(
padding: const EdgeInsets.fromLTRB(22.0, 0, 0, 0),
child: Text(
widget.dropdownText,
style: TextStyle(),
),
),
items: dropdownItems.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedItem = value;
});
}),
),
),
);
}
}
As some of the widgets were missing, I have added mine you can change as per your needs. Let me know if it works.

Not able to change a value in one page with respect to the value from another page in flutter

i want to change the indexvalue (pictogramindex) of one page when we click nextbutton on another screen.I will explain briefly , I have 2 screens in my scenario the first screen contains an image and it's name , a textfield and nextbutton (i have provided a dummy data contains a list of image and it's names) the logic behind this is , when we complete the textfield box and click next button(after validate) the textfield value checks with the correctvalue which i was given in the dummy data and show it's synonym which also provided. when we click the next button we will go to another page which contains the correct answer(passed from first page) and a textfield in this the user can write about the correct answer ( validated) when click next button in this page (till this my applicationworks perfectly) i want to load the first page with it's index updated (+1) which i initialised as 0 (var pictogramindex=0). But in my case when coming back to first page the index is not updating it will automatically stores the initialised value. what i want is i want to update index on the first page when i click next button in the Second page .
my source code of first screen is shown here
class Pictogramscreen extends StatefulWidget {
final int length;
const Pictogramscreen({Key key, this.length}) : super(key: key);
#override
_PictogramscreenState createState() => _PictogramscreenState();
}
class _PictogramscreenState extends State<Pictogramscreen> {
#override
final _Key = GlobalKey<FormState>();
Color defaultcolor = Colors.blue[50];
Color trueColor = Colors.green;
Color falseColor = Colors.red;
Widget defcorrect = Text('');
var pictogramindex = 0;
TextEditingController usertitleInput = TextEditingController();
nextPictogram() {
setState(() {
pictogramindex++;
});
}
fillColor() {
setState(() {
usertitleInput.text == pictdata[pictogramindex]['pictcorrectword']
? defaultcolor = trueColor
: defaultcolor = falseColor;
});
}
correctText() {
setState(() {
usertitleInput.text == pictdata[pictogramindex]['pictcorrectword']
? defcorrect = Text(pictdata[pictogramindex]['pictsynonym'])
: defcorrect = Text(pictdata[pictogramindex]['pictcorrectword']);
});
}
reset() {
setState(() {
defaultcolor = Colors.blue[50];
defcorrect = Text('');
usertitleInput.clear();
});
}
void description(BuildContext ctx) {
Navigator.of(context).pushNamed('/user-description', arguments: {
'id': pictdata[pictogramindex]['pictid'],
'word': pictdata[pictogramindex]['pictcorrectword']
});
}
Widget build(BuildContext context) {
int length = pictdata.length;
return Scaffold(
body: pictogramindex < pictdata.length
? ListView(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20),
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Card(
margin: EdgeInsets.only(top: 20),
child: Image.network(
pictdata[pictogramindex]['pictimg']),
),
SizedBox(
height: 10,
),
Text(
pictdata[pictogramindex]['pictword'],
style: TextStyle(
fontSize: 25,
),
),
SizedBox(
height: 10,
),
//Card(
//color: Colors.blue,
// child: TextField(
// decoration: InputDecoration.collapsed(
// hintText: 'type here'),
//textAlign: TextAlign.center,
// onSubmitted: (value) {
// usertitleInput = value;
// print(usertitleInput);
// },
// ),
//),
Form(
key: _Key,
child: TextFormField(
controller: usertitleInput,
validator: (usertitleInput) {
if (usertitleInput.isEmpty) {
return 'Answer cannot be empty';
} else {
return null;
}
},
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.blueAccent),
borderRadius: BorderRadius.all(
Radius.circular(15),
)),
labelText: 'Type your Answer',
filled: true,
fillColor: defaultcolor,
),
onFieldSubmitted: (value) {
usertitleInput.text = value;
fillColor();
correctText();
print(usertitleInput.text);
}),
),
SizedBox(
height: 10,
),
defcorrect,
SizedBox(
height: 10,
),
RaisedButton(
onPressed: () {
if (_Key.currentState.validate()) {
description(context);
// nextPictogram();
reset();
}
//
//if (_Key.currentState.validate() == correctText()) {
// nextPictogram;
// }
},
child: Text('Next'),
)
],
),
),
],
)
: Center(
child: Text('completed'),
));
}
}
my source code of the second screen is show here
class Userinputscreen extends StatefulWidget {
final String id;
final String word;
const Userinputscreen({Key key, this.id, this.word}) : super(key: key);
#override
_UserinputscreenState createState() => _UserinputscreenState();
}
class _UserinputscreenState extends State<Userinputscreen> {
final _Keey = GlobalKey<FormState>();
TextEditingController userdescription = TextEditingController();
var pictogramindex;
void nextpict(BuildContext context) {
Navigator.of(context).pushNamed('/main-screen');
}
// void nextpict(BuildContext context, int index) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (ctx) => Pictogramscreen(
// index: i = 0,
// )));
// }
#override
Widget build(BuildContext context) {
final routeArgs =
ModalRoute.of(context).settings.arguments as Map<String, String>;
final correctWord = routeArgs['word'];
return MaterialApp(
home: Scaffold(
body: ListView(children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 50),
child: Center(
child: Container(
padding: EdgeInsets.all(20),
margin: EdgeInsets.only(top: 100),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
correctWord,
style: TextStyle(fontSize: 26),
),
SizedBox(
height: 10,
),
Form(
key: _Keey,
child: TextFormField(
controller: userdescription,
validator: (userdescription) {
if (userdescription.isEmpty) {
return 'Answer cannot be empty';
} else {
return null;
}
},
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent),
borderRadius: BorderRadius.all(
Radius.circular(15),
)),
labelText: 'Type your Answer',
filled: true,
),
onFieldSubmitted: (value) {
userdescription.text = value;
print(userdescription.text);
}),
),
SizedBox(
height: 10,
),
RaisedButton(
onPressed: () {
if (_Keey.currentState.validate()) {
nextpict(context);
}
},
child: Text('Next'),
)
],
),
),
),
),
])),
);
}
}
If I get it right, you basically want to tell the initial page that it's state is updated(the index) elsewhere. You basically need to make your app "reactive".
As is said in Google Developers Tutorial:
One of the advantages of Flutter is that it uses reactive views, which you can take to the next level by also applying reactive principles to your app’s data model.
Use some sort of state management. You need to choose from and use either Bloc, InheritedWidget and InheritedModel, Provider(ScopedModel), or the like.
Check this article on flutter about state management, or this for a complete list of approaches