0

I have 2 JSON file like this:

json1 (API):

[
  {
    "json1Language": "English",
    "json1Icon": "https://www.countryflags.io/gb/flat/64.png",
    "json1Code": "en"
  },
  {
    "json1Language": "French",
    "json1Icon": "https://www.countryflags.io/fr/flat/64.png",
    "json1Code": "fr"
  },
  {
    "json1Language": "Spanish",
    "json1Icon": "https://www.countryflags.io/es/flat/64.png",
    "json1Code": "es"
  }
]

json2 (API):

[
  {
    "json2Country": "Canada",
    "json2Continent": "North American",
    "json2Language": [
      "French",
      "English"
    ]
  },
  {
    "json2Country": "Mexico",
    "json2Continent": "North American",
    "json2Language": [
      "Spanish",
      "English"
    ]
  },
  {
    "json2Country": "United Kingdom",
    "json2Continent": "Europe",
    "json2Language": [
      "English"
    ]
  },
  {
    "json2Country": "France",
    "json2Continent": "Europe",
    "json2Language": [
      "French"
    ]
  },
  {
    "json2Country": "Spain",
    "json2Continent": "Europe",
    "json2Language": [
      "Spanish"
    ]
  }
]

I tried to show the data of json1Code from Json1, it shows an error Flutter: RangeError (index): Invalid value: Valid value range is empty: -1 for a few seconds then shows the data correctly, I'm not sure where I did wrong enter image description here

I think maybe something wrong in the Build class:

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following RangeError was thrown building Builder(dirty):
RangeError (index): Invalid value: Valid value range is empty: -1

The relevant error-causing widget was: 
  Builder file:///D:/Flutter/Test/load_data/lib/json2_page3.dart:80:17
When the exception was thrown, this was the stack: 
#0      List.[] (dart:core-patch/growable_array.dart:177:60)
#1      _ShowContinentState.build.<anonymous closure> (package:load_data/json2_page3.dart:83:38)
#2      Builder.build (package:flutter/src/widgets/basic.dart:7183:48)
#3      StatelessElement.build (package:flutter/src/widgets/framework.dart:4644:28)
#4      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4570:15)

please help me, this is main file

import 'package:flutter/material.dart';
import 'package:load_data/model/json2_model.dart';
import 'package:load_data/service/json1_service.dart';
import 'package:load_data/service/json2_service.dart';
import 'model/json1_model.dart';

class Json2Page3 extends StatefulWidget {
  @override
  _Json2Page3State createState() => _Json2Page3State();
}

class _Json2Page3State extends State<Json2Page3> {
  List<Json2> json2 = [];
  List<String> _continent = [];
  @override
  void initState() {
    super.initState();
    setState(() {
      Json2Services.getData().then((data) {
        setState(() {
          json2 = data;
          _continent = json2.map<String>((x) => x.json2Continent).toSet().toList();
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        length: _continent.length,
        child: Scaffold(
          appBar: AppBar(
            title: Text('Page 2'),
            bottom: TabBar(tabs: _continent.map((String name) => Tab(text: name)).toList()),
          ),
          body: TabBarView(
              children: _continent.map((String name) {
            return ShowContinent(
              json2: List<Json2>.from(json2)..retainWhere((e) => e.json2Continent == name),
            );
          }).toList()),
        ));
  }
}

class ShowContinent extends StatefulWidget {
  final List<Json2> json2;
  ShowContinent({this.json2});
  @override
  _ShowContinentState createState() => _ShowContinentState(json2);
}

class _ShowContinentState extends State<ShowContinent> {
  final List<Json2> json2;
  List<Json1> json1 = [];

  _ShowContinentState(this.json2);

  @override
  void initState() {
    super.initState();
    Json1Services.getData().then((data) {
      setState(() {
        json1 = data;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        for (Json2 j2 in json2)
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              Text(j2.json2Country.toUpperCase()),
              for (int i = 0; i < j2.json2Language.length; i++)
                Builder(
                  builder: (_) {
                    int index = json1.indexWhere((e) => e.json1Language == j2.json2Language[i]);
                    return Row(
                      children: [
                        Image.network(json1[index].json1Icon),
                        Text(json1[index].json1Code),
                      ],
                    );
                  },
                )
            ],
          ),
      ],
    );
  }
}


3
  • I recommend you read more on Asynchronous programming: futures, async, await. This will save you lots of headaches. There are also amazing videos from the Flutter team on the topic Commented Sep 9, 2020 at 23:37
  • can not reproduce this error. please post full code and ping my name. thanks. Commented Sep 10, 2020 at 7:23
  • @chunhunghan I updated full code and JSON (I added more data to json1 so that when json2 shows data of json1, it will take longer and shows an error), please help me Commented Sep 10, 2020 at 13:02

2 Answers 2

1

You can copy paste run full code below
You can use addPostFrameCallback and bool isLoading to check loading status
when isLoading == true, return CircularProgressIndicator()
code snippet

bool isLoading = true;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      Json1Services.getData().then((data) {
        setState(() {
          json1 = data;
          isLoading = false;
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return isLoading
        ? Center(child: CircularProgressIndicator())
        : Column(

working demo

enter image description here

full code

import 'package:flutter/material.dart';

import 'dart:convert';

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

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

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

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

class Json1 {
  Json1({
    this.json1Language,
    this.json1Icon,
    this.json1Code,
  });

  String json1Language;
  String json1Icon;
  String json1Code;

  factory Json1.fromJson(Map<String, dynamic> json) => Json1(
        json1Language: json["json1Language"],
        json1Icon: json["json1Icon"],
        json1Code: json["json1Code"],
      );

  Map<String, dynamic> toJson() => {
        "json1Language": json1Language,
        "json1Icon": json1Icon,
        "json1Code": json1Code,
      };
}

class Json2 {
  Json2({
    this.json2Country,
    this.json2Continent,
    this.json2Language,
  });

  String json2Country;
  String json2Continent;
  List<String> json2Language;

  factory Json2.fromJson(Map<String, dynamic> json) => Json2(
        json2Country: json["json2Country"],
        json2Continent: json["json2Continent"],
        json2Language: List<String>.from(json["json2Language"].map((x) => x)),
      );

  Map<String, dynamic> toJson() => {
        "json2Country": json2Country,
        "json2Continent": json2Continent,
        "json2Language": List<dynamic>.from(json2Language.map((x) => x)),
      };
}

class Json2Services {
  static Future<List<Json2>> getData() async {
    await Future.delayed(Duration(seconds: 5), () {});

    String jsonString = '''
    [
  {
    "json2Country": "Canada",
    "json2Continent": "North American",
    "json2Language": [
      "French",
      "English"
    ]
  },
  {
    "json2Country": "Mexico",
    "json2Continent": "North American",
    "json2Language": [
      "Spanish",
      "English"
    ]
  },
  {
    "json2Country": "United Kingdom",
    "json2Continent": "Europe",
    "json2Language": [
      "English"
    ]
  },
  {
    "json2Country": "France",
    "json2Continent": "Europe",
    "json2Language": [
      "French"
    ]
  },
  {
    "json2Country": "Spain",
    "json2Continent": "Europe",
    "json2Language": [
      "Spanish"
    ]
  }
]
    ''';

    return Future.value(json2FromJson(jsonString));
  }
}

class Json1Services {
  static Future<List<Json1>> getData() async {
    await Future.delayed(Duration(seconds: 5), () {});
    String jsonString = '''
    [
  {
    "json1Language": "English",
    "json1Icon": "https://www.countryflags.io/gb/flat/64.png",
    "json1Code": "en"
  },
  {
    "json1Language": "French",
    "json1Icon": "https://www.countryflags.io/fr/flat/64.png",
    "json1Code": "fr"
  },
  {
    "json1Language": "Spanish",
    "json1Icon": "https://www.countryflags.io/es/flat/64.png",
    "json1Code": "es"
  }
]
    ''';

    return Future.value(json1FromJson(jsonString));
  }
}

class Json2Page3 extends StatefulWidget {
  @override
  _Json2Page3State createState() => _Json2Page3State();
}

class _Json2Page3State extends State<Json2Page3> {
  List<Json2> json2 = [];
  List<String> _continent = [];
  @override
  void initState() {
    super.initState();
    setState(() {
      Json2Services.getData().then((data) {
        setState(() {
          json2 = data;
          _continent =
              json2.map<String>((x) => x.json2Continent).toSet().toList();
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        length: _continent.length,
        child: Scaffold(
          appBar: AppBar(
            title: Text('Page 2'),
            bottom: TabBar(
                tabs:
                    _continent.map((String name) => Tab(text: name)).toList()),
          ),
          body: TabBarView(
              children: _continent.map((String name) {
            return ShowContinent(
              json2: List<Json2>.from(json2)
                ..retainWhere((e) => e.json2Continent == name),
            );
          }).toList()),
        ));
  }
}

class ShowContinent extends StatefulWidget {
  final List<Json2> json2;
  ShowContinent({this.json2});
  @override
  _ShowContinentState createState() => _ShowContinentState(json2);
}

class _ShowContinentState extends State<ShowContinent> {
  final List<Json2> json2;
  List<Json1> json1 = [];

  _ShowContinentState(this.json2);

  bool isLoading = true;
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      Json1Services.getData().then((data) {
        setState(() {
          json1 = data;
          isLoading = false;
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return isLoading
        ? Center(child: CircularProgressIndicator())
        : Column(
            children: [
              for (Json2 j2 in json2)
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    Text(j2.json2Country.toUpperCase()),
                    for (int i = 0; i < j2.json2Language.length; i++)
                      Builder(
                        builder: (_) {
                          int index = json1.indexWhere(
                              (e) => e.json1Language == j2.json2Language[i]);
                          return Row(
                            children: [
                              Image.network(json1[index].json1Icon),
                              Text(json1[index].json1Code),
                            ],
                          );
                        },
                      )
                  ],
                ),
            ],
          );
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Json2Page3(),
    );
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

still the perfect answer as always, thanks very much xD
0

When build() is called, json data is not ready.
So you need to fix code asynchronous.
I suggest one solution 'FutureBuilder' https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.