Home > Software engineering >  Parse Array in Object in Array in Dart / Flutter
Parse Array in Object in Array in Dart / Flutter

Time:10-04

I have a REST Service I like to consume, but I do not know how to parse that JSON to an Object.

My JSON looks like that:

[
  {
    "types": {
      "KEYWORD": "STRING"
    },
    "displaynames": {
      "KEYWORD": "Keyword"
    },
    "rows": [
      {
        "KEYWORD": "Test 1"
      },
      {
        "KEYWORD": "Test 2"
      }
    ]
  }
]

That is my object I created from that:

import 'dart:convert';

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

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

class Todo {
  Todo({
    required this.types,
    required this.displaynames,
    required this.rows,
  });

  Displaynames types;
  Displaynames displaynames;
  List<Displaynames> rows;

  factory Todo.fromJson(Map<String, dynamic> json) => Todo(
        types: Displaynames.fromJson(json["types"]),
        displaynames: Displaynames.fromJson(json["displaynames"]),
        rows: List<Displaynames>.from(
            json["rows"].map((x) => Displaynames.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "types": types.toJson(),
        "displaynames": displaynames.toJson(),
        "rows": List<dynamic>.from(rows.map((x) => x.toJson())),
      };
}

class Displaynames {
  Displaynames({
    required this.keyword,
  });

  String keyword;

  factory Displaynames.fromJson(Map<String, dynamic> json) => Displaynames(
        keyword: json["KEYWORD"],
      );

  Map<String, dynamic> toJson() => {
        "KEYWORD": keyword,
      };
}

I try Loading the JSON and Display like that by using the pull_to_refresh Package.

import 'package:flutter/material.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'dart:convert';
import 'package:user_portal/model/todo.dart';

class TodoRoute extends StatefulWidget {
  const TodoRoute({super.key});

  @override
  State<TodoRoute> createState() => _TodoRouteState();
}

class _TodoRouteState extends State<TodoRoute> {
  late List<Todo> todoList = [];
  final RefreshController refreshController =
      RefreshController(initialRefresh: true);

  Future<bool> fetchTodo() async {
    const String jsonstr =
        '[  {    "types": {      "KEYWORD": "STRING"    },    "displaynames": {      "KEYWORD": "Keyword"    },    "rows": [      {        "KEYWORD": "Test 1"      },      {        "KEYWORD": "Test 2"      }    ]  }]';
    todoList = (json.decode(jsonstr) as List)
        .map((data) => Todo.fromJson(data))
        .toList();
    setState(() {});

    return true;
  }

  @override
  Widget build(context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Todo'),
      ),
      body: SmartRefresher(
        controller: refreshController,
        enablePullUp: true,
        onRefresh: () async {
          final result = await fetchTodo();
          if (result) {
            refreshController.refreshCompleted();
          } else {
            refreshController.refreshFailed();
          }
        },
        onl oading: () async {
          final result = await fetchTodo();
          if (result) {
            refreshController.loadComplete();
          } else {
            refreshController.loadFailed();
          }
        },
        child: ListView.separated(
          scrollDirection: Axis.vertical,
          itemCount: todoList.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(todoList[0].rows[index].keyword),
            );
          },
          separatorBuilder: (context, index) => const Divider(),
        ),
      ),
    );
  }
}

But the Only Item I get is the Test 1 Item not the Test 2 Item and I do not know where to look further for that Problem.

CodePudding user response:

because jsonstr as only one object inside it so when decoding to todoList it has a length=1 , so the error is you are building the UI based on the wrong list. rows is a list with length=2 because it has two objects

CodePudding user response:

try this way it's so easy...

add this method in your TOdo model

 static List< Todo > fromList(json) {
List< Todo > tempList = [];
try {
  json.forEach((element) {
    tempList.add(Todo.fromJson(element));
  });
  return tempList;
} catch (e) {
  return tempList;
}
 }

change this function

Future<bool> fetchTodo() async {
const String jsonstr =
    '[  {    "types": {      "KEYWORD": "STRING"    },    
  "displaynames": {      "KEYWORD": "Keyword"    },    "rows": [      {        
 "KEYWORD": "Test 1"      },      {        "KEYWORD": "Test 2"      }    
]  
 }]';
Map data = json.decode(jsonstr);

todoList = Todo.fromList(data);
setState(() {});

return true;
}

CodePudding user response:

Change your fetchTodo() to this:

Future<bool> fetchTodo() async {
    const String jsonstr =
        '[  {    "types": {      "KEYWORD": "STRING"    },    "displaynames": {      "KEYWORD": "Keyword"    },    "rows": [      {        "KEYWORD": "Test 1"      },      {        "KEYWORD": "Test 2"      }    ]  }]';
    
    todoList = welcomeFromJson(jsonstr);//<--- add this

    setState(() {});

    return true;
  }

also change this in asdas class:

factory Todo.fromJson(Map<String, dynamic> json) => Todo(
        types: Displaynames.fromJson(json["types"]),
        displaynames: Displaynames.fromJson(json["displaynames"]),
        rows: json["rows"] != null ? (json["rows"] as List).map((x) => Displaynames.fromJson(x)).toList():[],
  • Related