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());
},
);
Related
I'm using flutter, and I'm loading in a locally stored JSON file like so:
Future<String> loadJson(String file) async {
final jsonData = await rootBundle.loadString("path/to/$file.json");
return jsonData;
}
The problem is that this returns a Future<String> and I'm unable to extract the actual JSON data (as a String) from it.
I call loadJson in the Widget build method like so:
#override
Widget build(BuildContext context) {
final data = ModalRoute.of(context)!.settings.arguments as Map;
final file = data["file"];
String jsonData = loadJson(file); // The issue is here
return Scaffold (/* -- Snip -- */);
}
How would I go about doing this? Any help is appreciated.
loadJson is Future and you need to await for its result:
String jsonData = await loadJson(file);
you also can't run Future function inside build method, you need to use FutureBuilder:
return Scaffold (
body: FutureBuilder<String>(
future: loadJson(file),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
String jsonData = snapshot.data ?? "";
return /* -- Snip -- */;
},
}
}
},
),
);
You are getting data but not decoding it. You need to decode for using the loaded data.
Future<String> loadJson(String file) async {
final jsonData = await rootBundle.loadString("path/to/$file.json");
final data = await jsonDecode(jsonData)
return data;
}
Also, please don't forget to import dart convert library to use jsonDecode.
import 'dart:convert';
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,
};
}
i have a onCall cloud function which is returning
resp.status(200).send(JSON.stringify(entities));
In my flutter app, i have created this future to get values from it.
Future<void> dataDriven(String filename) async {
HttpsCallable callable =
FirebaseFunctions.instance.httpsCallable('fruitsType');
final results = await callable;
final datE = results.call(<String, dynamic>{
'filename': 'filename',
});
final dataF = await datE.then((value) => value.data);
print (dataF);
}
It is successfully printing the response which is as per expectation. but my snapshot is always returning null. It is not even reaching hasData stage. Please help.
Response;
[{"name":"banana","type":"fruit","count":0,"color":"yellow"},{{"name":"apple","type":"fruit","count":2,"color":"red"}]
FutureBuilder(
future: dataDriven('fruits.txt'),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: Text('An error has occurred!'),
);
} else {
final data = snapshot.data;
return Text(data.toString());
}
It looks like there are some issues that need to be fixed (See comments in code).
// Set the correct return type (not void because you are returning data)
Future<String> dataDriven(String filename) async {
HttpsCallable callable = FirebaseFunctions.instance.httpsCallable('fruitsType');
// You can just call the function here with await
final result = await callable.call({
// Remove the quotes on the filename value
'filename': filename,
});
// Don't forget to return the data
return result;
}
I suggest reading up on the documentation about calling cloud functions from a flutter app and basic dart syntax.
I wanted to retrieve data from my sub collection. It should return the list of friendid.
But I keep getting the NoSuchMethodError snapshot has no instance method then error with the code below.
The error is at firebaseMethods.getFriend(Constant.currentId).then((value) line.
Widget friendList() {
return StreamBuilder(
stream: friendlistStream,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
return FriendTile(
snapshot.data.docs[index].data()["friendid"]);
},
)
: Container();
},
);
}
#override
void initState() {
getUserFriend();
super.initState();
}
getUserFriend() async {
Constant.currentId =
await HelperFunctions.getUserIdSharedPreference(Constant.currentId);
setState(() {
firebaseMethods.getFriend(Constant.currentId).then((value) {
setState(() {
friendlistStream = value;
});
});
});
}
The code for firestore is as below.
getFriend(String ownerid) {
return FirebaseFirestore.instance
.collection("users")
.doc(ownerid)
.collection("friends")
.snapshots();
}
I had tried hardcoding the Constant.currentId to the actual ID that I wanted to retrieve but still having the same error. What should I do to display the list of friendid correctly?
Future getFriend(String ownerid) async {
return await FirebaseFirestore.instance
.collection("users")
.doc(ownerid)
.collection("friends")
.get();
}
.then() is used for futures so your getFriend() method needs to return a Future
If you want to use the Stream than you need to use a StreamBuilder instead of calling a function in initState
This might help: https://www.youtube.com/watch?v=MkKEWHfy99Y&ab_channel=GoogleDevelopers
I try to implement the Firebase Realtime Database in Flutter and I want to display updated values in realtime. I try to achieve this with a StreamBuilder.
StreamBuilder Code
StreamBuilder(
stream: GuestbooksDatabase().getAllGuestbooksSync().asStream(),
builder: (context, snapshot) {
if (!snapshot.hasData || !snapshot.data.length) {
return CircularProgressIndicator();
} else {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Text(snapshot.data[index].title);
});
}
}),
The stream function
Future<List<Guestbook>> getAllGuestbooksSync() async {
List<Guestbook> guestbooks = [];
databaseRef.onValue.listen((event) async {
var dataSnapshot = event.snapshot;
if (dataSnapshot.value != null) {
dataSnapshot.value.forEach((key, value) async {
Guestbook guestbook = await Guestbook.fromJson(value);
guestbook.setId(key);
guestbooks.add(guestbook);
});
await Future.delayed(Duration.zero);
print(guestbooks); // Result: All Instances of Guestbook
return guestbooks;
}
});
}
I only see the CircularProgressIndicator() what means that the snapshot has no data.
What's the issue there?
You can use StreamController for this.
Create a new controller -
final StreamController streamController = StreamController<List>.broadcast();
Convert Future<List> to void type for your getAllGuestbooksSync() function and return nothing.
It can and will be called in initState() -
void getAllGuestbooksSync() {
List<Guestbook> guestbooks = [];
databaseRef.onValue.listen((event) async {
var dataSnapshot = event.snapshot;
if (dataSnapshot.value != null) {
dataSnapshot.value.forEach((key, value) async {
Guestbook guestbook = await Guestbook.fromJson(value);
guestbook.setId(key);
guestbooks.add(guestbook);
});
print(guestbooks); // Result: All Instances of Guestbook
streamController.add(guestbooks); // Adding list to the stream
}
});
}
In your StreamBuilder use -
stream: streamController.stream,