3

Gere is my goal : I click add button then add dropdown button which its item is fetch from API.

Here is my problem :
I select dropdown value, but NO VALUE is selected.
I click add button, then previous value is filled on new added dropdown button.

Here is my code (full)

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class RepeatableSection extends StatefulWidget {
  @override
  _RepeatableSectionState createState() => _RepeatableSectionState();
}

class _RepeatableSectionState extends State<RepeatableSection> {
  List<Widget> extractedChildren = <Widget>[];
  int _index = 1;

  String _mySelection;
  List data = List();

  Future<void> fetchAPI() async {
    var url = "http://webmyls.com/php/getdata.php";
    Map<String, String> headers = {
      'Content-type': 'application/json',
      'Accept': 'application/json',
    };
    final response = await http.post(url, headers: headers);
    final responseJson = json.decode(response.body);

    if (response.statusCode == 200) {
      setState(() {
        data = responseJson;
      });
    } else {
      setState(() {});
      throw Exception('Failed to load internet');
    }
  }

  @override
  void initState() {
    this.fetchAPI();
  }

  Widget build(BuildContext context) {
    return Column(
      children: [
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: extractedChildren,
        ),
        RaisedButton(
          child: Text('Add'),
          onPressed: () {
            add();
          },
        ),
      ],
    );
  }

  void add() {
    int keyValue = _index;
    extractedChildren = List.from(extractedChildren)
      ..add(Column(
        key: Key("$keyValue"),
        children: <Widget>[
          Text(keyValue.toString()),
          DropdownButton(
            hint: Text('Choose..'),
            items: data.map((item) {
              return new DropdownMenuItem(
                child: new Text(item['item_name']),
                value: item['id'].toString(),
              );
            }).toList(),
            onChanged: (newVal) {
              setState(() {
                _mySelection = newVal;
              });
            },
            value: _mySelection,
          ),
        ],
      ));
    setState(() => ++_index);
  }
}

3
  • You are sharing widgets between build() calls. Caching them in extractedChildren. Don't do that, always recreate in build. Also do not add() anything in build. Build can be called many times with no reason. Should have zero side effects. Commented May 7, 2020 at 20:07
  • @GazihanAlankus I dont get it. Can you give me more clue, please? Thanks Commented May 8, 2020 at 15:57
  • If you can get rid of this I'll try to help further: List<Widget> extractedChildren. You can change its type. You should not keep any reference to any widget in the variables in your class (fields). Commented May 8, 2020 at 17:06

1 Answer 1

1

To store value for each dropdown button you have to create a list of String in which you can store.

Following code will help you more to understand.

class RepeatableSection extends StatefulWidget {
  @override
  _RepeatableSectionState createState() => _RepeatableSectionState();
}

class _RepeatableSectionState extends State<RepeatableSection> {
  Widget extractedChildren;
  int _index = 0;

  List<String> _mySelection = [];
  List data = List();

  Future<void> fetchAPI() async {
    var url = "http://webmyls.com/php/getdata.php";
    Map<String, String> headers = {
      'Content-type': 'application/json',
      'Accept': 'application/json',
    };
    final response = await http.post(url, headers: headers);
    final responseJson = json.decode(response.body);

    print(data);
    if (response.statusCode == 200) {
      setState(() {
        data = responseJson;
      });
    } else {
      setState(() {});
      throw Exception('Failed to load internet');
    }
  }

  @override
  void initState() {
    super.initState();
    this.fetchAPI();
  }

  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                    child: _index > 0
                        ? ListView.builder(
                            itemCount: _index,
                            shrinkWrap: true,
                            itemBuilder: (_, index) {
                              return Column(
                                key: Key("$index"),
                                children: <Widget>[
                                  Text(index.toString()),
                                  DropdownButton(
                                    hint: Text('Choose..'),
                                    items: data.map((item) {
                                      return new DropdownMenuItem(
                                        child: new Text(item['item_name']),
                                        value: item['id'].toString(),
                                      );
                                    }).toList(),
                                    onChanged: (newVal) {
                                      setState(() {
                                        print("object");
                                        _mySelection[index] = newVal;
                                      });
                                    },
                                    value: _mySelection[index],
                                  ),
                                ],
                              );
                            },
                          )
                        : Container())
              ],
            ),
          ),
          RaisedButton(
            child: Text('Add'),
            onPressed: () {
              setState(() {
                _index++;
                _mySelection.add(null);
              });
              // add();
            },
          ),
        ],
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately, it doesn't work. My selected value is filled to next dropdown index. I don't think it was caused by fetching "delay" to get the values. But thanks for your feedback, mate !
Similar to stackoverflow.com/questions/60497571/… but works after some modifications. Thanks !
Keeping a reference to widgets in state is not a good idea. Widgets get recreated and become stale. State lives on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.