简体   繁体   English

在DropdownButton中选择项目会导致Flutter引发错误

[英]Selection of Item in DropdownButton causes Flutter to throw error

I am currently trying to retrieve data (tags) from a REST API and use the data to populate a dropdown menu which I can successfully do but upon selection of the item, I get the following error which according to this would mean that the "selected value is not member of the values list": 我目前正在尝试从REST API检索数据(标签),并使用该数据填充一个可以成功完成的下拉菜单,但是在选择该项目时,出现以下错误,根据错误, 意味着“已选择”值不是值列表的成员”:

items == null || 项目== null || value == null || 值== null || items.where((DropdownMenuItem item) => item.value == value).length == 1': is not true. items.where(((DropdownMenuItem item)=> item.value == value).length == 1':不正确。

This occurs after the dropdown menu shows my selected item. 这是在下拉菜单显示我的选定项目之后发生的。 However, this is error should not be occurring as I've done the necessary logging to check that the data is indeed assigned to the list in question. 但是,这不是应该发生的错误,因为我已经完成了必要的日志记录,以检查数据是否确实分配给了相关列表。 Could anyone help me resolve this issue? 谁能帮我解决这个问题? I have isolated it to down to it originating in the setState() method in onChanged of DropdownButton but can't seem to understand why that should be causing an issue. 我已经将其隔离到起源于DropdownButton的onChangedsetState()方法,但是似乎无法理解为什么这会引起问题。 Any help would be deeply appreciated! 任何帮助将不胜感激!

My code is as follows: 我的代码如下:

class _TodosByTagsHomePageState extends State<TodosByTagsHomePage> {
    Tag selectedTag;

    final Logger log = new Logger('TodosByTags');

    @override
    Widget build(BuildContext context) {
      return Scaffold(
          appBar: AppBar(
            title: Text("Second Screen"),
          ),
          body: ListView(
              children: <Widget>[
                FutureBuilder<List<Tag>> (
                    future: fetchTags(),
                    builder: (context, snapshot) {
                      if (snapshot.hasData) {
                        log.info("Tags are present");
                        _tagsList = snapshot.data;
                        return DropdownButton<Tag>(
                          value: selectedTag,
                          items: _tagsList.map((value) {
                            return new DropdownMenuItem<Tag>(
                              value: value,
                              child: Text(value.tagName),
                            );
                          }).toList(),
                          hint: Text("Select tag"),
                          onChanged: (Tag chosenTag) {
                            setState(() {
                              log.info("In set state");
                              selectedTag = chosenTag;
                              Scaffold.of(context).showSnackBar(new SnackBar(content: Text(selectedTag.tagName)));
                            });
                          },
                        ) ;
                      } else if (snapshot.hasError) {
                        return Text("${snapshot.error}");
                      }

                      return Container(width: 0.0, height: 0.0);
                    }),
              ])
      );
    }

// Async method to retrieve data from REST API
      Future<List<Tag>> fetchTags() async {
        final response =
        await http.get(REST_API_URL);

        if (response.statusCode == 200) {
          // If the call to the server was successful, parse the JSON
          var result = compute(parseData, response.body);
          return result;
        } else {
          // If that call was not successful, throw an error.
          throw Exception('Failed to load post');
        }
      }

      static List<Tag> parseData(String response) {
        final parsed = json.decode(response);

        return (parsed["data"] as List).map<Tag>((json) =>
        new Tag.fromJson(json)).toList();
      }

      List<Tag> _tagsList = new List<Tag>();

    }

// Model for Tag
    class Tag {
      final String tagName;
      final String id;
      final int v;

      Tag({this.id, this.tagName, this.v});

      factory Tag.fromJson(Map<String, dynamic> json) {
        return new Tag(
          id: json['_id'],
          tagName: json['tagName'],
          v: json['__v'],
        );
      }
    }

update your code like this I think issues that when calling setState in FutureBuilder that call fetchTags() move fetchTags() to initState() for once call 这样更新代码,我认为这样的问题是,在FutureBuilder中调用setState并调用fetchTags()fetchTags()移至initState()一次即可调用

class _TodosByTagsHomePageState extends State<TodosByTagsHomePage> {
      Tag selectedTag;
      Future<List<Tag>> _tags;
      @override
      void initState() {
         _tags = fetchTags();
        super.initState();
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              title: Text("Second Screen"),
            ),
            body: ListView(children: <Widget>[
              FutureBuilder<List<Tag>>(
                  future: _tags,
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
                      return DropdownButton<Tag>(
                        value: selectedTag,
                        items: snapshot.data.map((value) {
                          print(value);
                          return  DropdownMenuItem<Tag>(
                            value: value,
                            child: Text(value.tagName),
                          );
                        }).toList(),
                        hint: Text("Select tag"),
                        onChanged: (Tag chosenTag) {
                          setState(() {
                            selectedTag = chosenTag;
                          });
                        },
                      );
                    } else if (snapshot.hasError) {
                      return Text("${snapshot.error}");
                    }

                    return Container(width: 0.0, height: 0.0);
                  }),
            ]));
      }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM