flutter how to update grid view - flutter

i have grid view shows all data in list and i have drop down with values like price from low to high and when user select any value then i will re-sort the list at this point all is work correctly and list updated but grid view stell with old list.
i cannot update grid view
class ProductsListState extends State<ProductsList> {
double width;
String _title;
String _selectedSort;
String _language;
ProductsListState(this._title);
List productsList;
int filter;
#override
Widget build(BuildContext context) {
MediaQueryData deviceInfo = MediaQuery.of(context);
width = deviceInfo.size.width;
_language = _language ?? AppLocalizations.of(context).tr('lang');
filter = filter ?? 1;
_selectedSort ??= getSortFilter(_language)[0];
productsList = (productsList ?? getProductsList(filter));
print(productsList);
print(filter);
var size = MediaQuery.of(context).size;
var data = EasyLocalizationProvider.of(context).data;
return EasyLocalizationProvider(
data: data,
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Color.fromRGBO(205, 14, 64, 1),
appBar:
MarketinoAppBar(title: _title, width: width, appContext: context),
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
blurRadius: 13.0,
color: Colors.black.withOpacity(.5),
offset: Offset(6.0, 7.0),
),
],
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20)),
),
),
Column(
children: <Widget>[
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 20, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text('SORT BY: '),
DropdownButton<String>(
value: _selectedSort,
onChanged: (value) {
setState(() {
productsList.sort(
(a, b) => a['price'].compareTo(b['price']));
_selectedSort = value;
filter = 2;
});
},
items: getSortFilter(_language).map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
],
),
),
Container(
child: filter == 1
? Grid(productsList, width, size)
: Grid(getProductsList(2), width, size),
)
],
)
],
),
),
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
EasylocaLizationDelegate(locale: data.locale, path: "assets/language")
],
supportedLocales: [Locale('en', 'US'), Locale('ar', 'SA')],
locale: data.savedLocale,
),
);
}
//replace by json
List getProductsList(int filter) {
List list = [];
list.add({
"id": "1",
"name": "sssss",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "110",
"quantity": "1",
"isLiked": "false",
"max": "5"
});
list.add({
"id": "2",
"name": "sssss",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "112",
"quantity": "1",
"isLiked": "true",
"max": "5"
});
list.add({
"id": "3",
"name": "sssss",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "114",
"quantity": "1",
"isLiked": "true",
"max": "10"
});
list.add({
"id": "4",
"name": "sssssssssssssssssssssssssssssssssssssssssssssssssssssssszzzzz",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "11",
"quantity": "1",
"isLiked": "false",
"max": "1"
});
list.add({
"id": "5",
"name": "sssss",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "110",
"quantity": "1",
"isLiked": "false",
"max": "15"
});
switch (filter) {
case 1:
list.sort((a, b) => a['id'].compareTo(b['id']));
break;
case 2:
list.sort((a, b) => a['price'].compareTo(b['price']));
break;
}
return list;
}
List<String> getSortFilter(String language) {
if (language == 'english')
return [
"الأكثر رواجا",
"السعر من الأقل للأعلى",
"السعر من الأعلى للأقل",
"التخفيضات",
];
else
return [
"Popularty",
"Price: Low to High",
"Price: High to Low",
"Discount",
];
}
}
class Grid extends StatefulWidget {
List productsList;
var _width;
var _size;
Grid(this.productsList, this._width, this._size);
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return GridState(productsList, _width, _size);
}
}
class GridState extends State<Grid> {
List productsList;
var _width;
var _size;
GridState(this.productsList, this._width, this._size);
#override
Widget build(BuildContext context) {
// TODO: implement build
return Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new GridView.builder(
itemCount: productsList.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: _width > 600 ? 3 : 2,
childAspectRatio: _width > 600 ? 0.6 : _width > 400 ? .725 : .685,
// childAspectRatio: (_itemWidth / _itemHeight),
),
itemBuilder: (BuildContext context, int index) {
return ProductGridTile(
price: double.parse(productsList[index]['price']),
width: _size.width,
image: productsList[index]['imageUrl'],
title: productsList[index]['name'],
likeStatus: productsList[index]['isLiked'] == 'true',
max: double.parse(productsList[index]['max']),
id: int.parse(productsList[index]['id']));
}),
),
);
}
}
gridview updated after re-sort list

You are doing some operations inside the build() method, when you call setState() these operations would be called again. Check that part and also try to update the list this way:
productsList = List.from(productsList)..sort(
(a, b) => a['price'].compareTo(b['price']));

Related

how to check value in list empty or not and if not get the value

I am getting a list from servers like this
[
{
"Date": "2022-10-21",
"Wages": [
{
"Name": "101 Working hours",
"Balance": "8.00",
"Date": "2022-10-21",
"ShiftName": "AU128"
},
{
"Name": "102 Bonus pay",
"Balance": "3:48",
"Date": "2022-10-21",
"ShiftName": ""
},
{
"Name": "110 Split Shift",
"Balance": "1:00",
"Date": "2022-10-21",
"ShiftName": ""
},
{
"Name": "111 Wage reduction",
"Balance": "1:00",
"Date": "2022-10-21",
"ShiftName": ""
}
]
},
]
I want to get ShiftName if it is not empty and shows at FE. shift name is in Wages List
Text(
Wages[i].shiftName ?? "",
style: wageTextStyle,
),
I try to use List.any((any) => any.containsValue());
but I do not know which value I get from server because shiftName can be changed
my API calling method from provider Consumer
Consumer<EmployeeWageAccountsProvider>(
builder: (context, data, child) {
if (!data.isLoading) {
int length = data.getEmployeeAccountsData!.length;
if (data.getEmployeeAccountsData!.isNotEmpty) {
wageAccountsData = data.getEmployeeAccountsData!;
return ListView.builder(
itemCount: length,
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, i) {
return WageAccountsCard(
date: Helper.formatStringDate(
wageAccountsData[i].date!),
shiftName: wageAccountsData[i].wages!
[i].shiftName!.isEmpty ? "":wageAccountsData[i].wages!
[i].shiftName,
wages: wageAccountsData[i].wages,
);
},
);
}
return noDataFound(context, 50);
}
return const WageAccountsShimmer();
}),
wage accounts card to displaying data to user
class WageAccountsCard extends StatelessWidget {
final String? date;
final String? shiftName;
final List<Wages>? wages;
const WageAccountsCard(
{Key? key,
this.date,
this.shiftName,
this.wages})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(10),
padding: const EdgeInsets.all(8),
decoration: CustomBoxDecoration.cardDecoration(context,
shadow: true),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
shiftName ?? "",
style: wageTextStyle,
),
Text(
date.toString(),
style: wageTextStyle,
),
],
),
SizedBox(
height: Styles.height(context) * 0.01,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
S.of(context).wage_type,
style: cTextStyle,
),
Text(
S.of(context).balance,
style: cTextStyle,
),
],
),
const Divider(
color: Colors.black,
),
]
),
);
}
}
shiftName ?? "", used to return default value on null case.
You are getting empty String, therefore you can do
shiftName.isEmpty ? "onEmptyCaseValue" : shiftName
return shiftName.isEmpty ? Center(child: Text('Empty')) : Text(
shiftName ?? "",
style: wageTextStyle,
),
wageAccountsData[i].wages!
[i].shiftName!.isEmpty ? "":wageAccountsData[i].wages[i].shiftName,
insted of this just write like this
wageAccountsData[i].wages![i].shiftName ?? "Default Text",

How to select one checkbox in listView inside listview in Flutter

how to select one checkbox in each answer for each question. so that each question can only be chosen one answer. this is my data and this is my code
This is data example:
List<dynamic> survey = [
{
"id": 1,
"question":"Question1",
"answer": [
{"id": 1, "name": "Option A"},
{"id": 2, "name": "Option B"},
{"id": 3, "name": "Option C"},
{"id": 4, "name": "Option D"}
],
},
{
"id": 2,
"question":
"Question2",
"answer": [
{"id": 1, "name": "Option A"},
{"id": 2, "name": "Option B"},
{"id": 3, "name": "Option C"},
{"id": 4, "name": "Option D"}
],
},
];
This is my code:
bool isSelected = false;
onSelected(value) {
setState(() {
isSelected = value!;
});
}
#override
Widget build(BuildContext context) {
return ListView.builder(
shrinkWrap: true,
itemCount: survey.length,
itemBuilder: (BuildContext context, int index) {
var number = index + 1;
var listAnswer = survey[index]["answer"];
return Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.9,
child: Text(
survey[index]["question"],
maxLines: 5,
overflow: TextOverflow.ellipsis,
),
),
SizedBox(height: 10),
ListView.builder(
shrinkWrap: true,
itemCount: listAnswer.length,
itemBuilder: (BuildContext context, int index) {
return Container(
margin: EdgeInsets.only(bottom: 10),
child: ListTile(
title: Text(listAnswer[index]["name"]),
trailing: Checkbox(
checkColor: Colors.white,
value: isSelected,
shape: CircleBorder(),
onChanged: (bool? value) {
onSelected(value);
},
),
),
);
},
)
],
),
);
},
);
}
It would be easier with model class. I am using a map to store the selected answer.
Map<String, int> selectedAnswer = {};
Method checking whether current answer is selected or not.
bool isSelected(String qustion, int answerID) {
if (selectedAnswer.containsKey(qustion) &&
selectedAnswer[qustion] == answerID) {
return true;
}
return false;
}
And switching value
onChanged: (bool? value) {
if (_isSelected) {
selectedAnswer[question] =
listAnswer[index]["id"];
} else {
selectedAnswer
.addAll({question: listAnswer[index]["id"]});
}
setState(() {});
},
Full widget.
class TEL extends StatefulWidget {
const TEL({super.key});
#override
State<TEL> createState() => _TELState();
}
class _TELState extends State<TEL> {
List<dynamic> survey = [
{
"id": 1,
"question": "Question1",
"answer": [
{"id": 1, "name": "Option A"},
{"id": 2, "name": "Option B"},
{"id": 3, "name": "Option C"},
{"id": 4, "name": "Option D"}
],
},
{
"id": 2,
"question": "Question2",
"answer": [
{"id": 1, "name": "Option A"},
{"id": 2, "name": "Option B"},
{"id": 3, "name": "Option C"},
{"id": 4, "name": "Option D"}
],
},
];
Map<String, int> selectedAnswer = {};
bool isSelected(String qustion, int answerID) {
if (selectedAnswer.containsKey(qustion) &&
selectedAnswer[qustion] == answerID) {
return true;
}
return false;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(8),
itemCount: survey.length,
itemBuilder: (BuildContext context, int index) {
var number = index + 1;
final question = survey[index]["question"];
List<Map> listAnswer = survey[index]["answer"];
return Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.9,
child: Text(
question,
maxLines: 5,
overflow: TextOverflow.ellipsis,
),
),
SizedBox(height: 10),
ListView.builder(
shrinkWrap: true,
itemCount: listAnswer.length,
itemBuilder: (BuildContext context, int index) {
final bool _isSelected =
isSelected(question, listAnswer[index]["id"]);
return Container(
margin: EdgeInsets.only(bottom: 10),
child: ListTile(
title: Text(listAnswer[index]["name"].toString()),
trailing: Checkbox(
checkColor: Colors.white,
value: _isSelected,
shape: CircleBorder(),
onChanged: (bool? value) {
if (_isSelected) {
selectedAnswer[question] =
listAnswer[index]["id"];
} else {
selectedAnswer
.addAll({question: listAnswer[index]["id"]});
}
setState(() {});
},
),
),
);
},
)
],
),
);
},
),
);
}
}

error: Null check operator used on a null value OR List<dynamic> is not a subtype of type Map<String, dynamic>

fetch Two different pages api with same uniq id
I want the user_uniq_id of the API of the button and the user_uniq_id of the API of the team_list to match and show the data of its user after the match.
this code is for first File
This code is of the button that is coming from the api
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:practice/left_team.dart';
import 'package:http/http.dart' as http;
class Button extends StatefulWidget {
#override
_ButtonState createState() => _ButtonState();
}
class _ButtonState extends State<Button> {
var api = Uri.parse('http://192.***.***.***/flutter/teamApi.php');
var response;
var teamApi;
#override
void initState() {
super.initState();
fetchData();
}
fetchData() async {
response = await http.get(api);
print(response.body);
teamApi = jsonDecode(response.body);
setState(() {});
}
#override
Widget build(BuildContext context) {
var color = 0xff453658;
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff392850),
title: Row(
children: [
InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back)),
SizedBox(
width: 10.0,
),
Text(
"Income",
style: TextStyle(fontStyle: FontStyle.italic),
),
],
),
actions: [
IconButton(
icon: Icon(Icons.person),
onPressed: () => print("open cart"),
),
],
),
body: Column(
children: [
Container(
margin: const EdgeInsets.all(20.0),
padding: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
border: Border.all(width: 2, color: Color(color))),
child: Row(
children: [
Text(
"Total Income:",
style: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic),
),
SizedBox(
width: 10.0,
),
Text(
"Rs.2000",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic),
),
],
),
),
SizedBox(
height: 20.0,
),
Flexible(
child: Container(
child: GridView.count(
childAspectRatio: 1.0,
padding: EdgeInsets.only(left: 16, right: 16),
crossAxisCount: 3,
crossAxisSpacing: 18,
mainAxisSpacing: 18,
children: List.generate(
teamApi.length,
(index) => GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
LeftTeam(teamData: teamApi[index])),
);
},
child: Container(
decoration: BoxDecoration(
color: Color(0xff00ffff),
borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(teamApi[index]["teamType"],
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600)),
),
],
),
),
),
),
),
),
),
],
),
);
}
}
This is API data of button
[{"teamType":"direct team","team_name":"platinum","team_number":"234","team_uniq_id":"1","team_last_update":"10-may-2021"},{"teamType":"left team","team_name":"gold","team_number":"356","team_uniq_id":"2","team_last_update":"10-may-2021"},{"teamType":"right team","team_name":"silver","team_number":"876","team_uniq_id":"3","team_last_update":"10-may-2021"}]
this is code for second file.
this is model part.
class MyData {
List<Results> user = [];
MyData.fromJson(Map<String, dynamic> json) {
// previous = json['previous'];
// next = json['next'];
if (json['results'] != null) {
user = <Results>[];
json['results'].forEach((v) {
user.add(new Results.fromJson(v));
});
}
}
}
class Results {
String user_name = "";
String user_mother_name = "";
String user_address = "";
String user_mobile = "";
String user_sponsor_id = "";
String sponsor_id = "";
String email = "";
String city = "";
String state = "";
String dob = "";
Results.fromJson(Map<String, dynamic> json) {
user_name = json['user_name'];
user_mother_name = json['user_mother_name'];
user_address = json['user_address'];
user_mobile = json['user_mobile'];
user_sponsor_id = json['user_sponsor_id'];
email = json['email'];
city = json['city'];
state = json['state'];
dob = json['dob'];
}
}
this provider of api link.
import 'dart:convert';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:practice/LeftTeamFile/model/myData.dart';
class MyHomePageProvider extends ChangeNotifier {
MyData? data;
Future getData(context) async {
var url = Uri.parse(
var url = Uri.parse('http://192.***.***.***/flutter/team_list.php');
var response = await http.get(url);
print("res${response.body}");
var mJson = json.decode(response.body);
this.data = MyData.fromJson(mJson);
this.notifyListeners();
this is teamList part .
import 'package:flutter/material.dart';
import 'package:practice/LeftTeamFile/provider/myHomePageProvider.dart';
import 'package:provider/provider.dart';
class TeamList extends StatefulWidget {
final teamData;
const TeamList({Key? key, this.teamData}) : super(key: key);
#override
_TeamListState createState() => _TeamListState();
}
class _TeamListState extends State<TeamList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
Container(
padding: EdgeInsets.all(10.0),
height: 100.0,
color: Color(0xffedbf6b),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
Icons.list_alt,
color: Colors.white,
),
Text(
widget.teamData['team_uniq_id'],
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
],
),
]),
),
SizedBox(
height: 10.0,
),
Stack(
children: [
ChangeNotifierProvider<MyHomePageProvider>(
create: (context) => MyHomePageProvider(),
child: Consumer<MyHomePageProvider>(
builder: (context, provider, child) {
if (provider.data!.team_uniq_id ==
widget.teamData['team_uniq_id']) {
print("prov $provider.data");
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
// Data table widget in not scrollable so we have to wrap it in a scroll view when we have a large data set..
child: SingleChildScrollView(
child: DataTable(
columns: [
DataColumn(
label: Text('Name'),
tooltip: 'represents if user is verified.'),
DataColumn(
label: Text('Mother_name'),
tooltip: 'represents first S no of the user'),
DataColumn(
label: Text('address'),
tooltip: 'represents Sponsor ID of the user'),
DataColumn(
label: Text('mobile'),
tooltip: 'represents User ID of the user'),
DataColumn(
label: Text('User_s_id'),
tooltip: 'represents Name of the user'),
DataColumn(
label: Text('sponsor_id'),
tooltip: 'represents Mobile of the user'),
DataColumn(
label: Text('email'),
tooltip: 'represents Date of the user'),
DataColumn(
label: Text('city'),
tooltip: 'represents Date of the user'),
DataColumn(
label: Text('state'),
tooltip: 'represents Date of the user'),
DataColumn(
label: Text('dob'),
tooltip: 'represents Date of the user'),
],
rows: provider.data!.user
.map((data) =>
// we return a DataRow every time
DataRow(
// List<DataCell> cells is required in every row
cells: [
red when unverified
DataCell(Text(data.user_name)),
DataCell(Text(data.user_mother_name)),
DataCell(Text(data.user_address)),
DataCell(Text(data.user_mobile)),
DataCell(Text(data.user_sponsor_id)),
DataCell(Text(data.sponsor_id)),
DataCell(Text(data.email)),
DataCell(Text(data.city)),
DataCell(Text(data.state)),
DataCell(Text(data.dob)),
]))
.toList(),
),
),
);
}, provider.getData(context);
return Center(child: CircularProgressIndicator());
),
),
],
),
],
),
);
}
}
this is teamlist api
[
{
"teamType": "direct Team",
"team_uniq_id": "1",
"user": [
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
}
]
},
{
"teamType": "left Team",
"team_uniq_id": "2",
"user": [
{
"user_name": "Ashu",
"user_mother_name": "manju",
"user_address": "Mirzapur",
"user_mobile": "222222",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "Ashutodh",
"user_mother_name": "manju1",
"user_address": "Mirzapur1",
"user_mobile": "2222221",
"user_sponsor_id": "1234561",
"sponsor_id": "34561",
"email": "abc#gmai.com1",
"city": "varanasi1",
"state": "India1",
"dob": "12-5-19961"
}
]
},
{
"teamType": "Right Team",
"team_uniq_id": "3",
"user": [
{
"user_name": "tosh",
"user_mother_name": "snju",
"user_address": "Allahabad",
"user_mobile": "44444444",
"user_sponsor_id": "333456",
"sponsor_id": "6666666",
"email": "jkl#gmai.com",
"city": "lucknow",
"state": "India",
"dob": "15-3-1956"
}
]
},
{
"teamType": "Total Team",
"team_uniq_id": "4",
"user": [
{
"user_name": "tosh",
"user_mother_name": "snju",
"user_address": "Allahabad",
"user_mobile": "44444444",
"user_sponsor_id": "333456",
"sponsor_id": "6666666",
"email": "jkl#gmai.com",
"city": "lucknow",
"state": "India",
"dob": "15-3-1956"
},
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "tosh",
"user_mother_name": "snju",
"user_address": "Allahabad",
"user_mobile": "44444444",
"user_sponsor_id": "333456",
"sponsor_id": "6666666",
"email": "jkl#gmai.com",
"city": "lucknow",
"state": "India",
"dob": "15-3-1956"
}
]
}
]
I feel some error is coming.
You can try to make sure you convert the object you are getting from the server to list, to be able to pass in the list into the widget

Convert data from an API to lists and use it in dependent Dropdownbuttons

I want to convert this API to multiable lists
it should act like the image below
https://i.stack.imgur.com/10Qld.png
Any help will be appreciated
I want to convert
1-categories.name toList
2-categories.children.name toList
3-categories.children.children_lv.name toList
4-categories.children.name.children_lv.children.name toList
and want to make every dropdown dependant to the previous one
Example:
the user should select from categories.name toList to be able to choose from 2-categories.children.name toList
API
"categories": [
{
"category_id": "1841",
"name": "Cars",
"children": [
{
"name": "Car1",
"category_id": "1845",
"children_lv": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
"column": "1",
{
"name": "Car2",
"category_id": "1846",
"children_lv": [
{
"name": "Car2_1",
"category_id": "1847",
"children_lv": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
},
{
"name": "Car2_2",
"category_id": "1848",
"children_lv": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
}
],
}
],
},
{
"category_id": "1842",
"name": "Properties",
"children": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
"column": "1",
},
{
"category_id": "1843",
"name": "Machines",
"children": [
{
"name": "",
"category_id": "",
"children_lv": "",
}
],
"column": "1",
},
{
"category_id": "1844",
"name": "Electronics",
"children": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
"column": "1",
}
]
}```
the lists that should be converted are category, children and the other children_lv
**Model has been made with app.quicktype.io and it works **
List<T> list = (map['list'] as List).map<T>((e)=>T.fromMap(e));
Try with this, but replace T with Model.
Also it should have fromMap function, to parse Map<String,dynamic> to your model.
else use normal constructors
((e)=>T(a:e['a'], b:e['b']);
Here is an example:
class Model {
final String a;
final String b;
Model({this.a,this.b});
factory Model.fromMap(Map<String,dynamic> map) =>
Model(
a: map['a'],
b: map['b']
);
}
This is a model with fromMap function. You can get that function easy with plugins for AndroidStudio or VSCode.
The one I use for android studio is called DartDataClass.
Now when you have json with lists =>
{ list : [
{ "a":"we","b":"try"},
{ "a":"as","b":"dfg"},
]}
You can use code above to parse that JSON if you have create the model for it.
Map<String,dynamic> json = jsonDecode(jsonSource);
List<Model> list = (json['list'] as List).map<Model>((e)=>Model.fromMap(e)).toList();
I did an example, the same as your example, but changed some names to make it clear to you
First, you need to create the Classes that you need like this:
Example of only one class ***** the same thing applies to the other classes *****
myCategory.dart
import 'package:flutterapp/myCategory1.dart';
import 'package:json_annotation/json_annotation.dart';
part 'myCategory.g.dart';
#JsonSerializable()
class MyCategory {
String name;
List<MyCategory1> children1;
MyCategory({this.name,this.children1});
factory MyCategory.fromJson(Map<String, dynamic> json) =>
_$MyCategoryFromJson(json);
Map<String, dynamic> toJson() => _$MyCategoryToJson(this);
}
myCategory.g.dart
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'myCategory.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
MyCategory _$MyCategoryFromJson(Map<String, dynamic> json) {
return MyCategory(
name: json['name'] as String,
children1: (json['children1'] as List)
?.map((e) => e == null
? null
: MyCategory1.fromJson(e as Map<String, dynamic>))
?.toList());
}
Map<String, dynamic> _$MyCategoryToJson(MyCategory instance) =>
<String, dynamic>{'name': instance.name, 'children1': instance.children1};
the myCategory.g.dart is generic file by json_serializable,
pubspec.yaml
dependencies:
flutter:
sdk: flutter
json_serializable: ^3.4.1
dev_dependencies:
build_runner: ^1.10.0
Where I generate it with the following command
flutter pub run build_runner build --delete-conflicting-outputs
Of course, you can use another method, but I prefer this method
Now let's take a look at the most important thing:
class CategoriesWidget extends StatefulWidget {
#override
_CategoriesWidgetState createState() => new _CategoriesWidgetState();
}
class _CategoriesWidgetState extends State<CategoriesWidget> {
List<MyCategory> myNestedList;
MyCategory _selectedMyCategory;
MyCategory1 _selectedMyCategory1;
MyCategory2 _selectedMyCategory2;
#override
void initState() {
super.initState();
myNestedList =
(map['categories'] as List).map((e) => MyCategory.fromJson(e)).toList();
}
Map<String, dynamic> map = {
'categories': [
{
"name": '1',
"children1": [
{"name": '1-1'},
{
"name": '1-2',
'children2': [
{'name': '1-2-1'},
{'name': '1-2-2'}
]
}
]
},
{
"name": '2',
"children1": [
{"name": '2-1'},
{
"name": '2-2',
'children2': [
{'name': '2-2-1'},
{'name': '2-2-2'}
]
}
]
}
]
};
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(
title: Text("Dropdown Categories"),
centerTitle: true,
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.grey, width: 0.5)),
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
margin: EdgeInsets.all(8),
child: DropdownButton(
isDense: true,
isExpanded: true,
hint: Text('My categories'),
underline: Container(),
items: myNestedList.map((item) {
return DropdownMenuItem(
value: item,
child: Text(item.name),
);
}).toList(),
value: _selectedMyCategory,
onChanged: (value) {
setState(() {
_selectedMyCategory = value;
if (_selectedMyCategory1 != null) {
_selectedMyCategory1 = _selectedMyCategory.children1
.firstWhere(
(element) => element == _selectedMyCategory1,
orElse: () => null);
}
});
},
),
),
_selectedMyCategory?.children1 != null &&
_selectedMyCategory.children1.length > 0
? Container(
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.grey, width: 0.5)),
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
margin: EdgeInsets.all(8),
child: DropdownButton(
isDense: true,
isExpanded: true,
hint: Text('My categories 1'),
underline: Container(),
value: _selectedMyCategory1,
items: _selectedMyCategory.children1.map((item) {
return DropdownMenuItem(
value: item,
child: Text(item.name),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedMyCategory1 = value;
if (_selectedMyCategory2 != null) {
_selectedMyCategory2 =
_selectedMyCategory1.children2.firstWhere(
(element) =>
element == _selectedMyCategory2,
orElse: () => null);
}
});
},
),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text('My categories 1')),
),
_selectedMyCategory1?.children2 != null &&
_selectedMyCategory1.children2.length > 0
? Container(
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.grey, width: 0.5)),
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
margin: EdgeInsets.all(8),
child: DropdownButton(
isDense: true,
isExpanded: true,
hint: Text('My categories 2'),
underline: Container(),
items: _selectedMyCategory1.children2.map((item) {
return DropdownMenuItem(
value: item,
child: Text(item.name),
);
}).toList(),
value: _selectedMyCategory2,
onChanged: (value) {
setState(() {
_selectedMyCategory2 = value;
});
},
),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text('My categories 2')),
),
],
),
),
);
}
}
I tried it myself, and here is the result:
Good luck

Filter Items In GridView With Tab Bar

I have a Listview that contains a Gridview and I'm trying to filter the results based on the list headers in the list view but can't seems to make it work.
When I tap a tab button, I want the grid view to only show products that has the matching attribute. This is what my app looks like for reference:
EDIT 1: _changedDropDownItem
void _changedDropDownItem(int newValue) {
setState(() {
_selectedCustomerType = newValue;
});
makeDropdown(newValue);
print(_selectedCustomerType);
}
void makeDropdown(filterNumb) {
if (filterNumb == 0) {
_dropdownList = _all;
} else if (filterNumb == 1) {
_dropdownList = _feeling;
} else if (filterNumb == 2) {
_dropdownList = _productType;
} else if (filterNumb == 3) {
_dropdownList = _filter;
}
// _sortTabs(filterNumb, _filterCat, _productTabFilter, _dropdownList);
print(_dropdownList);
}
The Headers for each tab are as followed:
List _all = ['All'];
List _feeling = [
'Creativity',
'Energetic',
'Euphoric',
'Focused',
'Giggly',
'Happy',
'Hungry',
'Relaxed',
'Sleepy',
'Sexy Time',
'Talkative',
'Tingly',
'Uplifted',
];
List _productType = [
'Flower',
'Concentrates',
'Dabs',
'For Pets',
'Storage',
'Topical',
'Vaping',
'Home Setup',
'Edibles',
'Pre-Rolled',
'Bongs & Pipes',
];
List _usage = [
'Headache',
'Insomnia',
'Being Social',
'First Timers',
'Cramps\n & Pains',
'Body Pains',
'Stress and\n Tension',
'Creativity',
'Productivity',
'Accessory',
];
List _filter = [
'Headache',
'Insomnia',
'Being Social',
'First Timers',
'Cramps\n & Pains',
'Body Pains',
'Stress and\n Tension',
'Creativity',
'Productivity',
'Accessory',
];
Creating The ListView
Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: _dropdownList.length,
shrinkWrap: true,
itemBuilder: (context, _tabIndex) {
return Container(child: _buildProduct(context, _tabIndex));
},
Edit 2: JSON Data:
{
"product": [
{
"id": 28,
"name": "Blueberry Waltz",
"short_description": "Blue Frost is a hybrid that balances the genetics of Blue Monster and Jack Frost to create a 60/40 indica-dominant cross. Breeder Goldenseed has developed this strain to produce dense buds that show a range of deep violet hues and produces a pungent mixture of aromas. The flavor is an interesting combination of sweet fruity notes with a sharp cheese-like undertone. This hybrid is sure to lift your mood and replace any stress you may have with smile on your face.",
"usage": "First Timers",
"effect": "Energetic",
"quantity": 20,
"sizes": [
{
"id": 57,
"size": 3,
"product_id": 28,
"price": 25.0
},
{
"id": 58,
"size": 4,
"product_id": 28,
"price": 50.0
}
],
"image": "https://dispensaries.s3.amazonaws.com/product_images/grams.png",
"image2": "https://dispensaries.s3.amazonaws.com/product_images/blueberry-waltz-1.jpg",
"image3": "https://dispensaries.s3.amazonaws.com/product_images/GRAND-DADDY-PURPLE.jpg",
"Product_Type": "Carry Case",
"Product_Category": "Pets",
"thc_content": 92.0,
"cbd_content": 0.0
},
{
"id": 27,
"name": "Pink Champagne",
"short_description": "Wrawer",
"usage": "First Timers",
"effect": "Creative",
"quantity": 9,
"sizes": [
{
"id": 56,
"size": 2,
"product_id": 27,
"price": 29.99
}
],
"image": "https://dispensaries.s3.amazonaws.com/product_images/char.png",
"image2": "https://dispensaries.s3.amazonaws.com/product_images/Pink_Champagne_A3pza9w.jpeg",
"image3": "https://dispensaries.s3.amazonaws.com/product_images/Pink_Champagne_V65X8hn.jpeg",
"Product_Type": "Cartridge",
"Product_Category": "Storage",
"thc_content": 23.2,
"cbd_content": 20.0
}
{
"id": 29,
"name": "test prod",
"short_description": "wassup",
"usage": "First Timers",
"effect": "Euphoric",
"quantity": 4,
"sizes": [
{
"id": 59,
"size": 3,
"product_id": 29,
"price": 29.99
}
],
"image": "https://dispensaries.s3.amazonaws.com/product_images/1_1.png",
"image2": "https://dispensaries.s3.amazonaws.com/product_images/2_1.png",
"image3": "https://dispensaries.s3.amazonaws.com/product_images/2.png",
"Product_Type": "indica",
"Product_Category": "Dabs",
"thc_content": 20.0,
"cbd_content": 0.0
}
]
}
Create the Product GridView with data
Widget _buildProduct(BuildContext context, _tabIndex) {
return Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0, top: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
_dropdownList[_tabIndex],
style: TextStyle(
fontFamily: 'Poppins',
color: buddiesPurple,
fontSize: 18),
),
],
),
),
SizedBox(
height: screenAwareSize(10, context),
),
Container(
// padding: EdgeInsets.only(top: 10.0),
// height: 350,
width: MediaQuery.of(context).size.width,
child: FutureBuilder(
future: _setProducts,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
break;
case ConnectionState.none:
break;
case ConnectionState.active:
break;
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
productList = snapshot.data;
_productTabFilter = snapshot.data;
break;
}
return GridView.builder(
itemCount: _productTabFilter.length,
controller: ScrollController(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 20,
childAspectRatio: 0.7),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, i) {
return InkWell(
onTap: () {
currentRes = restaurant;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SelectedProduct(
restaurant: restaurant,
product: _productTabFilter[i],
)));
},
child: Stack(children: <Widget>[
_buildProductList(
_productTabFilter[i].name,
_productTabFilter[i].image2,
_productTabFilter[i].usage,
_productTabFilter[i].effect,
_productTabFilter[i].productType,
'${_productTabFilter[i].sizes[0].price.toStringAsFixed(2)}',
_productTabFilter[i].quantity)
]),
);
},
);
},
))
])));
}
This is my drop down that will contain the header names:
//Drop down
String _filterDropdown;
List _dropdownList = [];
List<DropdownMenuItem<String>> _dropDownMenuItems;
List<DropdownMenuItem<String>> buildAndGetDropDownMenuItems(List tempList) {
List<DropdownMenuItem<String>> items = List();
for (String x in tempList) {
items.add(DropdownMenuItem(
value: x,
child: Text(
x,
style: TextStyle(
fontSize: 14,
fontFamily: 'Roboto-Regular',
fontWeight: FontWeight.w700,
color: bPurple),
)));
}
return items;
}
And the tab bar that when tapped changes all of the headers to the next category
TabBar(
onTap: _changedDropDownItem,
indicatorColor: bGreen,
labelColor: bPurple,
unselectedLabelColor: Colors.grey,
// isScrollable: true,
tabs: [
Tab(
icon: Icon(FontAwesomeIcons.medkit),
text: "Recovery"),
Tab(icon: Icon(FontAwesomeIcons.heart), text: "Feels"),
Tab(icon: Icon(Icons.info), text: "Product"),
Tab(
icon: Icon(FontAwesomeIcons.home),
text: "More",
),
],
),
Please try this first:
void _changedDropDownItem(int newValue) {
setState(() {
makeDropdown(newValue);
_selectedCustomerType = newValue;
});
// makeDropdown(newValue);
print(_selectedCustomerType);
}