OGANICA_CBRE
OGANICA_CBRE

Reputation: 1

Dart / Flutter - nested json to data table

I am trying to get the following json into a data table (CFTable). The json is in the structure of map>. I have the COA class that will take care of the inner map (Map), and a TransposedCF class to make a map from that (Map). I dont want to hard code the string keys for the outer map ("Acquisition", "BP Uplift"...etc) or the inner map ("2019", "2020"...etc) because that will constantly change. I'm having difficulty with the fromJson method for the TransposedCF class (hence the ?).

Also, after I build this class I would like to consume it in a table, but there are many errors there...

JSON:

{
  "Acquisition": {
    "2019": -78600000,
    "2020": 0,
    "2021": 0,
    "2022": 0,
    "2023": 0,
    "2024": 0,
    "2025": 0,
    "2026": 0,
    "2027": 0,
    "2028": 0,
    "2029": 0,
    "2030": 77527013.89465855
  },
  "BP Uplift": {
    "2019": 0,
    "2020": 0,
    "2021": 0,
    "2022": 0,
    "2023": 0,
    "2024": 0,
    "2025": 0,
    "2026": 0,
    "2027": 0,
    "2028": 0,
    "2029": 0,
    "2030": 0
  },
  "Capex": {
    "2019": 0,
    "2020": 0,
    "2021": 0,
    "2022": 0,
    "2023": 0,
    "2024": 0,
    "2025": 0,
    "2026": 0,
    "2027": 0,
    "2028": 0,
    "2029": 0,
    "2030": 0
  }
}

FLUTTER:

import 'package:flutter/material.dart';

class COA {
  final Map<String, double> values;

  const COA({@required this.values});

  factory COA.fromJson(Map json) {
    final values = json['values'];
    return COA(values: values);
  }
}

class TransposedCF {
  final String assetname;
  final Map<String, COA> coas;

  TransposedCF({this.assetname, this.coas});

  factory TransposedCF.fromJson(String name, List json) {
    return TransposedCF(
      assetname: name,
      coas: ?,
    );
  }
}

class CFTable extends StatelessWidget {
  final TransposedCF cf;

  CFTable({Key key, this.cf}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text("OGANICA"),
        DataTable(columns: _buildColumns(), rows: _buildDataRows()),
      ],
    );
  }

  List<DataColumn> _buildColumns() {
    final years = cf.coas.first.values.keys.toList()..sort();
    return [
      DataColumn(label: Text(cf.assetname)),
      for (String year in years) DataColumn(label: Text("$year"))
    ];
  }

  List<DataRow> _buildDataRows() {
    return cf.coas.map<DataRow>((coa) {
      final years = coa.values.keys.toList()..sort();
      return DataRow(cells: [
        DataCell(Text(coa.name)),
        ...years.map<DataCell>((year) {
          final value = coa.values[year];
          //TODO format value
          return DataCell(Text(value.toString()));
        })
      ]);
    }).toList(growable: false);
  }
}

Upvotes: 0

Views: 1018

Answers (1)

chunhunghan
chunhunghan

Reputation: 54367

You can copy paste run full code below
Step 1: Consume original json string to related Map , in this demo class Payload
Step 2: Transfer this Payload to List of year data
Step 3: use json_table to consume List of year data

working demo

enter image description here

code snippet

class Payload {
  Map<String, double> acquisition;
  Map<String, double> bpUplift;
  Map<String, double> capex;
...  
class YearData {
  String year;
  double acquisition;
  double bpUplift;
  double capex;  
...  
void transfer() {
    Payload payload = payloadFromJson(jsonString);
    List<YearData> yearDataList = [];

    for (var val in payload.acquisition.keys) {
      var year = val;
      var acquisition = payload.acquisition[val];
      var capex = payload.capex[val];
      var bpUplift = payload.bpUplift[val];
      yearDataList.add(YearData(
          year: year,
          acquisition: acquisition,
          bpUplift: bpUplift,
          capex: capex));
    }

    jsonSample = yearDataToJson(yearDataList);
}  

full code

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

import 'dart:convert';

Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));

String payloadToJson(Payload data) => json.encode(data.toJson());

class Payload {
  Map<String, double> acquisition;
  Map<String, double> bpUplift;
  Map<String, double> capex;

  Payload({
    this.acquisition,
    this.bpUplift,
    this.capex,
  });

  factory Payload.fromJson(Map<String, dynamic> json) => Payload(
        acquisition: Map.from(json["Acquisition"])
            .map((k, v) => MapEntry<String, double>(k, v.toDouble())),
        bpUplift: Map.from(json["BP Uplift"])
            .map((k, v) => MapEntry<String, double>(k, v.toDouble())),
        capex: Map.from(json["Capex"])
            .map((k, v) => MapEntry<String, double>(k, v.toDouble())),
      );

  Map<String, dynamic> toJson() => {
        "Acquisition": Map.from(acquisition)
            .map((k, v) => MapEntry<String, dynamic>(k, v)),
        "BP Uplift":
            Map.from(bpUplift).map((k, v) => MapEntry<String, dynamic>(k, v)),
        "Capex": Map.from(capex).map((k, v) => MapEntry<String, dynamic>(k, v)),
      };
}

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

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

class YearData {
  String year;
  double acquisition;
  double bpUplift;
  double capex;

  YearData({
    this.year,
    this.acquisition,
    this.bpUplift,
    this.capex,
  });

  factory YearData.fromJson(Map<String, dynamic> json) => YearData(
        year: json["year"],
        acquisition: json["Acquisition"],
        bpUplift: json["BPUplift"],
        capex: json["Capex"],
      );

  Map<String, dynamic> toJson() => {
        "year": year,
        "Acquisition": acquisition,
        "BPUplift": bpUplift,
        "Capex": capex,
      };
}

class SimpleTable extends StatefulWidget {
  @override
  _SimpleTableState createState() => _SimpleTableState();
}

class _SimpleTableState extends State<SimpleTable> {
  String jsonString = '''
  {
  "Acquisition": {
    "2019": -78600000,
    "2020": 0,
    "2021": 0,
    "2022": 0,
    "2023": 0,
    "2024": 0,
    "2025": 0,
    "2026": 0,
    "2027": 0,
    "2028": 0,
    "2029": 0,
    "2030": 77527013.89465855
  },
  "BP Uplift": {
    "2019": 0,
    "2020": 0,
    "2021": 0,
    "2022": 0,
    "2023": 0,
    "2024": 0,
    "2025": 0,
    "2026": 0,
    "2027": 0,
    "2028": 0,
    "2029": 0,
    "2030": 0
  },
  "Capex": {
    "2019": 0,
    "2020": 0,
    "2021": 0,
    "2022": 0,
    "2023": 0,
    "2024": 0,
    "2025": 0,
    "2026": 0,
    "2027": 0,
    "2028": 0,
    "2029": 0,
    "2030": 0
  }
}
  ''';
  String jsonSample = "";

  bool toggle = true;
  List<YearData> yearDataList = [];

  @override
  void initState() {
    // TODO: implement initState
    transfer();
    super.initState();
  }

  void transfer() {
    Payload payload = payloadFromJson(jsonString);
    List<YearData> yearDataList = [];

    for (var val in payload.acquisition.keys) {
      var year = val;
      var acquisition = payload.acquisition[val];
      var capex = payload.capex[val];
      var bpUplift = payload.bpUplift[val];
      yearDataList.add(YearData(
          year: year,
          acquisition: acquisition,
          bpUplift: bpUplift,
          capex: capex));
    }

    jsonSample = yearDataToJson(yearDataList);
  }

  @override
  Widget build(BuildContext context) {
    var json = jsonDecode(jsonSample);
    return Scaffold(
      body: Container(
        padding: EdgeInsets.all(16.0),
        child: toggle
            ? Column(
                children: [
                  JsonTable(
                    json,
                    showColumnToggle: true,
                    tableHeaderBuilder: (String header) {
                      return Container(
                        padding: EdgeInsets.symmetric(
                            horizontal: 8.0, vertical: 4.0),
                        decoration: BoxDecoration(
                            border: Border.all(width: 0.5),
                            color: Colors.grey[300]),
                        child: Text(
                          header,
                          textAlign: TextAlign.center,
                          style: Theme.of(context).textTheme.display1.copyWith(
                              fontWeight: FontWeight.w700,
                              fontSize: 14.0,
                              color: Colors.black87),
                        ),
                      );
                    },
                    tableCellBuilder: (value) {
                      return Container(
                        padding: EdgeInsets.symmetric(
                            horizontal: 4.0, vertical: 2.0),
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 0.5,
                                color: Colors.grey.withOpacity(0.5))),
                        child: Text(
                          value,
                          textAlign: TextAlign.center,
                          style: Theme.of(context).textTheme.display1.copyWith(
                              fontSize: 14.0, color: Colors.grey[900]),
                        ),
                      );
                    },
                    allowRowHighlight: true,
                    rowHighlightColor: Colors.yellow[500].withOpacity(0.7),
                    paginationRowCount: 20,
                  ),
                  SizedBox(
                    height: 20.0,
                  ),
                  Text("Simple table which creates table direclty from json")
                ],
              )
            : Center(
                child: Text(getPrettyJSONString(jsonSample)),
              ),
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.grid_on),
          onPressed: () {
            setState(
              () {
                toggle = !toggle;
              },
            );
          }),
    );
  }

  String getPrettyJSONString(jsonObject) {
    JsonEncoder encoder = new JsonEncoder.withIndent('  ');
    String jsonString = encoder.convert(json.decode(jsonObject));
    return jsonString;
  }
}

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

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

Upvotes: 1

Related Questions