Hello Flutter developers! I am trying to pull data from my API to display in a dropdown. I will actually have 2 different drop downs that require two different api calls. I am currently trying to get the first one to work, which is a list of products. In another place in my program, I am able to successfully receive the list of products. However I am just displaying them, not adding them to a dropdown. In that instance, I am able to use Future Builder, because it is the only call I am making in that part of the program. Here is my current code. When I get to this page, the page itself loads, but my list of products returns as empty when I try to print it to the console.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:gateway_device/flutter_flow/flutter_flow_theme.dart';
import 'package:gateway_device/models/products_list_model.dart';
import 'package:gateway_device/routes/route_helper.dart';
import 'package:gateway_device/utils/app_constants.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
class EditDevicePortWidget extends StatefulWidget {
final String deviceId;
final String portId;
final String publicId;
final String label;
final String portProduct;
const EditDevicePortWidget(
{Key? key,
required this.deviceId,
required this.portId,
required this.publicId,
required this.label,
required this.portProduct})
: super(key: key);
@override
State<EditDevicePortWidget> createState() => _EditDevicePortWidgetState(
deviceId, portId, publicId, label, portProduct);
}
class _EditDevicePortWidgetState extends State<EditDevicePortWidget> {
final String deviceId;
final String portId;
final String publicId;
final String label;
final String portProduct;
late String _selectedProduct = portProduct;
@override
void initState() {
_getProductList();
super.initState();
print(allProducts);
}
_EditDevicePortWidgetState(
this.deviceId, this.portId, this.publicId, this.label, this.portProduct);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(
publicId + ' - ' + label,
style: FlutterFlowTheme.of(context).bodyText1.override(
fontFamily: 'Heebo',
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
centerTitle: true,
elevation: 0,
backgroundColor: Colors.white,
automaticallyImplyLeading: false,
actions: [
IconButton(
hoverColor: Colors.transparent,
iconSize: 40,
icon: Icon(
Icons.close,
color: Colors.black,
size: 30,
),
onPressed: () {
Get.offNamed(RouteHelper.getPortProfile(
deviceId, portId, publicId, label));
},
),
],
iconTheme: IconThemeData(color: Colors.black),
),
body: SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height.h * 1,
decoration: BoxDecoration(color: Colors.white),
child: Column(
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [],
),
),
Divider(
height: 10.h,
thickness: 2.h,
color: Colors.black,
),
Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(10, 10, 0, 0),
child: Text(
'Product:',
style:
FlutterFlowTheme.of(context).bodyText1.override(
fontFamily: 'Heebo',
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
),
],
),
Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<String>(
value: _selectedProduct,
iconSize: 30,
icon: (null),
style:
TextStyle(color: Colors.black, fontSize: 16.sp),
hint: Text('Select Product'),
onChanged: (newValue) {
setState(() {
_selectedProduct = newValue!;
_getProductList();
print(_selectedProduct);
});
},
items: allProducts.map((item) {
return new DropdownMenuItem(
child: new Text(item.productName),
value: item.productId.toString(),
);
}).toList(),
),
),
)
],
),
],
)
],
),
),
),
);
}
List<TankProduct> allProducts = [];
Future<List<TankProduct>> _getProductList() async {
final allProductsUrl =
Uri.parse(AppConstants.BASE_URL + AppConstants.TANK_PRODUCTS_LIST_URI);
final response = await http.get(allProductsUrl, headers: {
'Authorization': 'Bearer ' + AppConstants.TOKEN,
'X-API-KEY': AppConstants.API_KEY
});
Map<String, dynamic> body = json.decode(response.body);
(body["tank_products"]).forEach((product) {
allProducts.add(TankProduct.fromJson(product));
});
return allProducts;
}
Solution 1: Suz Zan
You should use setState({}) once you set the data in allProducts to refresh the UI and reflect the data. You are not doing anything with the returned value, so you can make the return type as void
Example:
Future<void> _getProductList() async {
final allProductsUrl =
Uri.parse(AppConstants.BASE_URL + AppConstants.TANK_PRODUCTS_LIST_URI);
final response = await http.get(allProductsUrl, headers: {
'Authorization': 'Bearer ' + AppConstants.TOKEN,
'X-API-KEY': AppConstants.API_KEY
});
Map<String, dynamic> body = json.decode(response.body);
(body["tank_products"]).forEach((product) {
allProducts.add(TankProduct.fromJson(product));
});
setState({}); // reload the UI
}