I hope you all are well.
I got a problem i am learning API integration in flutter now a days the problem I am facing is i can't get data here is the code below:
class _AppState extends State<App> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: getuser(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return CircularProgressIndicator();
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data[index].title),
);
},
);
}
},
));
}
}
it is only showing me circular indicator i am using API 'https://jsonplaceholder.typicode.com/posts'.
I tried to check if the API is working so i check it by passing a hello in list tile and getting the hello by the length of API given in item count and actually that showed me output according to length please help me out so that i can move forward.
Thank You.
Here is the function also:
import 'package:apiintegration/model/user_model.dart';
import 'package:http/http.dart' as http;
getuser() async {
var url = Uri.parse('https://jsonplaceholder.typicode.com/posts');
var response = await http.get(url);
var responsedata = jsonDecode(response.body);
return UserModel.fromJson(responsedata);```
You should continue step by step.
As you said if you have success response and not null data, you might have parsing problem.
You should go to your url => https://jsonplaceholder.typicode.com/posts again and copy the json data.
Open https://app.quicktype.io/ site and paste your json data here
to create related parsing methods.
Make http request again. If you parse the json data correctly check out getUser method in view file.
When you get response, be sure that you re-draw(setState etc.) the ui
for displaying parsed json data.
If everything works well you should handle all the states
that you can have from FutureBuilder such as:
if(snapshot.connectionState == ConnectionState.none) {...}
else if(snapshot.connectionState == ConnectionState.waiting) {...}
else if(snapshot.connectionState == ConnectionState.done) {
if(snapshot.hasError) {...}
if(snapshot.hasData) {...}
}
problem is here
return UserModel.fromJson(responsedata);```
it should be userModelFromJson(responsedata);
Example Model:
import 'dart:convert';
DefaultModel defaultModelFromJson(String str) =>
DefaultModel.fromJson(json.decode(str));
String defaultModelToJson(DefaultModel data) => json.encode(data.toJson());
class DefaultModel {
DefaultModel({
this.response,
this.data,
});
String? response;
String? data;
factory DefaultModel.fromJson(Map<String, dynamic> json) => DefaultModel(
response: json["response"],
data: json["data"],
);
Map<String, dynamic> toJson() => {
"response": response,
"data": data,
};
}
Related
Flutter Streambuilder code below runs without error and returns (screenshot at bottom):
ID: AzFdOO9WsFaFbTxTQsuo
Data: Instance of '_JsonDocumentSnapshot'
How do I get to the values inside the _JsonDocumentSnapshot and display them in the Text() widget?
For instance, there's a string field called "name", but I can't figure out how to get to it.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("groceries")
.doc(widget.docId)
.snapshots(),
builder: (context, streamSnapshot) {
if (streamSnapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
} else if (streamSnapshot.hasData) {
return Text("ID: ${widget.docId}\n"
"Data: ${streamSnapshot.data}");
} else {
return const Text("No Data");
}
}
)
Thanks for your help!
the following Stream, return an object with a type of DocumentSnapshot :
FirebaseFirestore.instance.collection("groceries").doc(widget.docId).snapshots();
and that type contains the document snapshot, and also contains more additional information about the document.
so in order to get the JSON Map<String, dynamic> which represents the data of the Firestore document, you need to call data() on the result of the snapshot.data(), so you need to try the following:
StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance
.collection("groceries")
.doc(widget.docId)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> streamSnapshot) {
if (streamSnapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
} else if (streamSnapshot.hasData) {
return Text("ID: ${widget.docId}\n"
"Data: ${streamSnapshot.data.data()}"); // added data()
} else {
return const Text("No Data");
}
}
)
now it should show the Map<String, dynamic> object which contains your document data in the Text widget.
hope this helps.
In your code example streamSnapshot.data is an Object or a dynamic type variable.
To access the json value of your data, you have to specify the key corresponding to your value.
streamSnapshot.data['banana']
This is my service function that communicate with the database
Future<News?> getNewsList(String token) async {
var url = Uri.tryParse('${baseUrl}get-news-list');
var response =
await http.post(url!, headers: {'Authorization': 'Bearer $token'});
if (response.statusCode == 200) {
var map = json.decode(response.body);
var list = News.fromJson(map);
print("map:${list.data![0]}");
return News.fromJson(map);
} else {
return News(message: null, status: false, data: null);
}
}
This my viewModel class I am using mvvm pattern
class NewsViewModel extends ChangeNotifier {
ApiOp api = ApiOp();
Future<List<NewsModel?>?> getNews() async {
String token ="token-here";
var map = await api.getNewsList(token);
List<NewsModel?>? list = map!.data;
print("object:${list![0]!.title}");
notifyListeners();
return list;
}
}
And here where I show the data on the view
Consumer<NewsViewModel?>(
builder: (context, value, child) => FutureBuilder<dynamic>(
future: value!.getNews(),
builder: (context, snapshot) {
List? list = snapshot.data;
print("list:$list");
return ListView.builder(
itemCount: 2,
itemBuilder: (context, index) {
return FirsatWidget(
title:"",
date: "",
photoUrl: "lib/assets/temp/4.jpg",
);
},
);
}),
),
But when I run the app some print function spamming in the debug like these prints
print("object:${list![0]!.title}");
print("map:${list.data![0]}");
Is this code continuously send post to the server or just rebuilding the consumer
Is this code continuously send post to the server or just rebuilding
the consumer
You are continuosly sending http reqests to your server.
You don't need to use Consumer<NewsViewModel?> and notifyListeners(); because you are using FutureBuilder which gets data from that future.
Try this code:
FutureBuilder<dynamic>(
future: Provider.of<NewsViewModel>(context,listen:false).getNews(),
builder: (context, snapshot) {
List? list = snapshot.data;
print("list:$list");
return ListView.builder(
itemCount: 2,
itemBuilder: (context, index) {
return FirsatWidget(
title:"",
date: "",
photoUrl: "lib/assets/temp/4.jpg",
);
},
);
}),
),
And comment notifyListeners()
class NewsViewModel extends ChangeNotifier {
ApiOp api = ApiOp();
Future<List<NewsModel?>?> getNews() async {
String token ="token-here";
var map = await api.getNewsList(token);
List<NewsModel?>? list = map!.data;
print("object:${list![0]!.title}");
// notifyListeners();
return list;
Let me know if you have issues and still have rebuilds.
I started flutter recently, and I try to retrieve the data from a query I made using 'where' , but the only thing I got back is "Instance of '_JsonQueryDocumentSnapshot'".
I tried different thing , but nothing work or i do it badly
this is my code :
CollectionReference users =
FirebaseFirestore.instance.collection('users');
final documents =
await users.where("username", isEqualTo: "username").get();
documents.docs.forEach((element) {
print(element);
});
I have also tried to use Future but without success :
class finduser extends StatelessWidget {
final String username;
finduser(this.username);
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('users');
return FutureBuilder(
future: users.where('username', isEqualTo: '${username}').get(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
print("wrong");
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
print("doesnt exist");
return Text("User does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data! as Map<String, dynamic>;
print(snapshot.data!);
return Text("${data}");
}
return Text("loading");
},
);
}
}
for the moment, all usernames are just "username"
Thank you for the help
When you get your documents like this :
CollectionReference users =
FirebaseFirestore.instance.collection('users');
final documents =
await users.where("username", isEqualTo: "username").get();
documents.docs.forEach((element) {
print(element);
});
You are trying to print an instance of a QueryDocumentSnapshot
This QueryDocumentSnapshot has a method .data() which returns a Map<String,dynamic> aka JSON.
So in order to print the content of your Document, do this :
documents.docs.forEach((element) {
print(MyClass.fromJson(element.data()));
});
This data by itself will not be very useful so I recommend creating a factory method for your class :
class MyClass {
final String username;
const MyClass({required this.username});
factory MyClass.fromJson(Map<String, dynamic> json) =>
MyClass(username: json['username'] as String);
}
Now you can call MyClass.fromJson(element.data()); and get a new instance of your class this way.
I have searched a lot but i see you have written code right.
The only thing that came to my mind is that you didn't initialize your firebase to your flutter project (you should do it in any flutter project to be able to use flutter).
link of the document:
https://firebase.flutter.dev/docs/overview#initializing-flutterfire
In your first code snippet you are printing element, which are instances of the QueryDocumentSnapshot class. Since you're not accessing specific data of the document snapshot, you get its default toString implementation, which apparently just shows the class name.
A bit more meaningful be to print the document id:
documents.docs.forEach((doc) {
print(doc.id);
});
Or a field from the document, like the username:
documents.docs.forEach((doc) {
print(doc.get("username"));
});
Run this code, it will work.
I also faced this similar problem, so I used this work around.
Map<String, dynamic> data = {};
FirebaseFirestore.instance.collection('users').where("username", isEqualTo: "username").get().then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((value){
data = value.data()!;
print('printing uid ${data['uid']}');
print('printing username--${data['username']}');
print('printing all data--$data');
});
});
This is my first attempt to use firebase with Flutter ,I am trying to get data from Realtime database stored (imported from json) like this image :
I created service like this :
import 'dart:convert';
import 'package:http/http.dart' as http;
class FireBaseApi {
Future getData() async {
try {
var url = 'https://xxxxxxxxxxxx.firebaseio.com/0.json';
var response = await http.get(url);
var data = jsonDecode(response.body);
return data;
} catch (e) {
print(e);
return null;
}
}
}
and used it like this :
return FutureBuilder(
future: FireBaseApi().getData(),
builder: (context, snapshot) {
Now How can I reach to items?
First you need to set your method with Future
class FireBaseApi {
Future getData() async {
...
return response;
}
}
and then you need to call this method with asStream() if you are calling this with StreamBuilder like below
return StreamBuilder(
stream: FireBaseApi().getData().asStream(),
builder: (context, snapshot) {
...
}
To get the data use the following method:
Future<DataSnapshot> getItems() {
return FirebaseDatabase().reference().child("items").once();
}
If you want to create a widget that reactively shows the items from your Realtime Database, use the following code:
FirebaseAnimatedList(
key: const Key("key"),
query: FirebaseDatabase().reference().child("items"),
itemBuilder:
(_, DataSnapshot data, Animation<double> animation, int index) {
// TODO update this to fit your own needs
return Text(data.value.toString());
},
);
FutureBuilder keep returning null even when the http request successfully fetch the data from api.
I use json_serializable and freezed package in my data model, is this error related to them or it is purely coming from flutter/dart?
Http request
Future<VitalSignResponse> getLatestVitalSign(String medicalNo) async {
final String url = Api.baseUrl +
'VitalSignByMedicalNoLatest?AccessKey=${Api.accessKey}&MedicalNo=$medicalNo';
Response res = await Dio().get(url);
print('api res: ${res.data}'); // 'api res: the correct data from api'
print('serialize: ${VitalSignResponse.fromJson(json.decode(res.data))}'); // print out nothing
return VitalSignResponse.fromJson(json.decode(res.data));
}
data model
#freezed
abstract class VitalSignResponse with _$VitalSignResponse {
#JsonSerializable(explicitToJson: true)
const factory VitalSignResponse(
final String status,
final String errorCode,
final List<VitalSign> data,
) = _VitalSignResponse;
factory VitalSignResponse.fromJson(Map<String, dynamic> json) =>
_$VitalSignResponseFromJson(json);
}
future builder logic
FutureBuilder(
future: service.getLatestVitalSign(patientBloc.patient.medicalNo),
builder: (
BuildContext context,
AsyncSnapshot snapshot,
) {
print(snapshot.data); // null
if (snapshot.connectionState == ConnectionState.waiting)
return Center(child: CircularProgressIndicator());
if (snapshot.hasData) {
// show data
}
return Container();
},
),
I simply forgot to run my project with debugging
i leave the question here as a personal reminder and for new developer out there to not making the same mistake i did. And for my friends to laugh at me haha