Getting Data from cloud Firestore and showing for flutter app - database

I have a profile screen. and getting data from the cloud store and showing in the profile screen.
I guess there is no problem while retrieving data but the problem is while showing. I don't know how I mess up?
Now the error is only showing "Loading" Text.
Help me
class Profile extends StatefulWidget {
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
bool userFlag = false;
var users;
#override
void initState() {
// TODO: implement initState
super.initState();
UserManagement().getData().then((QuerySnapshot docs){
userFlag = true;
users = docs.documents[0].data;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile'),
),
body: Container(
padding: EdgeInsets.all(50),
child: Column(
children:<Widget>[
name(),
],
),
),
);
}
Widget name() {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
"Name",
style: TextStyle(fontWeight: FontWeight.w600,fontSize: 18),
),
SizedBox(
width: 45,
),
userFlag ? Text(users['Name'],
style: TextStyle(fontWeight: FontWeight.w400,fontSize: 18),
)
:Text('Loading'),
],
),
);
}
for getting Data i have:
getData(){
return Firestore.instance
.collection('users').getDocuments();
}

I get and Use Data that way:
QuerySnapshot Users = await _fs
.collection("users")
.getDocuments();
It will give you all the users in the users collection.
so for retrieving one user in specific I use a "for loop".
String myEmail = "email#gmail.com";
String username;
for (var user in users.documents) {
if ( myEmail == user.data["email"]){
// you have all the field for the user using "myEmail".
username = user.data["username"];
} else {
print("There is no User with this email");
}
}
But I think there might be a better way to do it.

This error is because, You should initialize your user variable like
var users = {}; instead of
var user;

Related

Flutter: How to pass array data from json Future< to Widget

Being new to flutter, I'm learning and stumbling on the go.
I am trying to pass an array that I have received from json into an already waiting widget structure but can't quite seem to get the connection.
Here's the sample code:
class Products extends StatefulWidget {
#override
_ProductsState createState() => _ProductsState();
}
class _ProductsState extends State<Products> {
#override
void initState() {
_getProducts();
}
Future<List<Single_prod>> _getProducts() async {
var url = "";
var data = await http.get(url);
var jsonData = json.decode(data.body) as Map<String, dynamic>;
//print(jsonData.toString());
//jsonData.forEach((k, v) => print("Key : $k, Value : $v"));
List<Single_prod> items = [];
jsonData.forEach((k, v){
Single_prod item = Single_prod(v["error"], v["id"], v["name"], v["price"], v["image"]);
items.add(item);
});
//print(items.length);
return items; <---Tring to pass this to Widget build but not recognized.....
}
#override
Widget build(BuildContext context) {
return GridView.builder(
itemCount: items.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index){
return Single_prod(
prod_err: items[index]['error'], <--- This items array is not recognized
prod_id: items[index]['id'],
prod_name: items[index]['name'],
prod_price: items[index]['price'],
prod_image: items[index]['image'],
);
});
}
}
The items array is not recognized in the widget
Here is the rest of the code:
class Single_prod extends StatelessWidget {
final prod_err;
final prod_id;
final prod_name;
final prod_price;
final prod_image;
Single_prod({
this.prod_err,
this.prod_id,
this.prod_name,
this.prod_price,
this.prod_image,
});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(
tag: prod_name,
child: Material(
child: InkWell(
onTap: () => Navigator.of(context).push(new MaterialPageRoute(
// here we are passing the values of the products to the details page
builder: (context) => new ProductDetails(
prod_detail_name: prod_name,
prod_detail_image: prod_image,
prod_detail_id: prod_id,
prod_detail_price: prod_price,
))),
child: GridTile(
footer: Container(
height: 40.0,
color: Colors.white70,
child: ListTile(
leading: Text(prod_name, style: TextStyle(fontWeight: FontWeight.bold),),
title: Text(
prod_price,
style: TextStyle(color: Colors.blue, fontWeight: FontWeight.w800, fontSize: 12),
),
/*subtitle: Text(
prod_oldprice,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w800, fontSize: 11, decoration: TextDecoration.lineThrough),
),*/
),
),
child: Image.asset(prod_image,
fit: BoxFit.cover,),
),
),
),
),
);
}
}
How does the upper code connect with the lower code?
Thanks in advance.
First, look at the scope of your 'items' variable: it is defined in getItems() function, and it is not visible outside the function. So, first thing: make it class level property.
Next - your initState will call your method. Method is async, and the way to handle it in initState to use '.then' on the Future returned by your method. What you want to do here is: once the future completes, you want to set your class level variable to hold the value returned by _getProduct() function.
And finally - this is very important to understand: you don't call build method yourself - flutter framework does it for you. Now, flutter does not have a magic way of knowing when you changed the data - it won't observe your code, so you need to tell it somehow that your state object changed, and it requires rebuild. You do it by calling setState() function.
I think you have another issue here actually: you already bulit your Single_prod widget in _getProduct(), no need to build it again. I tried to correct this also.
Try this (I didn't compile it so it might have few errors):
class Products extends StatefulWidget {
#override
_ProductsState createState() => _ProductsState();
}
class _ProductsState extends State<Products> {
List<Single_prod> items = [];
#override
void initState() {
super.initState();
_getProducts().then( (result) {
setState(() {
items=result;
}
});
}
Future<List<Single_prod>> _getProducts() async {
var url = "";
var data = await http.get(url);
var jsonData = json.decode(data.body) as Map<String, dynamic>;
//print(jsonData.toString());
//jsonData.forEach((k, v) => print("Key : $k, Value : $v"));
List<Single_prod> items = [];
jsonData.forEach((k, v){
Single_prod item = Single_prod(v["error"], v["id"], v["name"], v["price"], v["image"]);
items.add(item);
});
//print(items.length);
return items;
}
#override
Widget build(BuildContext context) {
return GridView.builder(
itemCount: items.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index){
return items[index];
});
}
}

Exception has occurred. PlatformException (PlatformException(-3, Permission denied, ))

I tried to build an application, which should write data in a real time database. I tried an example I found in the internet, but now I get an error. The error I get is:
Exception has occurred.
PlatformException (PlatformException(-3, Permission denied, ))
This is the code I tried:
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
//final DBRef = FirebaseDatabase.instance.reference();
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Test",
home: Scaffold(
appBar: AppBar(
title: Text("Testo"),
),
body: Column(
children: <Widget>[
RaisedButton(
child: Text("Write Data"),
onPressed: () {
writeData();
},
),
],
),
),
);
}
void writeData() {
print("pressed");
FirebaseDatabase.instance
.reference()
.child("1")
.set({"id": "ID1", "data": "This is a test"});
}
}
I found in the internet, that my rule in the database could be wrong, that could be the mistake, but I didn't find a solution. This are my rules(I haven´t changed them):
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.time < timestamp.date(2020, 7, 29);
}
}
}
I don´t know why I get this error, hopefully someone can help me.

Looping Inside Stack Widget Flutter

I have a problem right now
I need to use StreamBuilder to get all the data from my database and then build every data into a widget with position in it.
Because I use position, I need to use Stack as a parent widget.
But the problem is I can't use ListView builder to loop the snapshot data
Is there any way to loop inside so I can return the widget?
Stack(
children: <Widget>[
Container(
color: Colors.white,
),
StreamBuilder(
// initialData: {'handler': "handler"},
stream: mapPlacementStream.stream,
builder: (context, snapshotPlacement) {
dataPlacement = snapshotPlacement.data;
if(!snapshotPlacement.hasData){
return const Text('Connecting...');
}
else{
return new StreamBuilder(
// initialData: {0: true},
stream: mapStateStream.stream,
builder: (context, snapshotState) {
dataState = snapshotState.data;
if(!snapshotState.hasData){
return const Text('Connecting...');
}
else{
return ParkPainter(
1,
20,
20,
1,
true
);
}
);
}
}
),
],
)
On Else I return the ParkPainter to see if it can print the ParkPainter (the widget with position)
It works

convert array to be displayed in the list

I tried to display the output of this data into a list but it can't
this is my data output
{activity: {"project":" Distributions","code":2000,"code_name":"OpenProcessSnapshot","activity":{"id_process_snapshot":988,"name":"Android Process"}}, created_at: 2019-06-20 08:58:48.492885+07, id: 1, id_user: 1}
{activity: {"project":"Distributions","code":2000,"code_name":"OpenProcessSnapshot","activity":{"id_process_snapshot":988,"name":"Android Process"}}, created_at: 2019-06-20 08:58:48.492885+07, id: 1, id_user: 1}
{activity: {"project":" Distributions","code":2000,"code_name":"OpenProcessSnapshot","activity":{"id_process_snapshot":988,"name":"Android Process"}}, created_at: 2019-06-20 08:58:48.492885+07, id: 1, id_user: 1}
and this is my code
FutureBuilder(
future: UserController.getActivity(_selectedUser),
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data.toString());
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data.toString()),
],
);
} else {
return Center(
child: Text("No data displayed"),
);
}
return Center(
child: CircularProgressIndicator(),
);
},
),
what if I want to display created_at and project?
You can use jsonDecode to get that specific element.
Documentation Link
For your case you have to create a new widget function and return it:
//put this method before your widget build function
Widget _mapJsonDataToText(String data){
Map<String, List<dynamic>> jsonData = jsonDecode(data);
Map<String, dynamic> jsonDataInner = jsonDecode(jsonData['activity']);
return Text(jsonDataInner['created_at']);
//do the same for project
}
children: <Widget>[
//gets the method that returns the text widget
_mapJsonDataToText(snapshot.data.toString()),
],
I have a different method, this will add up the data into the list. Not using future builder, just making use of my common sense to display the data logically into the list.
Assuming you know about http of flutter, if you don't then this is the link for you: Fetch data from the internet
Suppose you have a data[], in which activity{} are being displayed in your JSON output.
List<String> project = [];
List<String> createdAt = [];
void initState(){
super.initState();
//this will run this method on call of this page, everytime
this.fetchData();
}
Future<void> fetchData() async{
List<String> _project = [];
List<String> _createdAt = [];
final response =
await http.get('your_api_url');
//looping through the array of activity object
(response['data'] as list).forEach((item){
//check if the data comes correct
print(item['activity']['project']);
print(item['created_at']);
_project.add(item['activity']['project']);
_createdAt.add(item['created_at']);
});
setState((){
this.project = _project;
this.createdAt = _createdAt;
});
}
//In order to show them in the list of project, call ListView()
List<Widget> projectWidget(){
List<Widget> _widget = [];
this.project.forEach((item){
_widget.add(item);
});
return _widget;
}
//In order to show them in the list of createdAt, call ListView()
List<Widget> createdAtWidget(){
List<Widget> _anotherWidget = [];
this.createdAt.forEach((item){
_anotherWidget.add(item);
});
return _anotherWidget;
}
Display the data as you want in your UI. Let me if it works for you. Thanks :)

REST API in flutter

I have a project in which I have a Python database and I have a Flutter ui.
Is there anyway I can use the REST API to connect them? My teammates who do the backend state that their database will use the REST API, so it would be useful if I can do that.
Yes, you can easily use REST API's with Flutter.
Dart offers an http package for easy HTTP request and there are others available on Dart Pub.
With the http package, you can even integrate your REST API request into the build tree very easily using a FutureBuilder:
FutureBuilder(
future: http.get('https://your-rest-api-domain.xyz/get-images?amount=5'),
builder: (context, snapshot) {
// you can easily work with your request results in here and return a widget
},
)
As cricket_007 mentioned in a comment, Flutter also provides a cookbook entry on this topic.
Simple cade for calling REST API and display in a listview.
Step 1:
Create a model class like this
class ItemSubCat{
final String ItemCode;
final String ItemName;
ItemSubCat(
{this.ItemCode, this.ItemName});
factory ItemSubCat.fromJson(Map<String, dynamic> parsedJson){
return ItemSubCat(
ItemCode: parsedJson['ItemCode'],
ItemName: parsedJson['ItemName']);
}
}
Step 2:
List<ItemSubCat> parsePosts(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<ItemSubCat>((json) => ItemSubCat.fromJson(json)).toList();
}
Future<List<ItemSubCat>> fetchsubcat(http.Client client) async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile||connectivityResult == ConnectivityResult.wifi) {
final response = await client.get('Your Api Url');
//print(response.body);
return compute(parsePosts, response.body);
} else {
Toast.show(message: "Please check your network conenction", duration: Delay.SHORT, textColor: Colors.black);
}
}
Step 3:
class ItemSubCategory extends StatelessWidget {
final String ItemCatCode;
ItemSubCategory({Key key, #required this.ItemCatCode}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
elevation: 0.0,
backgroundColor: Colors.transparent,
iconTheme: IconThemeData.fallback(),
title: Text('Category', style: TextStyle(color: Colors.black)),
centerTitle: true,
),
body: FutureBuilder<List<ItemSubCat>>(
future: fetchsubcat(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? GridViewPosts(items: snapshot.data)
: Center(child: CircularProgressIndicator());
},
),
);
}
}
Step 4:
class GridViewPosts extends StatelessWidget {
final List<ItemSubCat> items;
GridViewPosts({Key key, this.items}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: new GridView.builder(
itemCount: items.length,
shrinkWrap: true,
gridDelegate:
new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemBuilder: (BuildContext context, int position) {
return new Column(
children: <Widget>[
Divider(height: 0.0),
cardDetails(--You pass your data to listitems--),
],
);
})
);
}
}
Here you design your widget for a list item (cardDetails)

Resources