2

Using the example in How to Create DropdownButton with a list of JSON Data and I want it to populate my DropDownButton in Flutter I have created the following working example:

main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final String jsonData =
      '[{"id":"e20c","name":"Apples","type":"fruit"},{"id":"a24e","name":"Oranges","type":"fruit"},{"id":"f2a0","name":"Bananas","type":"fruit"}]';
  List<FruitResponse> _fruitResponse = [];
  String selectedName;
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final json = JsonDecoder().convert(jsonData);
    _fruitResponse = (json)
        .map<FruitResponse>((item) => FruitResponse.fromJson(item))
        .toList();

    return MaterialApp(
        title: 'Pick Fruit',
        home: Scaffold(
          appBar: AppBar(
            title: Text("Pick Fruit"),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                DropdownButtonHideUnderline(
                    child: DropdownButton<String>(
                  hint: Text("Select Fruit"),
                  value: selectedName,
                  isDense: true,
                  onChanged: (String newValue) {
                    setState(() {
                      selectedName = newValue;
                    });
                    print(selectedName);
                  },
                  items: _fruitResponse.map((FruitResponse map) {
                    return DropdownMenuItem<String>(
                      value: map.nameDescription,
                      child: Text(map.nameDescription),
                    );
                  }).toList(),
                )),
              ],
            ),
          ),
        ));
  }
}

class FruitResponse {
  final String nameid;
  final String nameDescription;

  FruitResponse({this.nameid, this.nameDescription});
  factory FruitResponse.fromJson(Map<String, dynamic> json) {
    return new FruitResponse(nameid: json['id'], nameDescription: json['name']);
  }
}

However, my JSON data will be

{"objects":[{"id":"e20c","name":"Apples","type":"fruit"},{"id":"a24e","name":"Oranges","type":"fruit"},{"id":"f2a0","name":"Bananas","type":"fruit"}],"from":1,"to":3,"total":3}

I have used https://app.quicktype.io/ to generate the following

FruitResponse fruitResponseFromJson(String str) => FruitResponse.fromJson(json.decode(str));

String fruitResponseToJson(FruitResponse data) => json.encode(data.toJson());

class FruitResponse {
    List<Object> objects;
    int from;
    int to;
    int total;

    FruitResponse({
        this.objects,
        this.from,
        this.to,
        this.total,
    });

    factory FruitResponse.fromJson(Map<String, dynamic> json) => FruitResponse(
        objects: List<Object>.from(json["objects"].map((x) => Object.fromJson(x))),
        from: json["from"],
        to: json["to"],
        total: json["total"],
    );

    Map<String, dynamic> toJson() => {
        "objects": List<dynamic>.from(objects.map((x) => x.toJson())),
        "from": from,
        "to": to,
        "total": total,
    };
}

class Object {
    String id;
    String name;
    String type;

    Object({
        this.id,
        this.name,
        this.type,
    });

    factory Object.fromJson(Map<String, dynamic> json) => Object(
        id: json["id"],
        name: json["name"],
        type: json["type"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "type": type,
    };
}

When I replace the class FruitResponse with the updated class FruitResponse and make changes to the items map I get an error.

Class '_InternalLinkedHashMap' has no instance method 'map' with matching

Working example in DartPad here https://dartpad.dev/b54d896aa35c159cd1749d5c67db7d52

Non-working example in DartPad here https://dartpad.dev/0413fb4bb7944ccd378b9eabf4e88ff3

I think the problem is just getting the List<Object> names correctly from the json data and using it in the DropDownButton items value. I know that map.objects.toString() is not correct, but I don't know what to put there or if I am missing something with _fruitResponse.

Thanks in advance for any help. I'm struggling with understanding mapping JSON response list data.

3 Answers 3

2

Just Check out the following example i have created using the json, i have parsed the json locally :

Following is the json :

{
    "objects": [
        {
            "id": "e20c",
            "name": "Apples",
            "type": "fruit"
        },
        {
            "id": "a24e",
            "name": "Oranges",
            "type": "fruit"
        },
        {
            "id": "f2a0",
            "name": "Bananas",
            "type": "fruit"
        }
    ],
    "from": 1,
    "to": 3,
    "total": 3
}

Depending on the json i have created the model class :

// To parse this JSON data, do
//
//     final fruitResponse = fruitResponseFromJson(jsonString);

import 'dart:convert';

FruitResponse fruitResponseFromJson(String str) => FruitResponse.fromJson(json.decode(str));

String fruitResponseToJson(FruitResponse data) => json.encode(data.toJson());

class FruitResponse {
    List<Object> objects;
    int from;
    int to;
    int total;

    FruitResponse({
        this.objects,
        this.from,
        this.to,
        this.total,
    });

    factory FruitResponse.fromJson(Map<String, dynamic> json) => FruitResponse(
        objects: List<Object>.from(json["objects"].map((x) => Object.fromJson(x))),
        from: json["from"],
        to: json["to"],
        total: json["total"],
    );

    Map<String, dynamic> toJson() => {
        "objects": List<dynamic>.from(objects.map((x) => x.toJson())),
        "from": from,
        "to": to,
        "total": total,
    };
}

class Object {
    String id;
    String name;
    String type;

    Object({
        this.id,
        this.name,
        this.type,
    });

    factory Object.fromJson(Map<String, dynamic> json) => Object(
        id: json["id"],
        name: json["name"],
        type: json["type"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "type": type,
    };
}

And later the main class where the i have defined the dropdown :

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'dummy.dart';

main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _UploadImageState createState() => _UploadImageState();
}

class _UploadImageState extends State<MyApp> {
  bool _isLoading = false;
  List<Object> objectList = List();

  Future<String> loadFromAssets() async {
    return await rootBundle.loadString('json/parse.json');
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    loadYourData();
  }

  loadYourData() async {
    setState(() {
      _isLoading = true;
    });

    String jsonString = await loadFromAssets();
    final fruitResponse = fruitResponseFromJson(jsonString);
    objectList = fruitResponse.objects;
    setState(() {
      _isLoading = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    String selectedFruit;

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: Container(
            child: Padding(
              padding: const EdgeInsets.all(30.0),
              child: Container(
                height: 50,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(5.0),
                  border: Border.all(
                      color: Colors.red, style: BorderStyle.solid, width: 0.80),
                ),
                child: DropdownButton(
                    value: selectedFruit,
                    isExpanded: true,
                    icon: Padding(
                      padding: const EdgeInsets.only(left: 15.0),
                      child: Icon(Icons.arrow_drop_down),
                    ),
                    iconSize: 25,
                    underline: SizedBox(),
                    onChanged: (newValue) {
                      setState(() {
                        print(newValue);
                        selectedFruit = newValue;
                      });
                      print(selectedFruit);
                    },
                    hint: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Text('Select'),
                    ),
                    items: objectList.map((data) {
                      return DropdownMenuItem(
                        value: data.id.toString(),
                        child: Padding(
                          padding: const EdgeInsets.only(left: 10.0),
                          child: Text(
                            data.name,
                            style: TextStyle(
                              fontSize: 18,
                              color: Colors.black,
                            ),
                          ),
                        ),
                      );
                    }).toList()),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @sugar. I made a few corrections to get it to work here.
If you think the answer is helpful then you can make an upvote now.
0

For example listaCatalogo.partes is a list of Object:

List<DropdownMenuItem<Catalogo>> _itemsPartes() {
    var provider = Provider.of<CatalogNotifier>(context);

    return provider.listaCatalogo.partes
        .map((item) => DropdownMenuItem<Catalogo>(
              value: item,
              child: Text(item.valor),
            ))
        .toList();
  }

DropdownButton<Catalogo>(
                        value: registro.parteCat,
                        onChanged: (Catalogo value) {
                          setState(() {
                            registro.parteCat = value;
                            registro.parte = value.id;
                          });
                        },
                        items: _itemsPartes(),
                      )

Comments

-1

I give u the idea, you must to change the String to Object

Replace DropdownButton to DropdownButton Where FruitResponse is the OBject that you want to use.

And

Replace onChanged: (String newValue) {
                    setState(() {
                      selectedName = newValue;
                    });
                    print(selectedName);
                  }

to

onChanged: (FruitResponse newValue) {
                    setState(() {
                      selectedName = newValue.nameid;
                    });
                    print(selectedName);
                  }

And DropdownMenuItem to DropdownMenuItem

Comments

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.