Previous Article Next Article Flutter – Serialize Nested/Complex JSON From Network and Build List with Refresh Indicator
Posted in API Flutter PHP & MySQL

Flutter – Serialize Nested/Complex JSON From Network and Build List with Refresh Indicator

Flutter – Serialize Nested/Complex JSON From Network and Build List with Refresh Indicator Posted on May 10, 2020Leave a comment
I'm Hari Prasad Chaudhary from Nepal, developer of the finest educational website/app "MeroSpark" and the finest eCommerce system "PasalaY". Here I share the code snippet which I learn during development.

On this example project, I have tried to explain to generate JSON with PHP and build a list of students using column widget in Flutter. In this example, I have done the following things.

  • Generate Nested JSON with PHP
  • Request JSON from Server
  • Serialize JSON inside the model.
  • Build list using Column widget
  • Swipe down Refresh of list
  • Show student details when clicking on the list.

Screenshot:

Student List PageStudent Details PageJSON Format

Our Database:

Database table

PHP Code to Generate JSON: Previously I had written an article on Valid way to Generate Nested or Complex JSON data for Flutter using PHP

<?php 
  $db = "test_db";
  $host = "localhost";
  $db_user = 'root';
  $db_password = 'root';
  //MySql server and database info

  $link = mysqli_connect($host, $db_user, $db_password, $db);
  //connecting to database

  $json["error"] = false;
  $json["errmsg"] = "";
  $json["data"] = array();

  $sql = "SELECT * FROM student_list ORDER BY full_name ASC";
  $res = mysqli_query($link, $sql);
  $numrows = mysqli_num_rows($res);
  if($numrows > 0){
      
     //check if there is any data
      while($array = mysqli_fetch_assoc($res)){
           array_push($json["data"], $array);
      }

      /* Do not push data like below,
      it will cause error on flutter json prasing. 
      user array_push() function.  

      $datalist = array();
      $x = 1;
      while($array = mysqli_fetch_assoc($res)){
           $datalist[$x] = $array;
           $x++;
      }
      $json["data"] = $datalist;

      */
  }else{
      $json["error"] = true;
      $json["errmsg"] = "No any data to show.";
  }

  mysqli_close($link);
  
  header('Content-Type: application/json');
  // tell browser that its a json data
  echo json_encode($json);

?>

Now Flutter Part: Project Directory Structure

  • lib/
  • —— data.dart // student data model
  • —— home.dart // to show list of student
  • —— main.dart
  • —— student_details.dart // to show student details
  • pubspec.yaml

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  http: ^0.12.1
  #add this package for http request

main.dart

import 'package:flutter/material.dart';
import 'home.dart';
//importing home.dart file

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Home(),
    );
  }
}

data.dart // Student data model

class StudentOne{
    String studentid, fullname, address, classno, rollno, dob;
    
    StudentOne({
        this.studentid, 
        this.fullname, 
        this.address, 
        this.classno, 
        this.rollno,
        this.dob
    });
    //constructor

    factory StudentOne.fromJSON(Map<String, dynamic> json){
        return StudentOne( 
           studentid: json["student_id"],
           fullname: json["full_name"],
           address: json["address"],
           classno: json["class"],
           rollno: json["roll_no"],
           dob: json["dob"]
        );
    } 
}

home.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:studentlist/data.dart';
import 'package:studentlist/student_details.dart';
// import it manually, on VS code it will not
// suggest a import path 

class Home extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _Home();
  }
}

class _Home extends State<Home>{

  bool error = false, dataloaded = false;
  var data;
  String dataurl = "http://192.168.0.112/test/test.php";
  // do not use http://localhost/ for your local
  // machine, Android emulation do not recognize localhost
  // insted use your local ip address or your live URL
  // hit "ipconfig" on Windows or 
  // "ip a" on Linux to get IP Address

  @override
  void initState() {
    loaddata();
    //calling loading of data 
    super.initState();
  }

  void loaddata(){
    Future.delayed(Duration.zero,() async {
        var res = await http.post(dataurl);
        if (res.statusCode == 200) {
            setState(() {
                data = json.decode(res.body);
                dataloaded = true;
                // we set dataloaded to true,
                // so that we can build a list only
                // on data load
            });
        }else{
           //there is error
           setState(() {
               error = true;
           });
        }
    });
    // we use Future.delayed becuase there is 
    // async function inside it. 
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
         appBar:  AppBar(
              elevation: 0,
              backgroundColor: Colors.blue,
              title:Text("Student List")
         ),
          
         body: RefreshIndicator( 
             onRefresh: () async {
                 setState(() {
                    dataloaded = false;
                    error = false;
                 });
                 loaddata();
                 //calling loading of data on refresh
                 //seting dataloaded to flase so that 
                 // it shows circular spinner.
             },
             child: SingleChildScrollView( 
                 // to scroll on list overflow
                 child:Container( 
                     constraints: BoxConstraints( 
                         minHeight: MediaQuery.of(context).size.height
                         //set to minium height to verticle height
                     ), 
                     child: datalist(),
                 )
             )
         ),
    );
  }

  Widget datalist(){
      if(!dataloaded){
          //show progress indicator if data is not loaded
          return Center( 
             child: SizedBox(
                      height:50, width:50,
                      child:CircularProgressIndicator(),
             )
          );
      }else{
          if(error || data["error"]){
              //show error message on error
              String errormsg = "Error during fetching data.";
              if(data["error"]){
                  errormsg  = data["errmsg"];
                  //set error message from api.
              }
              return Container( 
                  margin: EdgeInsets.all(15),
                  child:Text(errormsg,
                     style:TextStyle(color:Colors.red)
                  ),
              );
          }else{
              List<StudentOne> studentslist = List<StudentOne>.from(
                  data["data"].map((i){
                         return StudentOne.fromJSON(i);
                  })
              );
              //serilizing json data inside model list.

              return Container( 
                  child: Column(
                      children: studentslist.map((student){
                        return Card( 
                            child:ListTile( 
                                title: Text(student.fullname),
                                subtitle: Text(student.classno + ' ' + student.rollno),
                                leading: Icon(Icons.person),
                                trailing: Icon(Icons.arrow_forward),
                                onTap: (){
                                    //showing details on tap
                                    Navigator.push(context, MaterialPageRoute( 
                                       builder: (context){
                                           return StudentDetails( 
                                               fullname: student.fullname,
                                               address: student.address,
                                               classno: student.classno,
                                               rollno: student.rollno,
                                               dob: student.dob
                                           );
                                           //passing student data to students details page
                                       }
                                    ));
                                },
                            )
                        );
                      }).toList(),
                  ),
              );
          }
      }

  }

}

student_details.dart

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

class StudentDetails extends StatelessWidget{
  final String fullname, address, classno, rollno, dob;
    
  StudentDetails({
        this.fullname, 
        this.address, 
        this.classno, 
        this.rollno,
        this.dob
  });
  //setting constructor for this class so that we can pass
  // data from another class.

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar:  AppBar(
              elevation: 0,
              backgroundColor: Colors.blue,
              title:Text("Student List")
         ), //app bar

        body: SingleChildScrollView(
            child:Card( 
              child:Container( 
                width: double.infinity, //making width 100%;
                margin:EdgeInsets.all(15),
                    child:Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children:<Widget>[
                            Text("Student Name: " + fullname),
                            Text("Address: " + address),
                            Text("Class: " + classno),
                            Text("Roll No: " + rollno),
                            Text("DOB: " + dob),

                        ]
                    )
                )
            )
        ),
    );
  }
   
}

Download the Project: Student List from Network JSON [260.87 KB]

In this way you can build a complete list functionality from complex or nested network JSON by serializing it inside data model.

I'm Hari Prasad Chaudhary from Nepal, developer of the finest educational website/app "MeroSpark" and the finest eCommerce system "PasalaY". Here I share the code snippet which I learn during development.

Leave a Reply

Your email address will not be published. Required fields are marked *