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
  }