How to create dropdown category name list in flutter where data comes from Rest API?

Viewed 58

I need to display a list of category names in the dropdown list and when I click on category detail it should need to store in a different category table. I create the controller, API, and Model of category and try to fetch in the view page but it would not display please suggest some example code. I am new to flutter how can I do this?

categoryapi.dart

import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:shivaram/model/category.dart';

class CategoryApi {
  static var client = http.Client();

  static Future<List<CategoryModel>> fetchCategoryModel() async {
    final response =
        await http.get(Uri.parse('http://127.0.0.1:8000/api/categories'));
    if (response.statusCode == 200) {
      List jsonResponse = json.decode(response.body);
      return jsonResponse
          .map((data) => new CategoryModel.fromJson(data))
          .toList();
    } else {
      throw Exception('Unexpected error occured!');
    }
  }
}

category_controller.dart

import 'package:get/get.dart';
import 'package:shivaram/api/categoryapi.dart';
import 'package:shivaram/model/category.dart';

class CategoryController extends GetxController {
  var isLoading = true.obs;
  // ignore: deprecated_member_use
  RxList<CategoryModel> categoryList = <CategoryModel>[].obs;

  @override
  void onInit() {
    fetchCategoryModel();
    super.onInit();
  }

  void fetchCategoryModel() async {
    try {
      isLoading(true);
      var categories = await CategoryApi.fetchCategoryModel();
      categoryList.value = categories;
    } finally {
      isLoading(false);
    }
  }
}

category.dart

// To parse this JSON data, do
//
//     final categoryModel = categoryModelFromJson(jsonString);

import 'dart:convert';

List<CategoryModel> categoryFromJson(String str) => List<CategoryModel>.from(
    json.decode(str).map((x) => CategoryModel.fromJson(x)));

String categoryToJson(List<CategoryModel> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class CategoryModel {
  CategoryModel({
    required this.id,
    required this.catName,
    required this.catImg,
    required this.createdAt,
    required this.updatedAt,
  });

  int id;
  String catName;
  String catImg;
  DateTime createdAt;
  DateTime updatedAt;

  factory CategoryModel.fromJson(Map<String, dynamic> json) => CategoryModel(
        id: json["id"],
        catName: json["cat_name"],
        catImg: json["cat_img"],
        createdAt: DateTime.parse(json["created_at"]),
        updatedAt: DateTime.parse(json["updated_at"]),
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "cat_name": catName,
        "cat_img": catImg,
        "created_at": createdAt.toIso8601String(),
        "updated_at": updatedAt.toIso8601String(),
      };
}

category_view.dart

import 'package:flutter/material.dart';

import 'animation/fadeanimation.dart';

class CategoryView extends StatefulWidget {
  const CategoryView({Key? key}) : super(key: key);

  @override
  State<CategoryView> createState() => _CategoryViewState();
}

var selectedCategory;
List<String> _category = <String>[
  'Student',
  'teaching',
  'traveling',
  'swimming',
  'playing',
  'driving',
  'Coding',
  'Others',
]; // manual data but at this section I want to fetch category name from API

class _CategoryViewState extends State<CategoryView> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          FadeAnimation(
            1.2,
            Padding(
              padding: EdgeInsets.only(top: 5),
              child: Container(
                height: 50,
                decoration: BoxDecoration(
                    border: Border.all(),
                    borderRadius: BorderRadius.circular(20)),
                child: DropdownButton(
                  items: _category
                      .map(
                        (value) => DropdownMenuItem(
                          child: Text(
                            value,
                            style: TextStyle(color: Colors.black),
                          ),
                          value: value,
                        ),
                      )
                      .toList(),
                  onChanged: (dynamic selectdCategories) {
                    setState(
                      () {
                        selectedCategory = selectdCategories;
                      },
                    );
                  },
                  value: selectedCategory,
                  hint: Text(
                    'Choose Account Type',
                    style: TextStyle(color: Colors.black),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
1 Answers

The following code would do the trick. The important changes are marked with the comment // <- Here.

It uses the Obx class to listen to the controller changes and update the screen accordingly.

class CategoryView extends StatefulWidget {
  const CategoryView({Key? key}) : super(key: key);

  @override
  State<CategoryView> createState() => _CategoryViewState();
}

class _CategoryViewState extends State<CategoryView> {
  final CategoryController categoryController = Get.find();        // <- Here
  CategoryModel? selectedCategory;                                 // <- Here

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        Padding(
          padding: const EdgeInsets.only(top: 5),
          child: Obx(                                              // <- Here
            () => categoryController.isLoading.value               // <- Here
                ? const CircularProgressIndicator()                // <- Here
                : Container(
                    height: 50,
                    decoration: BoxDecoration(
                        border: Border.all(),
                        borderRadius: BorderRadius.circular(20)),
                    child: DropdownButton<CategoryModel>(
                      items: categoryController.categoryList       // <- Here
                          .map(
                            (value) => DropdownMenuItem(
                              value: value,
                              child: Text(
                                value.catName,
                                style: const TextStyle(color: Colors.black),
                              ),
                            ),
                          )
                          .toList(),
                      onChanged: (selectdCategories) {
                        setState(
                          () {
                            selectedCategory = selectdCategories;
                          },
                        );
                      },
                      value: selectedCategory,
                      hint: const Text(
                        'Choose Account Type',
                        style: TextStyle(color: Colors.black),
                      ),
                    ),
                  ),
          ),
        ),
      ],
    );
  }
}

Don't forget to initialize the controller at the beginning of the app with Get.put. Most probably besides the MaterialApp like the following code:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Get.put(CategoryController());                                  // <- Here
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}
Related