List from json API response - flutter

I'm trying to use https://pub.dev/packages/flappy_search_bar#-readme-tab- to create a list of data which I plan on getting from an api(just testing now), but I can't seem to add the list created from the response json to the search widget.
The argument type 'Future<List<Album>> Function()' can't be assigned to the parameter type 'Future<List<Album>> Function(String)'.
class Album {
final int userId;
final int id;
final String title;
Album({this.userId, this.id, this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
Future<List<Album>> fetchAlbum() async {
final response =
await http.get('https://jsonplaceholder.typicode.com/albums/1');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
List jsonResponse = json.decode(response.body);
return jsonResponse.map((job) => Album.fromJson(job)).toList();
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
#override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SearchBar<Album>(
onSearch: fetchAlbum, <------ error here
onItemFound: (Album post, int index) {
return ListTile(
onTap: () => widget.setProviderData(post.title),
title: Text(post.title),
subtitle: Text(post.id.toString()),
);
},
),
),
);
}
Can anyone help me with this, please?

I can't test your code right now, but at first glance the problem is onSearch expects a function that gets String parameter and your code doesn't provide it.
You should modify this line Future<List<Album>> fetchAlbum() async as follows:
Future<List<Album>> fetchAlbum(String album) async

Related

Retrieve Data from Realtime Database in Flutter

I want to retrieve data from a realtime database for a flutter application. My data is built like this.
I need to loop through this data to display it on the application (ecommerce app, obviously). I have tried and failed in many ways. Currently when trying to get the data I see "Instance of '_Future'" as the message.
class Cart extends StatefulWidget {
Cart({Key? key}) : super(key: key);
#override
State<Cart> createState() => _CartState();
}
class _CartState extends State<Cart> {
DatabaseReference ref = FirebaseDatabase.instance.ref();
Object? products;
List productList = [];
String displayText = 'Results go here!';
snapshot() async {
final snapshot = await ref.child('Products').get();
productList = [];
if (snapshot.exists) {
productList.add(snapshot.value);
products = (snapshot.value);
print(snapshot);
print(snapshot.value);
} else {
print('No Data Available');
}
}
#override
void initState() {
super.initState();
snapshot();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: const PreferredSize(
preferredSize: Size.fromHeight(60), child: MyAppBar()),
body: Column(
children: [
ElevatedButton(
onPressed: () async {
// await ref.set({"name": "Tyler"});
snapshot();
},
child: Text("Add Data"),
),
Text("${snapshot()}", style: TextStyle(color: Colors.white))
],
)
);
}
}
I also have this data class built from other posts I have seen. I have to admit, I am not entirely sure how to use it.
import 'dart:convert';
class ProductData {
final int productID;
final String productCategory;
final String productDesc;
final String productName;
final String productPrice;
final String productSize;
final bool productInStock;
final String productImage1;
final String productGender;
final String productImage2;
ProductData(
{required this.productID,
required this.productCategory,
required this.productDesc,
required this.productName,
required this.productPrice,
required this.productSize,
required this.productInStock,
required this.productImage1,
required this.productGender,
required this.productImage2});
ProductData copyWith(
{int? productID,
String? productCategory,
String? productDesc,
String? productName,
String? productPrice,
String? productSize,
bool? productInStock,
String? productImage1,
String? productGender,
String? productImage2}) {
return ProductData(
productID: productID ?? this.productID,
productCategory: productCategory ?? this.productCategory,
productDesc: productDesc ?? this.productDesc,
productName: productName ?? this.productName,
productPrice: productPrice ?? this.productPrice,
productSize: productSize ?? this.productSize,
productInStock: productInStock ?? this.productInStock,
productImage1: productImage1 ?? this.productImage1,
productGender: productGender ?? this.productGender,
productImage2: productImage2 ?? this.productImage2,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'productID': productID,
'productCategory': productCategory,
'productDesc': productDesc,
'productName': productName,
'productPrice': productPrice,
'productSize': productSize,
'productInStock': productInStock,
'productImage1': productImage1,
'productGender': productGender,
'productImage2': productImage2,
};
}
factory ProductData.fromMap(Map<String, dynamic> map) {
return ProductData(
productID: map['productID'] as int,
productCategory: map['productCategory'] as String,
productDesc: map['productDesc'] as String,
productName: map['productName'] as String,
productPrice: map['productPrice'] as String,
productSize: map['productSize'] as String,
productInStock: map['productInStock'] as bool,
productImage1: map['productImage1'] as String,
productGender: map['productGender'] as String,
productImage2: map['productImage2'] as String,
);
}
String toJson() => json.encode(toMap());
factory ProductData.fromJson(String source) =>
ProductData.fromMap(json.decode(source) as Map<String, dynamic>);
#override
String toString() {
return 'ProductData(productID: $productID, productCategory: $productCategory, productDesc: $productDesc, productName: $productName, productPrice: $productPrice, productSize: $productSize, productInStock: $productInStock, productImage11: $productImage1, productGender: $productGender, productImage2: $productImage2)';
}
#override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ProductData &&
other.productID == productID &&
other.productCategory == productCategory &&
other.productDesc == productDesc &&
other.productName == productName &&
other.productPrice == productPrice &&
other.productSize == productSize &&
other.productInStock == productInStock &&
other.productImage1 == productImage1 &&
other.productGender == productGender &&
other.productImage2 == productImage2;
}
#override
int get hashCode {
return productID.hashCode ^
productCategory.hashCode ^
productDesc.hashCode ^
productName.hashCode ^
productPrice.hashCode ^
productSize.hashCode ^
productInStock.hashCode ^
productImage1.hashCode ^
productGender.hashCode ^
productImage2.hashCode;
}
}
Since the data is loaded from Firebase asynchronously, its get() method returns a Future. That's also why you had to declare your snapshot() function as async, which means that you also return a Future.
On its own the rendering code doesn't know anything about Futures, so it renders it by calling its toString() method, which leads to the output you see:
Instance of '_Future'
What you want instead is to wait for the future to resolve, which is just a fancy way of saying that you want to wait for the data to load. An easy way to do that is to use a FutureBuilder, which handles the asynchronous nature of a Future and all possible states it can be in.
That'd look something like:
snapshot() async {
final snapshot = await ref.child('Products').get();
productList = [];
if (snapshot.exists) {
productList.add(snapshot.value);
products = (snapshot.value);
} else {
print('No Data Available');
}
return productList;
}
body: Column(
children: [
ElevatedButton(
onPressed: () async {
snapshot();
},
child: Text("Add Data"),
),
FutureBuilder(
future: snapshot(),
builder: (BuildContext context, AsyncSnapshot asyncSnapshot) {
if (snapshot.hasData) {
var productList = asyncSnapshot.data! as List;
return Text(productList.length.toString());
} else if (snapshot.hasError) {
return Text('Error: ${asyncSnapshot.error}');
} else {
return CircularProgressIndicator(),
}
}
)
],
)

Display data fetched from JSON API in app

I am developing a Stock app in which I have to display News related to the stocks. I made a News class for the same as well as a factory constructor to convert the data from json
class News {
final String title;
final String desc;
final String imgURL;
final String url;
News(
{required this.title,
required this.desc,
required this.imgURL,
required this.url});
factory News.fromJSON(Map<String, dynamic> json) {
final title = json["title"] as String;
final desc = json["description"] as String;
final imgUrl = json["image_url"] as String;
final url = json["url"] as String;
return News(title: title, desc: desc, imgURL: imgUrl, url: url);
}
}
I have made a method to fetch the data from the API:
Future getNews() async {
final response = await http.get(Uri.parse(
'https://api.stockdata.org/v1/news/all?&filter_entities=true&language=en&api_token=${api_token}&countries=${country}'));
if (response.statusCode == 200) {
final jsonResponse = json.decode(response.body);
return jsonResponse.map((data) => News.fromJSON(data));
} else {
throw Exception('Unexpected error occurred!');
}
}
I am having trouble understanding how I can display the data in my app. I tried using FutureBuilder but I can't seem to understand how it's working.
Any help would be appreciated!
For the FutureBuilder you can do it this way :
FutureBuilder(
future: getNews(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
// Save your data in a variable
List<News> news = snapshot.data;
// Create a listview to show all of the news
return newsListView(news); //This is a list
} else {
return Center(
child: Container(
width: 300,
height: 290,
child: Center(child: Text("Error"))
)
);
}
}
),

How to fix "Unhandled Exception: Null check operator used on a null value" error in flutter?

I'm new to flutter.
I want to pass data from frontend to node.js backend through rest APIs(using post method). But it shows following error when app is executed.
This is the code I wrote so far. I tried to find what the error is, but unfortunately I could not find it. can somebody to help me to figure out this issue?
Model file
DataModel dataModelFromJSON(String str) => DataModel.fromJson(jsonDecode(str));
String dataModelToJson(DataModel data) => json.encode(data.toJson());
class DataModel {
DataModel({required this.title, required this.id});
String title;
String id;
factory DataModel.fromJson(Map<String, dynamic> json) =>
DataModel(title: json['title'], id: json['id']);
Map<String, dynamic> toJson() => {"name": title, "id": id};
}
Error occurred page
class PurchaseOrder extends StatefulWidget {
#override
_PurchaseOrderState createState() => _PurchaseOrderState();
}
Future<DataModel?> submitData(String title) async {
var response = await http.post(
Uri.http('176.12.10.0:8020', 'order/create'),
body: {"title": title},
);
print(title);
var data = response.body;
print(data);
if (response.statusCode == 201) {
String responseString = response.body;
return dataModelFromJSON(responseString);
} else
return null;
}
class _PurchaseOrderState extends State<PurchaseOrder> {
String today = DateFormat('yMd').format(DateTime.now());
late DataModel _dataModel;
TextEditingController titleController = TextEditingController();
#override
Widget build(BuildContext context) {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
return Container(
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your email',
),
controller: titleController,
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton(
onPressed: () async {
String title = titleController.text;
DataModel? data = await submitData(title);
setState(() {
_dataModel = data!;
});
},
child: Text("Submit"),
),
),
),
],
),
);
}
}
I hope your help to fix this issue.
Thank you
Edited:
I did following changes to the code. Error is gone. But data have not passed to the backend. What can I do.
I changed,
_dataModel = data!;
to
if (data != null) {
_dataModel = data;
}
The only null check operator in your code is _dataModel = data!;
That means your submitData method has returned a null value that was passed to data. Or when you put a null check operator you have to make sure the variable isn't null.
To avoid this error you could check if data is null and if true pass another value :
_dataModel = data ?? otherValue
The error means that somewhere in your code you are doing something with a non-nullable type, but the value is actually null.
When you use data! for example, you are telling the compiler that data will not be null, but it actually is.
You could use data ?? someValue to have a fallback, in case data is null.
I could fix "data not passing issue" also.
What I did?
I changed post request from,
var response = await http.post(
Uri.http('176.12.10.0:8020', 'order/create'),
body: {"title": title},
);
to
var response = await http.post(
Uri.parse('http://176.12.10.0:8020/order/create'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({"title": title}),
);

fetch data by using flutter http request and load more data on scroll down the screen

i fetch data from server using flutter http request and load more data when user scroll to bottom of screen. i receive this error "Unhandled Exception: type 'List' is not a subtype of type 'Product'". Please help, i struggle all day without success.
model.dart file
class Product {
final int id;
final String accountName,
callNumber,
whatsappNumber,
businessLocation,
caption;
final List<Images> productPhoto;
Product({
this.id,
this.accountName,
this.callNumber,
this.whatsappNumber,
this.businessLocation,
this.caption,
this.productPhoto,
});
// this is static method
factory Product.fromJson(Map<String, dynamic> json) {
return Product(
id: json['id'],
accountName: json['account_name'],
callNumber: json['call_number'],
whatsappNumber:
json['whatsapp_number'] != null ? json['whatsapp_number'] : null,
businessLocation: json['business_location'],
caption: json['caption'],
productPhoto:
(json['post_photos'] as List).map((i) => Images.fromJson(i)).toList(),
);
}
}
class Images {
final String filename;
Images({this.filename});
factory Images.fromJson(Map<String, dynamic> json) {
return Images(
filename: json['filename'],
);
}
}
explore.dart file (i import models.dart to this file)
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:windowshoppi/models/global.dart';
import 'package:windowshoppi/models/product.dart';
import 'package:http/http.dart' as http;
class Explore extends StatefulWidget {
#override
_ExploreState createState() => _ExploreState();
}
class _ExploreState extends State<Explore> {
ScrollController _scrollController = ScrollController();
List<Product> data;
String nextUrl;
#override
void initState() {
// TODO: implement initState
super.initState();
this.fetchProduct(http.Client(), ALL_PRODUCT_URL);
_scrollController.addListener(() {
// print(_scrollController.position.pixels);
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
if (nextUrl != null) {
this.fetchProduct(http.Client(), nextUrl);
}
// print(nextUrl);
}
});
}
Future<List<Product>> fetchProduct(http.Client client, url) async {
final response = await client.get(url);
if (response.statusCode == 200) {
Map<String, dynamic> mapResponse = json.decode(response.body);
nextUrl = mapResponse['next'];
if (mapResponse["count"] != "") {
final products = mapResponse["results"].cast<Map<String, dynamic>>();
final listOfProducts = await products.map<Product>((json) {
return Product.fromJson(json);
}).toList();
// return listOfProducts;
setState(() {
data.add(listOfProducts);
});
} else {
return [];
}
} else {
throw Exception('failed to load data from internet');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('http get'),
),
body: ListView.builder(
controller: _scrollController,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Container(
height: 200,
color: Colors.blue,
child: Text(data[index].caption),
),
);
},
),
);
}
}
Have a look at this part of the code.
final listOfProducts = await products.map<Product>((json) {
return Product.fromJson(json);
}).toList();
In the .map() method you are casting it to type < Product >. So judging by the error you have mentioned, "Unhandled Exception: type 'List' is not a subtype of type Product"
I think the json data being returned contains a List, instead of the product fields. I would highly recommend you to once check the json data being returned, and double-check if you are targeting the correct JSON tree nodes.
Let me know if this solved the issue.

Error by reading simple Json File - The getter 'visible' was called on null

First of all, I am new to flutter, dart and also StackOverflow..
I just wanted to experience some first insights to flutter and parsing a json file.
However I am getting an error, that the getter 'visible' was called on null.
By going to the debug mode in flutter, I can clearly see all the data provided from the API, but the frontend just shows nothing.
Just the mentioned error in the debug console.
This is the very simple code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'JSON',
home: Scaffold(
appBar: AppBar(
title: Text('JSON'),
),
body: Container(
child: FutureBuilder<List<User>>(
future: fetchListUser(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
List<User> users = snapshot.data;
return ListView(
children: users.map((user) {
Text('UserName: ${user.username}');
}).toList(),
);
} else {
return CircularProgressIndicator();
}
}),
),
),
);
}
}
Future<List<User>> fetchListUser() async {
final response = await http.get('https://jsonplaceholder.typicode.com/users');
if (response.statusCode == 200) {
List users = json.decode(response.body);
return users.map((user) => User.fromJson(user)).toList();
} else
throw Exception('Failed to Load Users');
}
class User {
final int id;
final String name, username, email, phone, website;
final Adresse adress;
final Company company;
User({
this.id,
this.name,
this.adress,
this.company,
this.email,
this.phone,
this.username,
this.website,
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
adress: Adresse.fromJson(json['address']),
company: Company.fromJson(json['company']),
email: json['email'],
id: json['id'],
name: json['name'],
phone: json['phone'],
username: json['username'],
website: json['website'],
);
}
}
class Adresse {
final String street, suite, zipcide;
final Geo geo;
Adresse({this.geo, this.street, this.suite, this.zipcide});
factory Adresse.fromJson(Map<String, dynamic> json) {
return Adresse(
geo: Geo.fromJson(json['geo']),
street: json['street'],
suite: json['suite'],
zipcide: json['zipcode'],
);
}
}
class Geo {
final String lat, lng;
Geo({this.lat, this.lng});
factory Geo.fromJson(Map<String, dynamic> json) {
return Geo(
lat: json['lat'],
lng: json['lng'],
);
}
}
class Company {
final String name;
final String catchPhrase;
final String bs;
Company({this.bs, this.catchPhrase, this.name});
factory Company.fromJson(Map<String, dynamic> json) {
return Company(
bs: json['bs'],
catchPhrase: json['catchPhrase'],
name: json['name'],
);
}
}
Its really just building some classes for the json structure and then I just wanted to output something.
Can anybody help me? :)
Thanks!
You are not returning a widget when you iterate over users in your users.map().
Change:
users.map((user) {
Text(
'UserName: ${user.username}',
);
}).toList()
To:
users.map((user) {
return Text(
'UserName: ${user.username}',
);
}).toList()