How to get firebase realtime database data in to a list formate in flutter - flutter

I am trying to retrieve data from Firebase Realtime Database into a list in Flutter using a model.I don't get snapshot.data how to get data.value. I have read several other posts about using Firebase with Flutter but have not found a clear answer.
Model class screen:
import 'package:firebase_database/firebase_database.dart';
class DataModel {
final String id;
final String name;
final String price;
final String qty;
DataModel(
{required this.id,
required this.name,
required this.price,
required this.qty});
DataModel.fromSnapshot(DataSnapshot snapshot)
: id = snapshot.key.toString(),
name = (snapshot.value as Map<String, dynamic>?)?['productName'] ?? '',
price =
(snapshot.value as Map<String, dynamic>?)?['productPrice'] ?? '',
qty = (snapshot.value as Map<String, dynamic>?)?['qty'] ?? '';
toJson() {
return {
"productName": name,
"productPrice": price,
"qty": qty,
};
}
}
Database service with Firebase query:
import 'package:firebase_database/firebase_database.dart';
import 'package:money_management/data_json_model.dart';
class DatabaseService {
static List<DataModel> getData() {
Query needsSnapshot =
FirebaseDatabase.instance.ref("Money Management").orderByKey();
// print(needsSnapshot); // to debug and see if data is returned
List<DataModel> needs = [];
Map<dynamic, dynamic> values = needsSnapshot.onValue as Map;
values.forEach((key, values) {
needs.add(DataModel.fromSnapshot(values));
});
return needs;
}
}
ListView Page:
import 'package:flutter/material.dart';
import 'package:money_management/data_json_model.dart';
import 'database_service.dart';
class ListScreen extends StatefulWidget {
const ListScreen({Key? key}) : super(key: key);
#override
State<ListScreen> createState() => _ListScreenState();
}
class _ListScreenState extends State<ListScreen> {
List<DataModel> _needs = [];
#override
void initState() {
super.initState();
_setupNeeds();
}
_setupNeeds() async {
List<DataModel> needs = DatabaseService.getData();
setState(() {
_needs = needs;
});
}
#override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: () => _setupNeeds(),
child: ListView.builder(
itemCount: _needs.length,
itemBuilder: (BuildContext context, int index) {
DataModel need = _needs[index];
return Column(
children: [
Text(need.id),
Text(need.name),
Text(need.price),
Text(need.qty),
],
);
}),
);
}
}

Try make the method getData() asynchronous and call get() of FirebaseDatabase instead:
class DatabaseService {
static Future<List<dynamic>> getData() async {
final snapshot = await FirebaseDatabase.instance
.ref("Money Management")
.orderByKey()
.get();
// print(snapshot); // to debug and see if data is returned
List<DataModel> needs = [];
Map<dynamic, dynamic> values = snapshot.value as Map;
values.forEach((key, values) {
needs.add(DataModel.fromSnapshot(values));
});
return needs;
}
}

you can receive data as Map<String,dynamic> in your DataModel like this:
class DataModel {
late String id;
late String name;
late String price;
late String qty;
DataModel({
required this.id,
required this.name,
required this.price,
required this.qty
});
DataModel.fromSnapshot(DataSnapshot snapshot){
Map<String, dynamic> myData= Map<String,dynamic>.from(snapshot.value as
Map);
id = snapshot.key.toString();
name = myData["productName"].toString() ?? '';
price =myData["productPrice"].toString() ?? '';
qty = myData["qty"].toString() ?? '';
}
Map<String,dynamic> toJson() {
return {
"productName": name,
"productPrice": price,
"qty": qty,
};
}
}

Related

How to solve the problem with types in flutter?

I have an array of elements that come from api and I get and error from api =>
The operator '[]' isn't defined for the type of 'Country'
Response from api looks like this:
{"success":true,"list":[{"id":2,"createdAt":"2022-11-11T15:25:31.680Z","updatedAt":"2022-11-11T15:25:31.680Z","name":"Afghanistan"}]}
This is the type of an element inside list:
class Country {
final int id;
final String createdAt;
final String updatedAt;
final String name;
const Country({
required this.id,
required this.createdAt,
required this.updatedAt,
required this.name
});
}
This is my widget:
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<Country> countries = [];
Future<void> getCountries() async {
try {
final response = await _apiService.getCountries();
countries = response['list']; // [{"id": 2, "createdAt:""...}]
} catch (e) {
log(e.toString());
rethrow;
}
}
#override
void initState() {
getCountries();
super.initState();
}
#override
Widget build(BuildContext context) {
return Container();
}
}
And if I try to call this, IDE lights me this error in country['name'] =>
final List countriesWithNames = countries.map((country) => country['name']).toList();
Or when I try to get an element from the list, like this => countries[index]['name']
response['list'] returns list of map.You need to convert into model class.
You can use this model class
class Country {
final int id;
final String createdAt;
final String updatedAt;
final String name;
const Country({
required this.id,
required this.createdAt,
required this.updatedAt,
required this.name,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'id': id});
result.addAll({'createdAt': createdAt});
result.addAll({'updatedAt': updatedAt});
result.addAll({'name': name});
return result;
}
factory Country.fromMap(Map<String, dynamic> map) {
return Country(
id: map['id']?.toInt() ?? 0,
createdAt: map['createdAt'] ?? '',
updatedAt: map['updatedAt'] ?? '',
name: map['name'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory Country.fromJson(String source) =>
Country.fromMap(json.decode(source));
}
And getting from local json string
final data = response["list"] as List?;
List<Country> countries =
data?.map((e) => Country.fromMap(e)).toList() ?? [];
print(countries);

API Response returns null in Flutter

I'm carrying out a basic fetch API request in the code below. The response I'm receiving gives the values for most of the properties except for two which come as null. This has me thinking if it is my code that's causing this issue to occur or something on the backend side which results into this anomaly. As shown below, the fiels that come as null in my VS Code terminal are product_description and restaurant_id. Although these come as null when displayed on the terminal, on Postman it is a different story as the response comes in full. The code and the responses are as follows:
Response on Postman:
{
"status": "success",
"data": [
{
"product_id": 8,
"restaurant_name": "Mocambo",
"restaurant_id": "6", //This is the field in question
"product_name": "Kaju Paneer",
"product_description": "Tasty yummy paneer gravy dish", //And So is this
"product_image": "/public/assets/product/lgml5L03-19-41.jpg",
"product_selling_price": "320"
}
]
}
Response received on Terminal after API Call:
{"status":"success","data":[{"product_id":8,"restaurant_name":"Mocambo","restaurant_id":"6","product_name":"Kaju Paneer","product_description":"Tasty yummy paneer gravy dish","product_image":"\/public\/assets\/product\/lgml5L03-19-41.jpg","product_selling_price":"320"}
When I try printing all the properties this is what I get(You can see above that I still receive data for restaurant_id and product_description)
I/flutter (10235): Provider product_selling_price 320
I/flutter (10235): Provider product_image /public/assets/product/lgml5L03-19-41.jpg
I/flutter (10235): Provider product_name Kaju Paneer
I/flutter (10235): Provider product_id 8
I/flutter (10235): Provider restaurantName Mocambo
I/flutter (10235): Provider Restaurant ID null //Restaurant ID here comes as null
I/flutter (10235): Provider Restaurant Description null //Restaurant Description comes as null
The codes for the Model Class, the class from which the API is called and the widget where it is used are below:
Model Class
import 'package:meta/meta.dart';
import 'dart:convert';
PopularDishes popularDishesFromJson(String str) =>
PopularDishes.fromJson(json.decode(str));
String popularDishesToJson(PopularDishes data) =>
json.encode(data.toJson());
class PopularDishes {
PopularDishes ({
required this.status,
required this.data,
});
String status;
List<Datum> data;
factory PopularDishes .fromJson(Map<String, dynamic> json) =>
PopularRestaurants(
status: json["status"],
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"status": status,
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
Datum({
required this.productId,
required this.restaurantName,
required this.restaurantId,
required this.productName,
required this.productDescription,
required this.productImage,
required this.productSellingPrice,
});
int productId;
String restaurantName;
String restaurantId;
String productName;
String productDescription;
String productImage;
String productSellingPrice;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
productId: json["product_id"],
restaurantName: json["restaurant_name"],
restaurantId: json["restaurant_id"],
productName: json["product_name"],
productDescription: json["product_description"],
productImage: json["product_image"],
productSellingPrice: json["product_selling_price"],
);
Map<String, dynamic> toJson() => {
"product_id": productId,
"restaurant_name": restaurantName,
"restaurant_id": restaurantId,
"product_name": productName,
"product_description": productDescription,
"product_image": productImage,
"product_selling_price": productSellingPrice,
};
}
The class from where the API is called
class PopularDishesProvider with ChangeNotifier {
Map<String, dynamic> _popularDishes = {};
String baseUrl = 'https://achievexsolutions.in/current_work/eatiano/';
Map<String, dynamic> get popularDishes {
return {..._popularDishes};
}
Future<void> fetchData() async {
final url = Uri.parse(baseUrl + 'api/all_products');
final response = await http.get(url);
print(response.body);
PopularDishes popularDishes = popularDishesFromJson(response.body);
_popularDishes = popularDishes.toJson();
// print(_popularDishes);
}
}
The widget
class PopularDishes extends StatefulWidget {
PopularDishesState createState() => PopularDishesState();
}
class PopularDishesState extends State<PopularDishes> {
bool _isLoading = true;
#override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
Provider.of<PopularDishesProvider>(context).fetchData().then((_) {
setState(() {
_isLoading = false;
});
});
}
#override
Widget build(BuildContext context) {
var width = MediaQuery.of(context).size.width;
var height = MediaQuery.of(context).size.height;
var textScale = MediaQuery.of(context).textScaleFactor * 1.1;
var subTitleScale = MediaQuery.of(context).textScaleFactor * 1.4;
final provider = Provider.of<PopularDishesProvider>(context).popularDishes;
print(
'Provider product_selling_price ${provider['data'][0]['product_selling_price']}');
print('Provider product_image ${provider['data'][0]['product_image']}');
print('Provider product_name ${provider['data'][0]['product_name']}');
print('Provider product_id ${provider['data'][0]['product_id']}');
print('Provider restaurantName ${provider['data'][0]['restaurant_name']}');
print('Provider Restaurant ID ${provider['data'][0]['restaurant_id']}'); //Returns null here
print(
'Provider Restaurant Description ${provider['data'][0]['product_description']}'); //Returns null here
}
}
Is there anything I can do to fix this or is this a backend issue?
It may happen if some of your restaurant_id contains null value. If you are getting the response of data Try as follows:
provider['data'][0]['restaurant_id']==null?
print("isEmpty") :
print('Provider Restaurant ID ${provider['data'][0]['restaurant_id']}');
Note, I could not check your Model class because you did not provide PopularRestaurants. Also, I may be mistaken but I don't think you should make async-await function calls inside provider. First call fetchData in your StatefulWidget, then save the data in your provider. I also think you're using didChangeDependencies wrong and what you want is initstate.
This works for me:
Model Class generated from https://javiercbk.github.io/json_to_dart/
class PopularDishesModel {
String? status;
List<Data>? data;
PopularDishesModel({this.status, this.data});
PopularDishesModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
if (json['data'] != null) {
data = <Data>[];
json['data'].forEach((v) {
data!.add(Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = status;
if (this.data != null) {
data['data'] = this.data!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
int? productId;
String? restaurantName;
String? restaurantId;
String? productName;
String? productDescription;
String? productImage;
String? productSellingPrice;
Data(
{this.productId,
this.restaurantName,
this.restaurantId,
this.productName,
this.productDescription,
this.productImage,
this.productSellingPrice});
Data.fromJson(Map<String, dynamic> json) {
productId = json['product_id'];
restaurantName = json['restaurant_name'];
restaurantId = json['restaurant_id'];
productName = json['product_name'];
productDescription = json['product_description'];
productImage = json['product_image'];
productSellingPrice = json['product_selling_price'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['product_id'] = productId;
data['restaurant_name'] = restaurantName;
data['restaurant_id'] = restaurantId;
data['product_name'] = productName;
data['product_description'] = productDescription;
data['product_image'] = productImage;
data['product_selling_price'] = productSellingPrice;
return data;
}
}
This is my stateful widget
class PopularDishes extends StatefulWidget {
PopularDishesState createState() => PopularDishesState();
}
class PopularDishesState extends State<PopularDishes> {
String baseUrl = 'https://achievexsolutions.in/current_work/eatiano/';
//Initialize PopularDishesModel
PopularDishesModel savedModel = PopularDishesModel();
//Make sure all json is downloaded
bool _isLoading = true;
//Remove this function from provider and put in your widget
Future<PopularDishesModel> fetchData() async {
final url = Uri.parse(baseUrl + 'api/all_products');
final response = await http.get(url);
//print(response.body);
PopularDishesModel popularDishes = PopularDishesModel.fromJson(json.decode(response.body));
return popularDishes;
}
//This is an async function f
void GetRestaurantData() async
{
PopularDishesModel result = await fetchData();
setState(() {
savedModel = result;
_isLoading = false;
});
}
#override
void initState() {
super.initState();
GetRestaurantData();
}
#override
Widget build(BuildContext context) {
var width = MediaQuery.of(context).size.width;
var height = MediaQuery.of(context).size.height;
var textScale = MediaQuery.of(context).textScaleFactor * 1.1;
var subTitleScale = MediaQuery.of(context).textScaleFactor * 1.4;
//Add code to save to provider
if(_isLoading == false) {
print(savedModel.data![0].productId);
print(savedModel.data![0].restaurantName);
print(savedModel.data![0].restaurantId);
print(savedModel.data![0].productName);
print(savedModel.data![0].productDescription);
print(savedModel.data![0].productImage);
print(savedModel.data![0].productSellingPrice);
/*Result
8
Mocambo
6
Kaju Paneer
Tasty yummy paneer gravy dish
/public/assets/product/lgml5L03-19-41.jpg
320*/
}
//Add logic to save to provider
return Container();
}
}

Null check operator used on a null value when connecting API's in flutter

I've been having this problem when trying to connect API's in flutter. I'm not sure if this is a problem of not receiving the data or if there is an error in my code, any hekp would be greatly appreciated.
This is the code I have on the page
import 'package:ctrade/models/newsinfo.dart';
import 'package:ctrade/services/api_manager.dart';
import 'package:flutter/material.dart';
class PostsPage extends StatefulWidget {
const PostsPage({ Key? key }) : super(key: key);
#override
State<PostsPage> createState() => _PostsPageState();
}
class _PostsPageState extends State<PostsPage> {
late Future<Welcome> _Welcome; //error here
#override
void initState() {
_Welcome = API_Manager().getNews();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold (
appBar: AppBar(
title: Text('News App'),
),
body: Container(
child: FutureBuilder<Welcome>(
future: _Welcome,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
itemCount: 52,
itemBuilder:(context, index) {
var ticker = snapshot.data!.ticker[index];
return Container(
height: 100,
child: Row(
children: [
//Text(ticker)
],
),
);
});
}
else
return Center(child: CircularProgressIndicator());
},
),
)
);
}
}
This is the code on my API manager file (I defined the news_url in a different file)
import 'package:ctrade/constants/strings.dart';
import 'package:ctrade/models/newsinfo.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class API_Manager {
Future<Welcome> getNews() async{
var client = http.Client();
var Welcome;
try{
var response = await client.get(Uri.parse(Strings.news_url));
if(response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
Welcome = Welcome.fromJson(jsonMap);
}
}
catch(Exception)
{
return Welcome;
}
return Welcome;
}
}
This is the file with the parsed json
// To parse this JSON data, do
//
// final welcome = welcomeFromJson(jsonString);
import 'dart:convert';
List<Welcome> welcomeFromJson(String str) => List<Welcome>.from(json.decode(str).map((x) => Welcome.fromJson(x)));
String welcomeToJson(List<Welcome> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Welcome {
Welcome({
required this.id,
required this.ticker,
required this.isin,
required this.bestAsk,
required this.bestBid,
required this.currentPrice,
required this.askVolume,
required this.bidVolume,
required this.fullCompanyName,
required this.prevPrice,
required this.prevPer,
required this.prevChange,
});
int id;
String ticker;
String isin;
String bestAsk;
String bestBid;
String currentPrice;
String askVolume;
String bidVolume;
String fullCompanyName;
String prevPrice;
String prevPer;
String prevChange;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
id: json["id"],
ticker: json["Ticker"],
isin: json["ISIN"],
bestAsk: json["Best_Ask"],
bestBid: json["Best_bid"],
currentPrice: json["Current_price"],
askVolume: json["Ask_Volume"],
bidVolume: json["Bid_Volume"],
fullCompanyName: json["FullCompanyName"],
prevPrice: json["PrevPrice"],
prevPer: json["PrevPer"],
prevChange: json["PrevChange"],
);
Map<String, dynamic> toJson() => {
"id": id,
"Ticker": ticker,
"ISIN": isin,
"Best_Ask": bestAsk,
"Best_bid": bestBid,
"Current_price": currentPrice,
"Ask_Volume": askVolume,
"Bid_Volume": bidVolume,
"FullCompanyName": fullCompanyName,
"PrevPrice": prevPrice,
"PrevPer": prevPer,
"PrevChange": prevChange,
};
}
class Welcome {
Welcome({
required this.id,
required this.ticker,
required this.isin,
required this.bestAsk,
required this.bestBid,
required this.currentPrice,
required this.askVolume,
required this.bidVolume,
required this.fullCompanyName,
required this.prevPrice,
required this.prevPer,
required this.prevChange,
});
int? id;
String? ticker;
String? isin;
String? bestAsk;
String? bestBid;
String? currentPrice;
String? askVolume;
String? bidVolume;
String? fullCompanyName;
String? prevPrice;
String? prevPer;
String? prevChange;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
id: json["id"]??"",
ticker: json["Ticker"]??"",
isin: json["ISIN"]??"",
bestAsk: json["Best_Ask"]??"",
bestBid: json["Best_bid"]??"",
currentPrice: json["Current_price"]??"",
askVolume: json["Ask_Volume"]??"",
bidVolume: json["Bid_Volume"]??"",
fullCompanyName: json["FullCompanyName"]??"",
prevPrice: json["PrevPrice"]??"",
prevPer: json["PrevPer"]??"",
prevChange: json["PrevChange"]??"",
);
Map<String, dynamic> toJson() => {
"id": id,
"Ticker": ticker,
"ISIN": isin,
"Best_Ask": bestAsk,
"Best_bid": bestBid,
"Current_price": currentPrice,
"Ask_Volume": askVolume,
"Bid_Volume": bidVolume,
"FullCompanyName": fullCompanyName,
"PrevPrice": prevPrice,
"PrevPer": prevPer,
"PrevChange": prevChange,
};
}

why my list model show this error : type 'List<dynamic>' is not a subtype of type 'List<String>'?

Hello I have try to add List in my model and add data to my homepage but I have this error only when I add " suite=widget.todo.suite; in the initstate :
suite=widget.todo.suite; => type 'List<dynamic>' is not a subtype of type 'List<String>'
If I use an other data model as "id" who is a string or "isDone" who is a bool I have no error. But my "suite" data have error
I don't understand.
-------------------homepage--------------
class Add_suite extends StatefulWidget {
final Todo todo;
const Add_suite({Key key, #required this.todo}) : super(key: key);
#override
_Add_suiteState createState() => _Add_suiteState();
}
class _Add_suiteState extends State<Add_suite> {
final _formKey = GlobalKey<FormState>();
String title;
String description;
List<String> suite =[""];
List<String> stringList = [];
#override
void initState() {
super.initState();
Firebase.initializeApp().whenComplete(() {
print("completed");
setState(() {});
});
suite=widget.todo.suite;
title = widget.todo.title;
description = widget.todo.description;
}
...
}
-------------------model--------------
class Todo {
DateTime date;
String title;
String id;
String description;
List suite;
bool isDone;
Todo({
#required this.date,
#required this.title,
this.description = '',
this.suite,
this.id,
this.isDone = false,
});
static Todo fromJson(Map<String, dynamic> json) => Todo(
date: Utils.toDateTime(json['createdTime']),
title: json['title'],
description: json['description'],
suite: json['suite'],
id: json['id'],
isDone: json['isDone'],
);
Map<String, dynamic> toJson() => {
'date': Utils.fromDateTimeToJson(date),
'title': title,
'description': description,
'suite': suite,
'id': id,
'isDone': isDone,
};
}
Edit: if I change list suite par list suite
my Streambuilder return error. If I use list I have no error on streambuilder but an other error with dynamic type
StreamBuilder<List<Todo>>(
stream: FirebaseFirestore.instance
.collection('first_stories')
.orderBy("date", descending: true)
.snapshots()
.transform(Utils.transformer(Todo.fromJson)),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
if (snapshot.hasError) {
return buildText('Erreur');
} else {
final todos = snapshot.data;
final provider = Provider.of<TodosProvider>(context);
provider.setTodos(todos);
return
TodoListWidget();
}
}
},
),
In Todo class, you need to specify your List type :
List<String> suite;
By default, if you not specify type, it's dynamic type :
List suite; is egal to List<dynamic> suite;
If you can't specify a type in Todo class, you can cast your dynamic List when you set it in suite :
suite = widget.todo.suite as List<String>;
EDIT
You also have to convert your data in fromJson function. Try this :
suite: List<String>.from(json['suite']),

Future<List<List<News>>>' can't be assigned to the parameter type 'List<dynamic>

I am getting this error when I try to assign the values that retrieved from firestore to a List in flutter
This method retrieves the data:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:snap_news_ctse_2020/banuka/model/news_model.dart';
class FireStoreServiceApi {
static final FireStoreServiceApi _fireStoreService =
FireStoreServiceApi._internal();
Firestore _db = Firestore.instance;
FireStoreServiceApi._internal();
factory FireStoreServiceApi() {
return _fireStoreService;
}
// get the news
Stream<List<News>> getNews() {
return _db.collection("news").snapshots().map(
(snapshot) => snapshot.documents
.map((doc) => News.fromMap(doc.data, doc.documentID))
.toList(),
);
}
}
And this is where I call it and assign to a List
Stream<List<News>> stream = FireStoreServiceApi().getNews();
stream.toList();
var banuka = [];
banuka = stream;
[Update]
This is the News model:
class News {
final String headline;
final String description;
final String imageUrl;
final String timeNews;
final String timeDate;
final String priority;
News({this.headline,this.description, this.imageUrl, this.timeNews, this.timeDate, this.priority});
News.fromMap(Map<String,dynamic> data, String id):
headline=data['headline'],
description=data['description'],
imageUrl=data['imageUrl'],
timeNews=data['timeNews'],
timeDate=data['timeDate'],
priority=data['priority'];
Map<String, dynamic> toMap(){
return {
"headline" : headline,
"description": description,
"imageUrl": imageUrl,
"timeNews": timeNews,
"timeDate": timeDate,
"priority": priority
};
}
}
Can someone please help me?