Mohammed El-Barbeer
Mohammed El-Barbeer

Reputation: 27

Convert data from an API to lists and use it in dependent Dropdownbuttons

I want to convert this API to multiable lists

it should act like the image below

https://i.sstatic.net/10Qld.png Any help will be appreciated

I want to convert

1-categories.name toList

2-categories.children.name toList

3-categories.children.children_lv.name toList

4-categories.children.name.children_lv.children.name toList

and want to make every dropdown dependant to the previous one Example: the user should select from categories.name toList to be able to choose from 2-categories.children.name toList

API

    "categories": [
        {
            "category_id": "1841",
            "name": "Cars",
            "children": [
                {
                    "name": "Car1",
                    "category_id": "1845",
                    "children_lv": [
                        {
                            "name": "",
                            "category_id": "",
                            "children_lv": "",
                            "href": ""
                        }
                    ],
                    "column": "1",
                 
                {
                    "name": "Car2",
                    "category_id": "1846",
                    "children_lv": [
                        {
                            "name": "Car2_1",
                            "category_id": "1847",
                            "children_lv": [
                                {
                                    "name": "",
                                    "category_id": "",
                                    "children_lv": "",
                                    "href": ""
                                }
                            ],
                           
                        },
                        {
                            "name": "Car2_2",
                            "category_id": "1848",
                            "children_lv": [
                                {
                                    "name": "",
                                    "category_id": "",
                                    "children_lv": "",
                                    "href": ""
                                }
                            ],
                           
                        }
                    ],
                   
                }
            ],
        },
        {
            "category_id": "1842",
            "name": "Properties",
            "children": [
                {
                    "name": "",
                    "category_id": "",
                    "children_lv": "",
                    "href": ""
                }
            ],
            "column": "1",
           
        },
        {
            "category_id": "1843",
            "name": "Machines",
            "children": [
                {
                    "name": "",
                    "category_id": "",
                    "children_lv": "",
                   
                }
            ],
            "column": "1",
            
        },
        {
            "category_id": "1844",
            "name": "Electronics",
            "children": [
                {
                    "name": "",
                    "category_id": "",
                    "children_lv": "",
                    "href": ""
                }
            ],
            "column": "1",
          
        }
    ]
}```

the lists that should be converted are category, children and the other children_lv
**Model has been made with app.quicktype.io and it works **

Upvotes: 2

Views: 233

Answers (2)

farouk osama
farouk osama

Reputation: 2529

I did an example, the same as your example, but changed some names to make it clear to you

First, you need to create the Classes that you need like this:

Example of only one class ***** the same thing applies to the other classes *****

myCategory.dart

import 'package:flutterapp/myCategory1.dart';
import 'package:json_annotation/json_annotation.dart';
part 'myCategory.g.dart';

@JsonSerializable()
class MyCategory {
  String name;
  List<MyCategory1> children1;

  MyCategory({this.name,this.children1});

  factory MyCategory.fromJson(Map<String, dynamic> json) =>
      _$MyCategoryFromJson(json);

  Map<String, dynamic> toJson() => _$MyCategoryToJson(this);
}

myCategory.g.dart

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'myCategory.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

MyCategory _$MyCategoryFromJson(Map<String, dynamic> json) {
  return MyCategory(
      name: json['name'] as String,
      children1: (json['children1'] as List)
          ?.map((e) => e == null
              ? null
              : MyCategory1.fromJson(e as Map<String, dynamic>))
          ?.toList());
}

Map<String, dynamic> _$MyCategoryToJson(MyCategory instance) =>
    <String, dynamic>{'name': instance.name, 'children1': instance.children1};

the myCategory.g.dart is generic file by json_serializable,

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  json_serializable: ^3.4.1

dev_dependencies: 
  build_runner: ^1.10.0

Where I generate it with the following command

flutter pub run build_runner build --delete-conflicting-outputs

Of course, you can use another method, but I prefer this method

Now let's take a look at the most important thing:

class CategoriesWidget extends StatefulWidget {
  @override
  _CategoriesWidgetState createState() => new _CategoriesWidgetState();
}

class _CategoriesWidgetState extends State<CategoriesWidget> {
  List<MyCategory> myNestedList;
  MyCategory _selectedMyCategory;
  MyCategory1 _selectedMyCategory1;
  MyCategory2 _selectedMyCategory2;

  @override
  void initState() {
    super.initState();
    myNestedList =
        (map['categories'] as List).map((e) => MyCategory.fromJson(e)).toList();
  }

  Map<String, dynamic> map = {
    'categories': [
      {
        "name": '1',
        "children1": [
          {"name": '1-1'},
          {
            "name": '1-2',
            'children2': [
              {'name': '1-2-1'},
              {'name': '1-2-2'}
            ]
          }
        ]
      },
      {
        "name": '2',
        "children1": [
          {"name": '2-1'},
          {
            "name": '2-2',
            'children2': [
              {'name': '2-2-1'},
              {'name': '2-2-2'}
            ]
          }
        ]
      }
    ]
  };

  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.rtl,
      child: Scaffold(
        appBar: AppBar(
          title: Text("Dropdown Categories"),
          centerTitle: true,
        ),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Container(
              height: 45,
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(10),
                  border: Border.all(color: Colors.grey, width: 0.5)),
              padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
              margin: EdgeInsets.all(8),
              child: DropdownButton(
                isDense: true,
                isExpanded: true,
                hint: Text('My categories'),
                underline: Container(),
                items: myNestedList.map((item) {
                  return DropdownMenuItem(
                    value: item,
                    child: Text(item.name),
                  );
                }).toList(),
                value: _selectedMyCategory,
                onChanged: (value) {
                  setState(() {
                    _selectedMyCategory = value;
                    if (_selectedMyCategory1 != null) {
                      _selectedMyCategory1 = _selectedMyCategory.children1
                          .firstWhere(
                              (element) => element == _selectedMyCategory1,
                              orElse: () => null);
                    }
                  });
                },
              ),
            ),
            _selectedMyCategory?.children1 != null &&
                    _selectedMyCategory.children1.length > 0
                ? Container(
                    height: 45,
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(10),
                        border: Border.all(color: Colors.grey, width: 0.5)),
                    padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
                    margin: EdgeInsets.all(8),
                    child: DropdownButton(
                      isDense: true,
                      isExpanded: true,
                      hint: Text('My categories 1'),
                      underline: Container(),
                      value: _selectedMyCategory1,
                      items: _selectedMyCategory.children1.map((item) {
                        return DropdownMenuItem(
                          value: item,
                          child: Text(item.name),
                        );
                      }).toList(),
                      onChanged: (value) {
                        setState(() {
                          _selectedMyCategory1 = value;
                          if (_selectedMyCategory2 != null) {
                            _selectedMyCategory2 =
                                _selectedMyCategory1.children2.firstWhere(
                                    (element) =>
                                        element == _selectedMyCategory2,
                                    orElse: () => null);
                          }
                        });
                      },
                    ),
                  )
                : Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Center(child: Text('My categories 1')),
                  ),
            _selectedMyCategory1?.children2 != null &&
                    _selectedMyCategory1.children2.length > 0
                ? Container(
                    height: 45,
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(10),
                        border: Border.all(color: Colors.grey, width: 0.5)),
                    padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
                    margin: EdgeInsets.all(8),
                    child: DropdownButton(
                      isDense: true,
                      isExpanded: true,
                      hint: Text('My categories 2'),
                      underline: Container(),
                      items: _selectedMyCategory1.children2.map((item) {
                        return DropdownMenuItem(
                          value: item,
                          child: Text(item.name),
                        );
                      }).toList(),
                      value: _selectedMyCategory2,
                      onChanged: (value) {
                        setState(() {
                          _selectedMyCategory2 = value;
                        });
                      },
                    ),
                  )
                : Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Center(child: Text('My categories 2')),
                  ),
          ],
        ),
      ),
    );
  }
}

I tried it myself, and here is the result:

enter image description here

Good luck

Upvotes: 1

Tree
Tree

Reputation: 31371

List<T> list = (map['list'] as List).map<T>((e)=>T.fromMap(e));

Try with this, but replace T with Model.

Also it should have fromMap function, to parse Map<String,dynamic> to your model.

else use normal constructors

((e)=>T(a:e['a'], b:e['b']);

Here is an example:

class Model {

 final String a;
 final String b;
 
 Model({this.a,this.b});

 factory Model.fromMap(Map<String,dynamic> map) => 
   Model(
     a: map['a'],
     b: map['b']
   );
}

This is a model with fromMap function. You can get that function easy with plugins for AndroidStudio or VSCode.

The one I use for android studio is called DartDataClass.

Now when you have json with lists =>

{ list : [
  { "a":"we","b":"try"},
  { "a":"as","b":"dfg"},
]}

You can use code above to parse that JSON if you have create the model for it.

Map<String,dynamic> json = jsonDecode(jsonSource);

List<Model> list = (json['list'] as List).map<Model>((e)=>Model.fromMap(e)).toList();

Upvotes: 1

Related Questions