Преобразование данных из API в списки и использование их в зависимых выпадающих кнопках

#flutter #dart

#flutter #dart

Вопрос:

Я хочу преобразовать этот API в многоуровневые списки

это должно действовать как изображение ниже

https://i.stack.imgur.com/10Qld.png
Любая помощь будет оценена

Я хочу преобразовать

 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
  

и хотите, чтобы каждый выпадающий список зависел от предыдущего
Пример:
пользователь должен выбрать из categories.name Включить список, чтобы иметь возможность выбирать из 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 **

  

Ответ №1:

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

Попробуйте использовать это, но замените T на Model.

Также у него должна быть fromMap функция для синтаксического анализа Map<String,dynamic> в соответствии с вашей моделью.

в противном случае используйте обычные конструкторы

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

Вот пример:

 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']
   );
}
  

Это модель с fromMap функцией. Вы можете легко получить эту функцию с помощью плагинов для AndroidStudio или VSCode.

Тот, который я использую для Android Studio, называется DartDataClass .

Теперь, когда у вас есть json со списками =>

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

Вы можете использовать приведенный выше код для анализа этого JSON, если у вас есть созданная для него модель.

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

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

Комментарии:

1. отредактированный сейчас, я написал это из своей головы, проверил сейчас в IDE

Ответ №2:

Я привел пример, аналогичный вашему примеру, но изменил некоторые имена, чтобы вам было понятнее

Сначала вам нужно создать нужные вам классы следующим образом:

Пример только одного класса ***** то же самое относится и к другим классам *****

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};
  

myCategory.g.dart является универсальным файлом с помощью json_serializable,

pubspec.yaml

 dependencies:
  flutter:
    sdk: flutter
  json_serializable: ^3.4.1

dev_dependencies: 
  build_runner: ^1.10.0
  

Где я генерирую их с помощью следующей команды

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

Конечно, вы можете использовать другой метод, но я предпочитаю этот метод

Теперь давайте взглянем на самое важное:

 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 amp;amp;
                    _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 amp;amp;
                    _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')),
                  ),
          ],
        ),
      ),
    );
  }
}
  

Я попробовал это сам, и вот результат:

введите описание изображения здесь

Удачи