Home > Enterprise >  How to display the data fetched from API?
How to display the data fetched from API?

Time:02-04

I have fetched the details of the planet i.e. (NOM) No. of moons, Gravity and Density from an API. And i have stored these details in an array PlanetInfo. And i want to display it using text widget like Text("${PlanetInfo[1]}", style: TextStyle(color: Colors.white)). but it is giving me an erro: RangeError (index): Invalid value: Valid value range is empty: 1

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:xperience/Models/planets.dart';

class PlanetDescNoMGD extends StatelessWidget {
  final Planet planeteee;
  List PlanetInfo = [];
  getPlanetData() async {
    var url =
        "https://api.le-systeme-solaire.net/rest/bodies/${planeteee.planetApi}";
    final uri = Uri.parse(url);
    final response = await http.get(uri);
    final body = response.body;
    final jsondata = jsonDecode(body);

    PlanetInfo.add(jsondata["moons"].length);
    PlanetInfo.add(jsondata["gravity"]);
    PlanetInfo.add(jsondata["density"]);
  }

  PlanetDescNoMGD({Key? key, required this.planeteee}) : super(key: key);
  @override
  void initState() {
    this.getPlanetData();
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: <Widget>[
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "No. of moons",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w700),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[1]}", style: TextStyle(color: Colors.white))
          ],
        ),
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "Gravity",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[1]}"   " m/s²",
                style: TextStyle(color: Colors.white))
            //Text(${num}   " m/s²", style: TextStyle(color: Colors.white))
          ],
        ),
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "Density",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[2]}"   " g/cm3",
                style: TextStyle(color: Colors.white))
          ],
        ),
      ],
    );
  }
}

I need a solution.

CodePudding user response:

  1. You do not know how to work with async functions. Please learn it. You are making async request to API and directly trying to use respond from API. It is not possible. What is happening is your List PlanetInfo is empty when build is called. so you are getting error.

  2. Stateless widgets does not have initState! I see you are trying to override initState that does not exist.

  3. You need stateful widget to use setState.

  4. Here is, with minimal change working version of your code. You need to use setState after data is loaded and change isLoaded = true.

Here is solution:

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:xperience/Models/planets.dart';

class PlanetDescNoMGD extends StatefulWidget {
  PlanetDescNoMGD({Key? key, required this.planeteee}) : super(key: key);

  final Planet planeteee;

  @override
  State<PlanetDescNoMGD> createState() => _PlanetDescNoMGDState();
}

class _PlanetDescNoMGDState extends State<PlanetDescNoMGD> {
  List PlanetInfo = [];

  bool isLoaded = false;

  getPlanetData() async {
    var url =
        "https://api.le-systeme-solaire.net/rest/bodies/${widget.planeteee.planetApi}";
    final uri = Uri.parse(url);
    final response = await http.get(uri);
    final body = response.body;
    final jsondata = jsonDecode(body);

    PlanetInfo.add(jsondata["moons"].length);
    PlanetInfo.add(jsondata["gravity"]);
    PlanetInfo.add(jsondata["density"]);
    setState(() {
      isLoaded = true;
    });
  }

  @override
  void initState() {
    super.initState();
    getPlanetData();
  }

  @override
  Widget build(BuildContext context) {
    return !isLoaded
        ? const Center(child: CircularProgressIndicator())
        : Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  const Text(
                    "No. of moons",
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.w700),
                  ),
                  const SizedBox(
                    height: 12,
                  ),
                  Text("${PlanetInfo[1]}",
                      style: TextStyle(color: Colors.white))
                ],
              ),
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  const Text(
                    "Gravity",
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.w600),
                  ),
                  const SizedBox(
                    height: 12,
                  ),
                  Text("${PlanetInfo[1]}"   " m/s²",
                      style: TextStyle(color: Colors.white))
                  //Text(${num}   " m/s²", style: TextStyle(color: Colors.white))
                ],
              ),
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  const Text(
                    "Density",
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.w600),
                  ),
                  const SizedBox(
                    height: 12,
                  ),
                  Text("${PlanetInfo[2]}"   " g/cm3",
                      style: TextStyle(color: Colors.white))
                ],
              ),
            ],
          );
  }
}

CodePudding user response:

You have got 2 things to fix there.

  1. Class.
    Do not use PlanetInfo as a list of ints. Make full use of defining a class: encapsulating data and improving readability.

Define the class as follows

PlanetInfo{
int noOfMoons;
double gravity;
double density;
PlanetInfo({
 required this.noOfMoons,
 required this.gravity,
 required this.density,
 });
}

Declare a member in state.

List PlanetInfo = [];//remove this
late final PlanetInfo myPlanet;// use this

Now create an object in your fetch call and assign it to state member.

 final jsondata = jsonDecode(body);

    PlanetInfo tempPlanet=PlanetInfo(
               noOfMoons: jsondata["moons"].length,
               gravity: jsondata["gravity"],
               density: jsondata["density"],
);
myPlanet=x; // use setState() if required

and display in widgets using attributes.

//rest of code

    Text("${planetInfo.noOfMoons}",

 //rest of code

     Text("${planetInfo.gravity}}"   " m/s²",'

 //rest of code  
            
     Text("${planetInfo.density}"   " g/cm3",

 //rest of code
  1. Displaying API data.

You can either use FutureBuilder to wait on building UI until api call is done, or do as @hiloliddin suggested (using isLoaded member and building ui based on its value).

In your current implementation you were getting the error because UI was built before api call finished and the list PlanetInfo was empty.

  • Related