Flutter: dropdown with custom map - flutter

I have a list of maps list this:
var taxesGroups = [
{
"name": "Spain",
"taxes": [
{"name": "IVA", "percentage": "21"},
{"name": "IRPF", "percentage": "19"},
]
},
{
"name": "UK",
"taxes": [
{"name": "VAT", "percentage": "20"},
]
}
];
var dropdownValue = taxesGroups[0]["name"];
So far I tried this:
DropdownButton(
value: dropdownValue,
items: taxesGroups.map((taxGroup) {
return DropdownMenuItem<String>(
value: taxGroup["name"],
child: Text(taxGroup["name"]),
);
}).toList(),
onChanged: (taxGroup) {
setState(() {
dropdownValue = taxGroup;
});
},
),
I get this error:
type 'List' is not a subtype of type
'List<DropdownMenuItem>'
I guess it's related to the info I want to display in the dropdown (Spain, UK) and what I get when choose an option but I don't figure it out

You have mismatched the taxesGroups map.
I tried to recreate your use case with this and it works.
class MyApp2 extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp2> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var taxesGroups = [
{
"name": "Spain",
"taxes": [
{"name": "IVA", "percentage": "21"},
{"name": "IRPF", "percentage": "19"},
]
},
{
"name": "UK",
"taxes": [
{"name": "VAT", "percentage": "20"},
]
}
];
var dropdownValue;
#override
void initState() {
dropdownValue = taxesGroups[0];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("AppBar"),
),
body: DropdownButton(
value: dropdownValue['name'],
items: taxesGroups.map((taxGroup) {
return DropdownMenuItem<String>(
value: taxGroup["name"],
child: Text(taxGroup["name"]),
);
}).toList(),
onChanged: (taxGroup) {
print('taxGroup $taxGroup');
taxesGroups.map((e) {
if (e["name"] == taxGroup)
setState(() {
dropdownValue = e;
});
});
},
),
);
}
}

Add type as DropownMenuItem for map
DropdownButton(
value: dropdownValue,
items: taxesGroups.map<DropdownMenuItem>((taxGroup) {
return DropdownMenuItem<String>(
value: taxGroup["name"],
child: Text(taxGroup["name"]),
);
}).toList(),
onChanged: (taxGroup) {
setState(() {
dropdownValue = taxGroup;
});
},
),

Related

How to add a label inside the dropdown item with list inside the list (FLUTTER)

List<Map<String, dynamic>> category = [
{
"name": "One",
"detail": ['1', '1', '1', '1', '1', '1']
},
{
"name": "two",
"detail": ['2', '2', '2', '2', '2', '2']
},
{
"name": "three",
"detail": ['3', '3', '3', '3', '3', '3']
},
];
I want to add the name as the label in dropdown item, and the detail as the item. For example, as showing in the picture
The bold text should be the "name", the normal text will be the detail items
This can give you an idea of how to possibly do it:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final List<Map<String, dynamic>> category = [
{
"name": "One",
"detail": ['11', '12', '13', '14']
},
{
"name": "two",
"detail": ['21', '22', '23', '24']
},
{
"name": "three",
"detail": ['31', '32', '33', '34']
},
];
late final List data;
String? selectedItem;
#override
void initState() {
data = [
for (final item in category)
for (final value in item.values)
if (value is List)
for (final listValue in value) {'value': listValue, 'bold': false}
else
{'value': value, 'bold': true}
];
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: DropdownButton<String>(
value: selectedItem,
items: [
for (final item in data)
item['bold'] == true
? DropdownMenuItem(
enabled: false,
child: Text(item['value'],
style: const TextStyle(
fontWeight: FontWeight.bold)))
: DropdownMenuItem(
value: item['value'],
child: Padding(
padding: const EdgeInsets.only(left: 8),
child: Text(item['value']),
))
],
onChanged: (value) {
setState(() {
selectedItem = value;
});
}))));
}
}
Output:
In the initState I transform the data in a way so you have a list where each item corresponds to a dropdown item. With additional info whether it should be bold or not

Flutter Lazy loading on Listview inside another Listview

How to apply Lazy Loading or other better option to load more than 5000 of topping list in the Listview.builder inside another Listview.builder?
Below is post.json which will be loaded from local assets
{
"Food": [
{
"name": "Cake",
"id": "0001",
"description": [
{
"category": "AAA",
"Size": "Regular",
"topping": []
},
{
"category": "BBB",
"Size": "Small",
"topping": []
},
{
"category": "CCC",
"Size": "Medium",
"topping": [
{
"ingredient": "Chocolate with Sprinkles",
"price": "$70"
},
{
"ingredient": "Maple",
"price": "$99"
},
{
"ingredient": "Blueberry",
"price": "$123"
}, ... // more than 5000 of topping list
]
}
]
},
{
"name": "Raised",
"id": "0002",
"description": ... // same structure as above
}
]
}
Below is the Main file to display List of foods
void main() {
runApp(const MyApp());
}
// Load local Json file
Future<Post> getFoodList() => Future.delayed(Duration(seconds: 1), () async {
final getResponse = await rootBundle.loadString('assets/post.json');
var data = jsonDecode(getResponse);
return Post.fromJson(data);
});
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: FutureBuilder<Post>(
future: getFoodList(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var getFoodName = snapshot.data!.food;
return SingleChildScrollView(
child: Wrap(
children: [
for (final food in getFoodName!)
GestureDetector(
child: Text(foodName.name.toString()),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => foodDetail(food: food)));
},
),
],
),
);
} else {
return Text('Loading');
}
},
),
),
],
),
);
}
}
Food Detail page - display more than 5000 of topping list
class FoodDetail extends StatefulWidget {
final Food food;
const FoodDetail({super.key, required this.food});
#override
State<FoodDetail> createState() => _FoodDetailState();
}
class _FoodDetailState extends State<FoodDetail> {
late ScrollController controller;
// This example is taken from Flutter ListView lazy loading
List<String> items = List.generate(100, (position) => 'Hello $position');
#override
void initState() {
super.initState();
controller = ScrollController()..addListener(_scrollListener);
}
#override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
children: [
// This is the first ListView.build to display category and size under description
ListView.builder(
itemCount: widget.food.description!.length,
itemBuilder: (context, index) {
// IF category is AAA || BBB, display the size
if (widget.food.description![index].category == "AAA" || widget.food.description![index].category == "BBB") {
return Text(widget.food.description![index].size.toString());
}
// IF category is CCC display the List of Topping (Note: this topping list is more than 5000)
else {
// This is the second ListView.build to display the topping information
// How do I apply ScollController or Lazy Loading to load 5000 list of topping?
return ListView.builder(
controller: controller,
itemCount: widget.food.description![index].topping!.length,
itemBuilder: (context, position) {
return Column(
children: [
Text(widget.food.description![index].topping![position].ingredient.toString())
Text(widget.food.description![index].topping![position].price.toString())
],
);
});
}
}),
],
),
)));
}
// This example is taken from Flutter ListView lazy loading
void _scrollListener() {
if (controller.position.extentAfter < 500) {
setState(() {
items.addAll(List.generate(42, (index) => 'Inserted $index'));
});
}
}
}
Output of the workflow:
I think your best bet is to try to try to refactor it in a way to use only a single ListView.builder. To do this you need to flatten the data you are working with in some way. Here is an example that also uses nested data that transforms it in a way so a single ListView displays it. I'm not sure if it's the best way to do it but I think you could do something similar for your code maybe. This might give you an idea of how to do it:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
final data = const [
{
"name": "A",
"subnames": ["A1", "A2", "A3", "A4", "A5"]
},
{
"name": "B",
"subnames": ["B1", "B2", "B3", "B4", "B5"]
},
{
"name": "C",
"subnames": ["C1", "C2", "C3", "C4", "C5"]
},
];
const MyApp({super.key});
#override
Widget build(BuildContext context) {
final newData = data
.map((e) => [
{"type": 1, "name": e["name"]},
for (final name in (e["subnames"] as List))
{"type": 2, "name": name}
])
.expand((e) => e.toList())
.toList();
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: newData.length,
itemBuilder: (context, index) {
if (newData[index]['type'] == 1) {
return Text(
newData[index]['name'],
style: const TextStyle(color: Colors.red),
);
} else {
return Text(
newData[index]['name'],
style: const TextStyle(color: Colors.blue),
);
}
}),
)),
);
}
}
Output:

Flutter Dropdown with sqllite

Good noon every one i want to ask on how to put a dropdown onchanged i am using sqllite for my database.
edit_note_page.dart
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
actions: [buildButton()],
),
body: Form(
key: _formKey,
child: NoteFormWidget(
category: category,
onChangedCategory: (category) => setState(() => this.category = category),
),
),
);
note_form_widget.dart
Widget buildCategory() => DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
items: <String>['A1', 'A2', 'A3', 'A4','A5','C1']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: category,
child: Text(value),
);
}).toList(), onChanged: (String? value)
{
setState(() {
dropdownValue = newValue!;//im getting an error on this part
});
},
Logs
error encounter
The method 'setState' isn't defined for the type 'NoteFormWidget'.
Try correcting the name to the name of an existing method, or defining a method named 'setState'.
[{
"resource": "/c:/Users/VIMS-SERVER/Documents/Flutter Projects/apps/lib/widget/note_form_widget.dart",
"owner": "_generated_diagnostic_collection_name_#0",
"code": {
"value": "undefined_identifier",
"target": {
"$mid": 1,
"external": "https://dart.dev/diagnostics/undefined_identifier",
"path": "/diagnostics/undefined_identifier",
"scheme": "https",
"authority": "dart.dev"
}
},
"severity": 8,
"message": "Undefined name 'dropdownValue'.\nTry correcting the name to one that is defined, or defining the name.",
"source": "dart",
"startLineNumber": 229,
"startColumn": 11,
"endLineNumber": 229,
"endColumn": 24
}]
[{
"resource": "/c:/Users/VIMS-SERVER/Documents/Flutter Projects/apps/lib/widget/note_form_widget.dart",
"owner": "_generated_diagnostic_collection_name_#0",
"code": {
"value": "undefined_identifier",
"target": {
"$mid": 1,
"external": "https://dart.dev/diagnostics/undefined_identifier",
"path": "/diagnostics/undefined_identifier",
"scheme": "https",
"authority": "dart.dev"
}
},
"message": "Undefined name 'newValue'.\nTry correcting the name to one that is defined, or defining the name.",
}]
The setState method doesn't work on StatelessWidget because StatelessWidget doesn't have a state. Only StatefulWidget has a state, and therefore only it has a setState.
So you most turn your StatelessWidget to StatefulWidget.
I think your note_widget is stateless so you change to the stateful widget. you cant use a set state callback on the stateless widget.Dartpad live check here.you can use another state management tool(Provider ,cubit,riverport,bloc) to update your value
DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
items: <String>['A1', 'A2', 'A3', 'A4', 'A5', 'C1']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
value: dropdownvalu,
onChanged: (values) {
setState(() {
dropdownvalu = values.toString();
});
},
)
Widget
class _ParentState extends State<Parent> {
Widget build(context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
setState(() {
counter++;
});
},
icon: const Icon(Icons.add),
),
],
),
body: Column(
children: [
DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
items: <String>['A1', 'A2', 'A3', 'A4', 'A5', 'C1']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
value: dropdownvalu,
onChanged: (values) {
setState(() {
dropdownvalu = values.toString();
});
},
),
Center(
child: Text(
"$dropdownvalu",
style: TextStyle(fontSize: 30),
)),
],
),
);
}
}
SampleCode
import 'package:flutter/material.dart';
//import 'package:pucon/home.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Parent(),
);
}
}
class Parent extends StatefulWidget {
#override
State<Parent> createState() => _ParentState();
}
String dropdownvalu = "A1";
class _ParentState extends State<Parent> {
Widget build(context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
setState(() {
counter++;
});
},
icon: const Icon(Icons.add),
),
],
),
body: Column(
children: [
DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
items: <String>['A1', 'A2', 'A3', 'A4', 'A5', 'C1']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
value: dropdownvalu,
onChanged: (values) {
setState(() {
dropdownvalu = values.toString();
});
},
),
Center(
child: Text(
"$dropdownvalu",
style: TextStyle(fontSize: 30),
)),
],
),
);
}
}
int counter = 0;
class Child extends StatefulWidget {
Child({Key? key}) : super(key: key);
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
#override
Widget build(BuildContext context) {
return Center(
child: Text(
"$dropdownvalu",
style: TextStyle(fontSize: 30),
));
} //to be incremented when the parent's button is clicked on.
}
// dbHelper
Future<List> getEmployeeData() async {
try {
final dbClient = await db;
var l = await dbClient!.transaction(
(txn) async => txn.rawQuery("SELECT * FROM ${DbConstants.tblGloEmployeeMaster} where is_active = 1"),
);
return l;
} catch (e) {
return [];
}
}
// getx
// login controller
// init
final employeeModelList = List<EmployeeModel>.empty(growable: true).obs;
// create method
void _getEmployees() async {
List list = await _dbHelper.getEmployeeData();
employeeModelList.value = [];
employeeModelList.value = list.map((employeeModel) => EmployeeModel.fromJson(employeeModel)).toList();
}
// create model
class EmployeeModel {
EmployeeModel({
required this.employeeId,
required this.employeeNm,
});
late final int employeeId;
late final String employeeNm;
EmployeeModel.fromJson(Map<String, dynamic> json) {
employeeId = json['employee_id'];
employeeNm = json['employee_nm'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['employee_id'] = employeeId;
_data['employee_nm'] = employeeNm;
return _data;
}
}
// stateless widget
// call
Container(
child: _searchEmployee(context),
),
// method
Widget _searchEmployee(BuildContext context) {
return Obx(
() => CustomSearchableDropDown(
items: _loginController.employeeModelList,
label: Strings.selectEmployee,
labelStyle: Theme.of(context).textTheme.bodyText1!.merge(TextStyles.defaultRegular),
dropdownLabelStyle: Theme.of(context).textTheme.bodyText1!.merge(TextStyles.defaultRegular),
dropDownMenuItems: _loginController.employeeModelList.map((item) {
return "${item.employeeId} - ${item.employeeNm}"; // ui view
}).toList(),
suffixIcon:
Icon(Icons.arrow_drop_down, size: Sizes.s16, color: Get.isDarkMode ? AppColors.white : AppColors.black),
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: AppColors.fontGray))),
onChanged: (value) {
if (value != null) {
EmployeeModel employeeModel = value;
_loginController.employeeId.value = int.parse(employeeModel.employeeId);
_loginController.employeeName.value = employeeModel.employeeNm;
}
},
),
);
}

Flutter: RangeError (index): Invalid value: Valid value range is empty: -1

I have 2 JSON file like this:
json1 (API):
[
{
"json1Language": "English",
"json1Icon": "https://www.countryflags.io/gb/flat/64.png",
"json1Code": "en"
},
{
"json1Language": "French",
"json1Icon": "https://www.countryflags.io/fr/flat/64.png",
"json1Code": "fr"
},
{
"json1Language": "Spanish",
"json1Icon": "https://www.countryflags.io/es/flat/64.png",
"json1Code": "es"
}
]
json2 (API):
[
{
"json2Country": "Canada",
"json2Continent": "North American",
"json2Language": [
"French",
"English"
]
},
{
"json2Country": "Mexico",
"json2Continent": "North American",
"json2Language": [
"Spanish",
"English"
]
},
{
"json2Country": "United Kingdom",
"json2Continent": "Europe",
"json2Language": [
"English"
]
},
{
"json2Country": "France",
"json2Continent": "Europe",
"json2Language": [
"French"
]
},
{
"json2Country": "Spain",
"json2Continent": "Europe",
"json2Language": [
"Spanish"
]
}
]
I tried to show the data of json1Code from Json1, it shows an error Flutter: RangeError (index): Invalid value: Valid value range is empty: -1 for a few seconds then shows the data correctly, I'm not sure where I did wrong
I think maybe something wrong in the Build class:
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following RangeError was thrown building Builder(dirty):
RangeError (index): Invalid value: Valid value range is empty: -1
The relevant error-causing widget was:
Builder file:///D:/Flutter/Test/load_data/lib/json2_page3.dart:80:17
When the exception was thrown, this was the stack:
#0 List.[] (dart:core-patch/growable_array.dart:177:60)
#1 _ShowContinentState.build.<anonymous closure> (package:load_data/json2_page3.dart:83:38)
#2 Builder.build (package:flutter/src/widgets/basic.dart:7183:48)
#3 StatelessElement.build (package:flutter/src/widgets/framework.dart:4644:28)
#4 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4570:15)
please help me, this is main file
import 'package:flutter/material.dart';
import 'package:load_data/model/json2_model.dart';
import 'package:load_data/service/json1_service.dart';
import 'package:load_data/service/json2_service.dart';
import 'model/json1_model.dart';
class Json2Page3 extends StatefulWidget {
#override
_Json2Page3State createState() => _Json2Page3State();
}
class _Json2Page3State extends State<Json2Page3> {
List<Json2> json2 = [];
List<String> _continent = [];
#override
void initState() {
super.initState();
setState(() {
Json2Services.getData().then((data) {
setState(() {
json2 = data;
_continent = json2.map<String>((x) => x.json2Continent).toSet().toList();
});
});
});
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: _continent.length,
child: Scaffold(
appBar: AppBar(
title: Text('Page 2'),
bottom: TabBar(tabs: _continent.map((String name) => Tab(text: name)).toList()),
),
body: TabBarView(
children: _continent.map((String name) {
return ShowContinent(
json2: List<Json2>.from(json2)..retainWhere((e) => e.json2Continent == name),
);
}).toList()),
));
}
}
class ShowContinent extends StatefulWidget {
final List<Json2> json2;
ShowContinent({this.json2});
#override
_ShowContinentState createState() => _ShowContinentState(json2);
}
class _ShowContinentState extends State<ShowContinent> {
final List<Json2> json2;
List<Json1> json1 = [];
_ShowContinentState(this.json2);
#override
void initState() {
super.initState();
Json1Services.getData().then((data) {
setState(() {
json1 = data;
});
});
}
#override
Widget build(BuildContext context) {
return Column(
children: [
for (Json2 j2 in json2)
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(j2.json2Country.toUpperCase()),
for (int i = 0; i < j2.json2Language.length; i++)
Builder(
builder: (_) {
int index = json1.indexWhere((e) => e.json1Language == j2.json2Language[i]);
return Row(
children: [
Image.network(json1[index].json1Icon),
Text(json1[index].json1Code),
],
);
},
)
],
),
],
);
}
}
You can copy paste run full code below
You can use addPostFrameCallback and bool isLoading to check loading status
when isLoading == true, return CircularProgressIndicator()
code snippet
bool isLoading = true;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
Json1Services.getData().then((data) {
setState(() {
json1 = data;
isLoading = false;
});
});
});
}
#override
Widget build(BuildContext context) {
return isLoading
? Center(child: CircularProgressIndicator())
: Column(
working demo
full code
import 'package:flutter/material.dart';
import 'dart:convert';
List<Json2> json2FromJson(String str) =>
List<Json2>.from(json.decode(str).map((x) => Json2.fromJson(x)));
String json2ToJson(List<Json2> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
List<Json1> json1FromJson(String str) =>
List<Json1>.from(json.decode(str).map((x) => Json1.fromJson(x)));
String json1ToJson(List<Json1> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Json1 {
Json1({
this.json1Language,
this.json1Icon,
this.json1Code,
});
String json1Language;
String json1Icon;
String json1Code;
factory Json1.fromJson(Map<String, dynamic> json) => Json1(
json1Language: json["json1Language"],
json1Icon: json["json1Icon"],
json1Code: json["json1Code"],
);
Map<String, dynamic> toJson() => {
"json1Language": json1Language,
"json1Icon": json1Icon,
"json1Code": json1Code,
};
}
class Json2 {
Json2({
this.json2Country,
this.json2Continent,
this.json2Language,
});
String json2Country;
String json2Continent;
List<String> json2Language;
factory Json2.fromJson(Map<String, dynamic> json) => Json2(
json2Country: json["json2Country"],
json2Continent: json["json2Continent"],
json2Language: List<String>.from(json["json2Language"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"json2Country": json2Country,
"json2Continent": json2Continent,
"json2Language": List<dynamic>.from(json2Language.map((x) => x)),
};
}
class Json2Services {
static Future<List<Json2>> getData() async {
await Future.delayed(Duration(seconds: 5), () {});
String jsonString = '''
[
{
"json2Country": "Canada",
"json2Continent": "North American",
"json2Language": [
"French",
"English"
]
},
{
"json2Country": "Mexico",
"json2Continent": "North American",
"json2Language": [
"Spanish",
"English"
]
},
{
"json2Country": "United Kingdom",
"json2Continent": "Europe",
"json2Language": [
"English"
]
},
{
"json2Country": "France",
"json2Continent": "Europe",
"json2Language": [
"French"
]
},
{
"json2Country": "Spain",
"json2Continent": "Europe",
"json2Language": [
"Spanish"
]
}
]
''';
return Future.value(json2FromJson(jsonString));
}
}
class Json1Services {
static Future<List<Json1>> getData() async {
await Future.delayed(Duration(seconds: 5), () {});
String jsonString = '''
[
{
"json1Language": "English",
"json1Icon": "https://www.countryflags.io/gb/flat/64.png",
"json1Code": "en"
},
{
"json1Language": "French",
"json1Icon": "https://www.countryflags.io/fr/flat/64.png",
"json1Code": "fr"
},
{
"json1Language": "Spanish",
"json1Icon": "https://www.countryflags.io/es/flat/64.png",
"json1Code": "es"
}
]
''';
return Future.value(json1FromJson(jsonString));
}
}
class Json2Page3 extends StatefulWidget {
#override
_Json2Page3State createState() => _Json2Page3State();
}
class _Json2Page3State extends State<Json2Page3> {
List<Json2> json2 = [];
List<String> _continent = [];
#override
void initState() {
super.initState();
setState(() {
Json2Services.getData().then((data) {
setState(() {
json2 = data;
_continent =
json2.map<String>((x) => x.json2Continent).toSet().toList();
});
});
});
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: _continent.length,
child: Scaffold(
appBar: AppBar(
title: Text('Page 2'),
bottom: TabBar(
tabs:
_continent.map((String name) => Tab(text: name)).toList()),
),
body: TabBarView(
children: _continent.map((String name) {
return ShowContinent(
json2: List<Json2>.from(json2)
..retainWhere((e) => e.json2Continent == name),
);
}).toList()),
));
}
}
class ShowContinent extends StatefulWidget {
final List<Json2> json2;
ShowContinent({this.json2});
#override
_ShowContinentState createState() => _ShowContinentState(json2);
}
class _ShowContinentState extends State<ShowContinent> {
final List<Json2> json2;
List<Json1> json1 = [];
_ShowContinentState(this.json2);
bool isLoading = true;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
Json1Services.getData().then((data) {
setState(() {
json1 = data;
isLoading = false;
});
});
});
}
#override
Widget build(BuildContext context) {
return isLoading
? Center(child: CircularProgressIndicator())
: Column(
children: [
for (Json2 j2 in json2)
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(j2.json2Country.toUpperCase()),
for (int i = 0; i < j2.json2Language.length; i++)
Builder(
builder: (_) {
int index = json1.indexWhere(
(e) => e.json1Language == j2.json2Language[i]);
return Row(
children: [
Image.network(json1[index].json1Icon),
Text(json1[index].json1Code),
],
);
},
)
],
),
],
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Json2Page3(),
);
}
}
When build() is called, json data is not ready.
So you need to fix code asynchronous.
I suggest one solution 'FutureBuilder'
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

flutter: how to populate a dropdown box from an list of of object [duplicate]

How do I populate this JSON list into dropdown button?
{
"status": true,
"message": "success",
"data": {
"list": [
{
"idattribute": "2",
"attrName": "BBQ"
},
{
"idattribute": "1",
"attrName": "FRUIT JUICE"
}
]
}
}
class _YourPageState extends State<YourPage> {
Map yourJson = {
"status": true,
"message": "success",
"data": {
"list": [
{"idattribute": "2", "attrName": "BBQ"},
{"idattribute": "1", "attrName": "FRUIT JUICE"}
]
}
};
int _value = 1;
List<DropdownMenuItem<int>> _menuItems;
#override
void initState() {
super.initState();
List dataList = yourJson["data"]["list"];
_menuItems = List.generate(
dataList.length,
(i) => DropdownMenuItem(
value: int.parse(dataList[i]["idattribute"]),
child: Text("${dataList[i]["attrName"]}"),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButton<int>(
items: _menuItems,
value: _value,
onChanged: (value) => setState(() => _value = value),
),
),
);
}
}