Smart HO
Smart HO

Reputation: 169

Flutter: JSON data , list under list

I have JSON data file that looks like this, as you can see the email is a list itself:

[
    {
        "index": 0,
        "about": "text text text",
        "email": [
            "[email protected]",
            "[email protected]",
        ],
        "name": "sample name",
        "picture": "https://kdjfksfjsdklfs.com"
    },
    {
        "index": 1,
        "about": "text text text",
        "email": [
            "[email protected]",
            "[email protected]",
        ],
        "name": "sample name ",
        "picture": "https://kdjfksfjsdklfs.com"
    },
    {
        "index": 2,
        "about": "text text text",
        "email": [
            "[email protected]",
            "[email protected]",
        ],
        "name": "sample name",
        "picture": "https://kdjfksfjsdklfs.com"
    }
]

My code is the following, which is basically a listview builder that gets data from the above JSON. Now when the list is clicked it navigate to the next page where I need to show details of this user.

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Users'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

Future _data;

class _MyHomePageState extends State<MyHomePage> {
  Future<List<User>> _getUsers() async {
    var data =
        await DefaultAssetBundle.of(context).loadString("assets/test.json");

    var jsonData = json.decode(data);

    List<User> users = [];

    for (var u in jsonData) {
      User user =
          User(u["index"], u["about"], u["name"], u["email"], u["picture"]);

      users.add(user);
    }

    print(users.length);

    return users;
  }

  @override
  void initState() {
    super.initState();
    _data = _getUsers();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: Container(
        child: FutureBuilder(
          future: _data,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            print(snapshot.data);
            if (snapshot.data == null) {
              return Container(child: Center(child: Text("Loading...")));
            } else {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(
                    leading: CircleAvatar(
                      backgroundImage:
                          NetworkImage(snapshot.data[index].picture),
                    ),
                    title: Text(snapshot.data[index].name),
                    // subtitle: Text(snapshot.data[index].email),
                    onTap: () {
                      Navigator.push(
                          context,
                          new MaterialPageRoute(
                              builder: (context) =>
                                  DetailPage(snapshot.data[index])));
                    },
                  );
                },
              );
            }
          },
        ),
      ),
    );
  }
}

class DetailPage extends StatelessWidget {
  final User user;

  DetailPage(this.user);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(user.name),
      ),
      body: Container(
        child: Text(user.about),
      ),
    );
  }
}

class User {
  final int index;
  final String about;
  final String name;
  final String email;
  final String picture;

  User(this.index, this.about, this.name, this.email, this.picture);
}

I wanted to create Listview Builder in the second page for name and the email so that all the emails listed under the name.

can someone help I am not able to generate the second page list especially the email list.

Upvotes: 1

Views: 2648

Answers (2)

Sagar Acharya
Sagar Acharya

Reputation: 3767

Just check out this example and let me know if it works for you:

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';

import 'package:json_parsing_example/models.dart';

// To parse this JSON data, do
//
//     final user = userFromJson(jsonString);

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Users'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

Future _data;

class _MyHomePageState extends State<MyHomePage> {
  Future<List<User>> _getUsers() async {
    var data =
        await DefaultAssetBundle.of(context).loadString("json/parse.json");

    return userFromJson(data);
  }

  @override
  void initState() {
    super.initState();
    _data = _getUsers();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: Container(
        child: FutureBuilder<List<User>>(
          future: _data,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            print(snapshot.data);
            if (snapshot.data == null) {
              return Container(child: Center(child: Text("Loading...")));
            } else {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(
                    leading: CircleAvatar(
                      backgroundImage:
                          NetworkImage(snapshot.data[index].picture),
                    ),
                    title: Text(snapshot.data[index].name),
                    // subtitle: Text(snapshot.data[index].email),
                    onTap: () {
                      Navigator.push(
                          context,
                          new MaterialPageRoute(
                              builder: (context) =>
                                  DetailPage(snapshot.data[index])));
                    },
                  );
                },
              );
            }
          },
        ),
      ),
    );
  }
}

class DetailPage extends StatefulWidget {
  final User user;

  DetailPage(this.user);

  @override
  _DetailPageState createState() => _DetailPageState();
}

class _DetailPageState extends State<DetailPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.user.name),
      ),
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                widget.user.name,
                style: TextStyle(fontSize: 20),
              ),
            ),
            ListView.builder(
              shrinkWrap: true,
              itemCount: widget.user.email.length,
              itemBuilder: (BuildContext context, int index) {
                return Card(
                    child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(widget.user.email[index]),
                ));
              },
            ),
          ],
        ),
      ),
    );
  }
}


Your model class :

// To parse this JSON data, do
//
//     final user = userFromJson(jsonString);

import 'dart:convert';

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

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

class User {
    User({
        this.index,
        this.about,
        this.email,
        this.name,
        this.picture,
    });

    int index;
    String about;
    List<String> email;
    String name;
    String picture;

    factory User.fromJson(Map<String, dynamic> json) => User(
        index: json["index"],
        about: json["about"],
        email: List<String>.from(json["email"].map((x) => x)),
        name: json["name"],
        picture: json["picture"],
    );

    Map<String, dynamic> toJson() => {
        "index": index,
        "about": about,
        "email": List<dynamic>.from(email.map((x) => x)),
        "name": name,
        "picture": picture,
    };
}

Upvotes: 2

Charlie Abou Moussa
Charlie Abou Moussa

Reputation: 135

First of all: You can use either

  • moor/moor_flutter moor flutter_moor
  • OR
  • built_value built_value

    To map the json String and generate fromJson/toJson functions.

    Example using moor:
  • First, create a moor database (if you have any question I am glad to answer).
  • Second, this would be the class you should use.
import 'dart:convert';
import 'package:db/moordb/database.dart';
import 'package:json_annotation/json_annotation.dart' as json;
import 'package:moor/moor.dart';

part 'user.g.dart';

@DataClassName("User")
class Users extends Table {
  IntColumn get id => integer().nullable().autoIncrement()();

  @JsonKey("index")
  IntColumn get index => text().nullable()();

  @JsonKey("about")
  TextColumn get about => text().nullable()();

  @JsonKey("email")
  TextColumn get emails => text().map(const EmailConverter()).nullable()();

  @JsonKey("name")
  TextColumn get name => text().nullable()();

  @JsonKey("picture")
  TextColumn get picture => text().nullable()();

  @override
  Set<Column> get primaryKey => {id};
}

class EmailConverter extends TypeConverter<List<String>, String> {
  const EmailConverter ();

  @override
  List<String> mapToDart(String fromDb) {
    if (fromDb == null) {
      return null;
    }
    List _emails = List<String>();
    (jsonDecode(fromDb)).forEach((value) {
      _emails.add(value);
    });
    return _emails;
  }

  @override
  String mapToSql(List<dynamic> value) {
    if (value == null) {
      return null;
    }
    return jsonEncode(value);
  }
}

Second:

It is preferred that you send the User object through:

In your case you are passing the object to the widget directly.
In conclusion, it is obvious that the String field email in your User object is not being populated by the decoded data which contains the emails in a List. (since you are using the Class User).

Note: lose the new keyword since it is no longer required in Dart 2

Upvotes: 0

Related Questions