1

I have built a page which reads the json from recipeURL and I wish for it to display the product_name value in the json file. However for some reason my future fetchData () class isn't being read as none of the text in my if else statement is being displayed. Am I missing a simple oversight here?

EDIT: The main dart file is my main screen. This is where my navbar is created. Users are redirected to other pages when they click on the corresponding icon. Im having trouble passing BarcodePage(title:title); as parameters in my main file,26th line, can be found under Class MyAppState extends State<MyApp> {

My main dart file:

import 'package:flutter/material.dart';

import 'pages/BarcodePage.dart';
import 'pages/FoodPage.dart';
import 'pages/RecipePage.dart';
import 'pages/ShoppingPage.dart';


void main() {
  runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState(){
    return MyAppState();
  }
}


class MyAppState extends State<MyApp> {
 int _selectedPage =0;
 final _pageOptions= [
    FoodPage(),
    RecipePage(),
    BarcodePage(title: ,),
    ShoppingPage(),
  ];

  

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //title: 'Best B4',
        theme: ThemeData(
         primarySwatch: Colors.teal,),
         debugShowCheckedModeBanner: false,
         home: Scaffold (
           appBar: AppBar(
            title:Text(
              'BestB4',
              style: TextStyle(
                  fontFamily: 'PacificoRegular',
                  fontSize: 30,
              ),
            ),
            backgroundColor: Colors.teal,
            elevation: 20,
            actions: [
              IconButton(
                icon: Icon(Icons.qr_code_2_rounded),
                tooltip: 'Add item',
                onPressed:(){
                   Navigator.push(
                     context, 
                     MaterialPageRoute(builder: (context) => BarcodePage()));
                },
              )
              ],
              //ONPRESSED MENU OPEN
           ),
            body:_pageOptions[_selectedPage],
            bottomNavigationBar: BottomNavigationBar(
              type: BottomNavigationBarType.fixed,
              backgroundColor: Colors.teal,
              selectedItemColor: Colors.white,
              unselectedItemColor: Colors.white70,
              iconSize: 40,
              selectedFontSize: 15,
              unselectedFontSize: 15,
              currentIndex:_selectedPage,
              onTap: (int index) {
                setState(() {
                  _selectedPage  = index;
                });
              },
              items: [
                BottomNavigationBarItem(
                  icon:Icon(Icons.restaurant_rounded),
                  label: 'Food',
                  ), //, title:Text('Food')
                BottomNavigationBarItem(
                  icon:Icon(Icons.menu_book_rounded),
                  label:'Recipes',
                  ),//, title:Text('Recipes')
                BottomNavigationBarItem(
                  icon:Icon(Icons.add_outlined),
                  label:'Add',
                  ),//, title:Text('Add')
                 BottomNavigationBarItem(
                  icon:Icon(Icons.shopping_cart_rounded),
                  label:'Shopping',
                  ),//,title:Text('Shopping')
              ],
          ),
      ),
      ); 
  }
}

My BarcodePage dart file:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as p;
import 'package:flutter/services.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:http/http.dart';



class BarcodePage extends StatefulWidget{
  const BarcodePage({Key? key, required this.title}) : super(key: key);
  final String title;

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

var futuredata = {};

class _BarcodePageState extends State<BarcodePage> {
  int counter=0;
  String result= "";

  Future _scanBarcode() async{
    try{
      ScanResult scanResult = await BarcodeScanner.scan();
      String barcodeResult = scanResult.rawContent;
      setState(() {
        result = barcodeResult;
      });

    } on PlatformException catch (ex) {
      if (ex.code == BarcodeScanner.cameraAccessDenied) {
        setState((){
        result = "CAMERA PERMISSION WAS DENIED. \n EDIT THIS IN YOUR SETTINGS";
      });
    }else {
      setState(() {
        result = "404 ERROR UNKNOWN $ex";
      });
    }
  } on FormatException {
    setState(() {
      result = "SCAN AN ITEM";
    });
  } catch (ex){
    setState(() {
        result = "404 ERROR UNKNOWN $ex";
      });
    }
  }
  @override
  void initState() {}

  fetchmydata() async {
    var request = p.Request(
        'GET',
        Uri.parse(
            'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));

    StreamedResponse response = await request.send();

    if (response.statusCode == 200) {
      // print(await response.stream.bytesToString());
      var data = await response.stream.bytesToString();
      futuredata = json.decode(data);
    } else {
      print(response.reasonPhrase);
    }
  }

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.teal,
        title:Text('Add an item',
        style: TextStyle(
        fontFamily: 'Fredoka',
        fontSize: 25,
        ),
        ),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          FutureBuilder(
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting)
                return Center(
                  child: Container(
                    child: CircularProgressIndicator(),
                    height: 50,
                    width: 50,
                  ),
                );
              else if (snapshot.connectionState == ConnectionState.done)
                return ListTile(
                  title: Text(futuredata["product"]["product_name"].toString()),
                  subtitle: Text("France:" +
                      futuredata["product"]["product_name_en"].toString()),
                );
              else {
                return Container(
                  child: CircularProgressIndicator(),
                  height: 50,
                  width: 50,
                );
              }
            },
            future: fetchmydata(),
          )
        ],
      ),
      floatingActionButton: FloatingActionButton.extended(
        backgroundColor: Color.fromRGBO(51, 171, 160, 100),
        icon: Icon(Icons.camera_alt),
        label: Text("Scan"),
        onPressed: _scanBarcode,
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}

The Json file looks like this:

JSON LINK: https://world.openfoodfacts.org/api/v0/product/5060391623139.json

enter image description here

Maisie Brooke
  • 123
  • 1
  • 10
  • you can refer my below answers for getting data from API and display it into Flutter. [1]: https://stackoverflow.com/a/68533647/13997210 [2]: https://stackoverflow.com/a/68807671/13997210 [3]: https://stackoverflow.com/a/69131277/13997210 [4]: https://stackoverflow.com/a/68709502/13997210 [5]: https://stackoverflow.com/a/68594656/13997210 [6]: https://docs.flutter.dev/cookbook/networking/fetch-data – Ravindra S. Patil Mar 14 '22 at 10:27
  • could your add your json instead of image – lava Mar 14 '22 at 10:38
  • @lava I have just added it to my original question, thank you! – Maisie Brooke Mar 14 '22 at 10:42
  • @RavindraS.Patil Thank you for your reads, I have tried to follow your answers in them but still having no luck. – Maisie Brooke Mar 14 '22 at 11:23
  • Try use a FutureBuilder https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html – LearnFlutter Mar 14 '22 at 13:14

2 Answers2

0

enter image description here

You can read your json like this

var futuredata = {};
var productname=    futuredata["product"]["product_name"]

Your fetch method like this

 fetchmydata() async {
    var request = p.Request(
        'GET',
        Uri.parse(
            'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));

    StreamedResponse response = await request.send();

    if (response.statusCode == 200) {
      // print(await response.stream.bytesToString());
      var data = await response.stream.bytesToString();
      futuredata = json.decode(data);
    } else {
      print(response.reasonPhrase);
    }
  }

With model Class SampleModel? Mymodel = null; fetchmydata() async { var request = p.Request( 'GET', Uri.parse( 'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));

    StreamedResponse response = await request.send();

    if (response.statusCode == 200) {
      // print(await response.stream.bytesToString());
      var data = await response.stream.bytesToString();
      futuredata = json.decode(data);
      Mymodel = SampleModel.fromJson(futuredata);
    } else {
      print(response.reasonPhrase);
    }
  }
  1. in the method we first read data from json as string or text
  2. then we decode the string type or text from server to map type

enter image description here

enter image description here

enter image description here

SampleCode Dartpad live code check

import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:http/http.dart' as p;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

var futuredata = {};

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  @override
  void initState() {}

  fetchmydata() async {
    var request = p.Request(
        'GET',
        Uri.parse(
            'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));

    StreamedResponse response = await request.send();

    if (response.statusCode == 200) {
      // print(await response.stream.bytesToString());
      var data = await response.stream.bytesToString();
      futuredata = json.decode(data);
    } else {
      print(response.reasonPhrase);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          FutureBuilder(
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting)
                return Center(
                  child: Container(
                    child: CircularProgressIndicator(),
                    height: 50,
                    width: 50,
                  ),
                );
              else if (snapshot.connectionState == ConnectionState.done)
                return ListTile(
                  title: Text(futuredata["product"]["product_name"].toString()),
                  subtitle: Text("France:" +
                      futuredata["product"]["product_name_en"].toString()),
                );
              else {
                return Container(
                  child: CircularProgressIndicator(),
                  height: 50,
                  width: 50,
                );
              }
            },
            future: fetchmydata(),
          )
        ],
      ),
    );
  }
}

Sample ModelClass

///
/// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/
///
class SampleModelProduct {
/*
{
  "_id": "5060391623139",
  "_keywords": [
    "peanut"
  ],
  "product_name": "Peanut butter",
  "product_name_en": "Peanut butter",
  "product_name_fr": "Peanut butter"
}
*/

  String? Id;
  List<String?>? Keywords;
  String? productName;
  String? productNameEn;
  String? productNameFr;

  SampleModelProduct({
    this.Id,
    this.Keywords,
    this.productName,
    this.productNameEn,
    this.productNameFr,
  });

  SampleModelProduct.fromJson(Map<String, dynamic> json) {
    Id = json['_id']?.toString();
    if (json['_keywords'] != null) {
      final v = json['_keywords'];
      final arr0 = <String>[];
      v.forEach((v) {
        arr0.add(v.toString());
      });
      Keywords = arr0;
    }
    productName = json['product_name']?.toString();
    productNameEn = json['product_name_en']?.toString();
    productNameFr = json['product_name_fr']?.toString();
  }

  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['_id'] = Id;
    if (Keywords != null) {
      final v = Keywords;
      final arr0 = [];
      v!.forEach((v) {
        arr0.add(v);
      });
      data['_keywords'] = arr0;
    }
    data['product_name'] = productName;
    data['product_name_en'] = productNameEn;
    data['product_name_fr'] = productNameFr;
    return data;
  }
}

class SampleModel {
/*
{
  "code": "5060391623139",
  "product": {
    "_id": "5060391623139",
    "_keywords": [
      "peanut"
    ],
    "product_name": "Peanut butter",
    "product_name_en": "Peanut butter",
    "product_name_fr": "Peanut butter"
  },
  "status": 1,
  "status_verbose": "product found"
}
*/

  String? code;
  SampleModelProduct? product;
  int? status;
  String? statusVerbose;

  SampleModel({
    this.code,
    this.product,
    this.status,
    this.statusVerbose,
  });

  SampleModel.fromJson(Map<String, dynamic> json) {
    code = json['code']?.toString();
    product = (json['product'] != null)
        ? SampleModelProduct.fromJson(json['product'])
        : null;
    status = json['status']?.toInt();
    statusVerbose = json['status_verbose']?.toString();
  }

  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['code'] = code;
    if (product != null) {
      data['product'] = product!.toJson();
    }
    data['status'] = status;
    data['status_verbose'] = statusVerbose;
    return data;
  }
}
lava
  • 6,020
  • 2
  • 31
  • 28
  • no i didnt. i direct convert the json string to map and call it – lava Mar 14 '22 at 15:14
  • i just adde sample factory class .i used online model class genertator – lava Mar 14 '22 at 15:32
  • based on the question . i only added product name .this json contain more than 100 properties so skip that. – lava Mar 14 '22 at 16:44
  • The flutter generator create the .g.dart file reducing the keystroking. It uses the class properties to create the map – Golden Lion Mar 14 '22 at 19:28
  • thanks .i know some of this properties custom object type .so writing 100 properties and there object type creating and use this devdependecy is time take.so using this online converter is better. – lava Mar 14 '22 at 19:49
  • Thank you so much @lava & @Golden Lion for your help, this was an issue I was stuck on for days! Only issue Im now having is passing the title variable as the parameter for `BarcodePage()` on my main screen. Idea is when the barcode button is pressed in main navbar it directs the user to the BarcodePage. Button works fine. Im just having trouble trying to pass title as `BarcodePage(title:title)` however its now saying title is an undefined name. Code is here: [link] (https://www.codepile.net/pile/9Qn1kEz2) – Maisie Brooke Mar 15 '22 at 11:19
  • you didnt add barcodepage page .please add – lava Mar 15 '22 at 11:27
  • `class MyAppState extends StatefulWidget { var title; MyAppState({Key? key, this.title}) : super(key: key); @override State createState() => _MyAppStateState(); }` – lava Mar 15 '22 at 11:27
  • you can pass named parameters to a constructor by changing the constructor to myclass({this.field1}) final string field1; – Golden Lion Mar 15 '22 at 12:16
  • call in my app `BarcodePage(title:'mybarcode'))` insteada`Barcode()` you used required attribute for `title` argument. – lava Mar 15 '22 at 12:28
0

try creating a .g.dart file using flutter packages pub run build_runner build. flutter automatically will create your binding class factory. once you have the binding classes created flutter will automatically code your binding class, including nested classes. I personally think automation is the way to handle all interactions with json from the server. The reason you want to use the future .g.dart code generator is to reduce the possibility of error and incorrect type casting.

file.dart
factory ProductView.fromJson(Map<String, dynamic> json) =>
      _$ProductFromJson(json);
Map<String, dynamic> toJson() => _$ProductViewToJson(this);

file.g.dart


ProductView _$ProductViewFromJson(Map<String, dynamic> json) {
  return
ProductView(
    json['field1'] as int,
    json['field2'] as String,
    json['field3'] == null
        ? null
        : DateTime.parse(json['field3'] as String),
  );
}

Map<String, dynamic> _$ProjectViewToJson(ProductView instance) =>
    <String, dynamic>{
      'field1': instance.field1,
      'field2': instance.field2,
      'field3': instance.field3?.toIso8601String(),
    };

decoding the json

 var client = http.Client();
      Map<String, String> headers = new HashMap();
      headers['Accept'] = 'application/json';
      headers['Content-Type'] = 'application/json';
      headers['Authorization'] = 'Bearer $token';
var response = await client.get(url, headers: headers).timeout(_TIMEOUT);
    var parsed = json.decode(response.body);
    var view = ProductView.fromJson(parsed);
Golden Lion
  • 3,840
  • 2
  • 26
  • 35