I am using Firebase Database to store information regarding my flutter app.
I have manually updated my collections and documents.
But in one instance I want my users to setdata in my documents so it gets reflected in the app for that particular user. But, when the user does setdate it goes and creates new documents which I do not want, I want the user to setdata in the existing document. I did try but no luck.
Here are my codes:
class FirestoreService {
FirestoreService._();
static final instance = FirestoreService._();
Future<void> setData(
{#required String path, Map<String, dynamic> data}) async {
final reference = Firestore.instance.document(path);
await reference.setData(data);
}
abstract class Database {
Future<void> setRackBook(RackBookItems rackBookItems);
}
bool documentCheckBox() => true;
class FirestoreDatabase implements Database {
final String uid;
FirestoreDatabase({#required this.uid}) : assert(uid != null);
final _service = FirestoreService.instance;
#override
Future<void> setRackBook(RackBookItems rackBookItems) async =>
await _service.setData(
path: APIPath.rackBookItems(uid, rackBookItems.id),
data: rackBookItems.toMap());
}
class PageScreen extends StatefulWidget {
final RackBookItems rackBookItems;
final Database database;
const PageScreen(this.rackBookItems, {#required this.database});
static Future<void> show(
BuildContext context, {
Database database,
RackBookItems rackBookItems,
}) async {
final database = Provider.of<Database>(context);
await Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(
fullscreenDialog: false,
builder: (context) => PageScreen(
rackBookItems,
database: database,
),
),
);
}
#override
_PageScreenState createState() => _PageScreenState();
}
class _PageScreenState extends State<PageScreen> {
final _formKey = GlobalKey<FormState>();
bool _validateAndSaveForm() {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
Future<void> _completed() async {
if (_validateAndSaveForm()) {
try{
final checkBox = widget.rackBookItems?.checkBox ?? documentCheckBox();
final rackBookItems = RackBookItems(checkBox: checkBox);
await widget.database.setRackBook(rackBookItems);
Navigator.of(context).pop();
} on PlatformException catch (e) {
PlatformExceptionAlertDialog(
title: 'Operations failed',
exception: e,
).show(context);
}
}
}
#override
Widget build(BuildContext context) {
final auth = Provider.of<AuthBase>(context, listen: true);
return SafeArea(
child: Scaffold(
body: Column(
children: <Widget>[
StreamBuilder<User>(
stream: auth.onAuthStateChange,
builder: (context, snapshot) {
User user = snapshot.data;
if (snapshot.hasData) {
return Provider<Database>(
create: (_) => FirestoreDatabase(uid: user.uid),
child: Text('Data'),
);[![enter image description here][1]][1]
}
return Center(
child: CircularProgressIndicator(),
);
},
),
Form(
key: _formKey,
child: RaisedButton(
child: Text(
'Done',
style: TextStyle(color: Theme.of(context).accentColor),
),
onPressed: _completed,
),
)
],
),
),
);
}
}
class RackBookItems {
final String id;
final String rackId;
final String title;
final bool checkBox;
const RackBookItems({
this.id,
this.rackId,
this.title,
this.checkBox,
});
Map<String, dynamic> toMap() {
return {
'checkBox': checkBox,
};
}
factory RackBookItems.fromMap(Map<String, dynamic> data, String id) {
if (data == null) {
return null;
}
final String id = data['id'];
final String rackId = data['rackId'];
final String title = data['title'];
final bool checkBox = data['checkBox'];
return RackBookItems(
id: id,
rackId: rackId,
title: title,
checkBox: checkBox,
);
}
}
This is how my firebase looks like.
[1]: https://i.stack.imgur.com/Z07ai.png
Is there any error with the path I have given?
class APIPath {
static String rackBookItems( String uid, String id) =>
'rackBookItems/$id/';
}
You need to use updateData, this method required you to know the document's Document ID
Firestore.instance.collection('rackBookItems').document('book1').updateData({
'newData' : 14
});
If you need to update all of your documents, you can pull all of the documents and use a for loop to update them.
QuerySnapshot qs = await Firestore.instance.collection('rackBookItems').getDocuments();
List<DocumentSnapshot> books = qs.documents;
for (int i = 0; i < books.length; i++){
Firestore.instance.collection('rackBookItems').documents(books[i].documentID).updateData({
'title' : newData
});
}
updateData is good but in case the document does not exist you should use setData and set merge: true
class FirestoreService {
FirestoreService._();
static final instance = FirestoreService._();
Future<void> setData(
{#required String path, Map<String, dynamic> data}) async {
final reference = Firestore.instance.document(path);
await reference.setData(data, merge:true);
}
Related
Hello flutter experts i am fetching data from Api and show in listview in my app when user click any item from listview its saved data in sqlite now i want if API data already exist in sqlite then my trailing star icon change into yellow color otherwise it will remain same please check my code let me know i can achieve this type functionality mobile app.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:testfproject/Model/Articlemodel.dart';
import 'package:testfproject/Model/Favourite/Favouritemodel.dart';
import 'package:testfproject/Services/services.dart';
import 'package:http/http.dart' as http;
import '../Db/Databasehelper.dart';
class Home extends StatefulWidget {
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
void initState() {
// TODO: implement initState
super.initState();
// article();
}
Services api=Services();
Databasehelper databasehelper=Databasehelper();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Articles'),
),
body: Column(
children: [
FutureBuilder(
future: api.Article(),
builder: (BuildContext context, AsyncSnapshot<List<Articlemodel>> snapshot) {
if(snapshot.hasData){
List<Articlemodel>?articles=snapshot.data;
return Expanded(
child: ListView.separated(
shrinkWrap: true,
itemCount:articles!.length,
itemBuilder: (conext,index){
//this list tile when user press on trailing icon it saved data in sqlite
return ListTile(
trailing: IconButton(
icon:Icon(Icons.star),
onPressed: () {
databasehelper.insert(Favouritemodel(author: articles[index].author.toString(), title:articles[index].title.toString()));
},
),
title: Text(articles[index].title.toString()),
//subtitle: Text(articles[index].author.toString()),
);
}, separatorBuilder: (BuildContext context, int index) {
return Divider();
},),
);
}else{
return Container(
child: Text('NO data'),
);
}
},
)
],
),
);
}
}
//my Api services class
import 'dart:convert';
import 'package:testfproject/Model/Articlemodel.dart';
import 'package:http/http.dart' as http;
class Services{
Future<List<Articlemodel>>Article() async {
final response = await http.get(Uri.parse('https://newsapi.org/v2/top-headlines?country=us&apiKey=0fb3a9662c3747fba42ffd3d66cc612d'));
if(response.statusCode==200){
var data=jsonDecode(response.body.toString());
final Iterable json = data["articles"];
return json.map((article) => Articlemodel.fromJson(article)).toList();
}else{
throw Exception('Error');
}
}
}
model class of api
class Articlemodel {
Source? source;
String? author;
String? title;
String? description;
String? url;
String? urlToImage;
String? publishedAt;
String? content;
bool? iSfavourite;
Articlemodel(
{this.source,
this.author,
this.title,
this.description,
this.url,
this.urlToImage,
this.publishedAt,
this.content,
});
Articlemodel.fromJson(Map<String, dynamic> json) {
source =
json['source'] != null ? new Source.fromJson(json['source']) : null;
author = json['author'];
title = json['title'];
description = json['description'];
url = json['url'];
urlToImage = json['urlToImage'];
publishedAt = json['publishedAt'];
content = json['content'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.source != null) {
data['source'] = this.source!.toJson();
}
data['author'] = this.author;
data['title'] = this.title;
data['description'] = this.description;
data['url'] = this.url;
data['urlToImage'] = this.urlToImage;
data['publishedAt'] = this.publishedAt;
data['content'] = this.content;
return data;
}
}
class Source {
String? id;
String? name;
Source({this.id, this.name});
Source.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}
//model class of sqlite for favouriting
class Favouritemodel {Favouritemodel(
{required this.author,required this.title,}
);
Favouritemodel.fromJson(dynamic json) {
author = json['author'];
title = json['title'];
}
String? author;
String? title;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['author'] = author;
map['title'] = title;
return map;
}
}
//database helper class
import 'dart:io' as io;
import 'package:flutter/cupertino.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import '../Model/Favourite/Favouritemodel.dart';
class Databasehelper{
static Database? _db;
bool check=false;
Future<Database?> get db async {
if(_db != null)
return _db;
_db = await initDb();
return _db;
}
//Creating a database with name test.dn in your directory
initDb() async {
io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "favourite.db");
var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return theDb;
}
// Creating a table
void _onCreate(Database db, int version) async {
// When creating the db, create the table
await db.execute(
"CREATE TABLE favourite(ID INTEGER PRIMARY KEY AUTOINCREMENT, author TEXT, title TEXT unique )");
print("Created tables");
}
//insert data
Future<Favouritemodel> insert(Favouritemodel favouritemodel) async {
Database? db = await this.db;
await db!.insert('favourite', favouritemodel.toJson()).catchError((e)=>(debugPrint(e)));
return favouritemodel;
}
first add this function to your database helper
Future<List<Favouritemodel>> favourites() async {
Database? db = await this.db;
final List<Map> data = await db!.query('favourite');
return data.map((e) => Favouritemodel.fromJson(e)).toList();
}
and override the equal operator in Favouritemodel
#override
bool operator ==(Object other) {
return identical(this, other) ||
(other is Favouritemodel &&
author == other.author &&
title == other.title);
receive the favourite list in the build method:
#override
Widget build(BuildContext context) {
final futureFavourites = databasehelper.favourites();
return Scaffold(
// ...
and finally change the itemBuilder to this:
itemBuilder: (conext, index) {
return FutureBuilder<List<Favouritemodel>>(
future: futureFavourites,
builder: (context, favouriteSnapshot) {
if(!favouriteSnapshot.hasData) {
return ListTile(title: Text('Loading...'));
}
final favourites = favouriteSnapshot.data!;
final favouriteModel = Favouritemodel(author: articles[index].author.toString(),
title:articles[index].title.toString());
final isFavourite = favourites.contains(favouriteModel);
return ListTile(
trailing: IconButton(
icon:Icon(Icons.star, color: isFavourite ? Colors.yellow : null),
onPressed: () {
databasehelper.insert(favouriteModel);
},
),
title: Text(articles[index].title.toString()),
//subtitle: Text(articles[index].author.toString()),
);
}
);
}
I try to get a List from this Api(https://www.getpostman.com/collections/fa1296508e65891de558)
But there does no appear any Object. Console showing => "E/LB (26008): fail to open file: No such file or directory
".
I tried to print respone.statusCode but the result does'n apper in console.
I hope to solve this problem, Thank you.
What can be the problem here?
My code:
class ApiSetting{
static const String _baseUri='http://demo-api.mr-dev.tech/api/';
static const String users= '${_baseUri}users';
}
**User Model
** class User {
late int id;
late String firstName;
late String lastName;
late String email;
late String mobile;
late String bio;
late String jobTitle;
late String latitude;
late String longitude;
late String country;
late String image;
late String active;
late String emailVerifiedAt;
late String imagesCount;
User.fromJson(Map<String, dynamic> json) {
id = json['id'];
firstName = json['first_name'];
lastName = json['last_name'];
email = json['email'];
mobile = json['mobile'];
bio = json['bio'];
jobTitle = json['job_title'];
latitude = json['latitude'];
longitude = json['longitude'];
country = json['country'];
image = json['image'];
active = json['active'];
emailVerifiedAt = json['email_verified_at'];
imagesCount = json['images_count'];
}
}
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:api_secand_project/api/api_setting.dart';
import 'package:api_secand_project/models/user.dart';
class UserApiController {
Future<List<User>> getUser() async {
var uri = Uri.parse(ApiSetting.users);
var response = await http.get(uri);
if (response.statusCode == 200) {
print(response.statusCode);
var jsonResponse = jsonDecode(response.body);
var userJsonArray = jsonResponse['data'] as List;
return userJsonArray
.map((jsonObject) => User.fromJson(jsonObject))
.toList();
}
return [];
}
}
import 'package:api_secand_project/api/controllers/user_api_controller.dart';
import 'package:api_secand_project/models/user.dart';
import 'package:flutter/material.dart';
class UsersScreen extends StatefulWidget {
const UsersScreen({Key? key}) : super(key: key);
#override
State<UsersScreen> createState() => _UsersScreenState();
}
class _UsersScreenState extends State<UsersScreen> {
List<User> _users=<User>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Users'),
),
body: FutureBuilder<List<User>>(
future: UserApiController().getUser(),
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.waiting){
return const Center(
child: CircularProgressIndicator(),
);
}
else if(snapshot.hasData){
_users=snapshot.data!;
return ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
radius: 30,
// child: NetworkImage(snapshot.data!.),
),
title: Text(_users[index].firstName),
subtitle: Text(_users[index].mobile),
);
},
);
}
else{
return Center(child: Text('No Data',style: TextStyle(fontWeight: FontWeight.bold,fontSize: 28),),);
}
},
));
}
}
The question was not very clear, and there is no clear screenshot or message from the error console,
It seems that you are using the BLOC pattern and since part of the code is missing, you decide to create one from scratch, maybe it will help you, I thought not to publish it, but maybe something from here will help you
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class GetApi extends StatefulWidget {
const GetApi({super.key});
#override
State<GetApi> createState() => _GetApiState();
}
class _GetApiState extends State<GetApi> {
List<User> users = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Get Api")),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ElevatedButton(
onPressed: () {
getApi();
},
child: const Text("Get Api"),
),
Flexible(
child: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
User user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.id),
);
}),
),
],
),
);
}
Future<void> getApi() async {
users = [];
Uri uri = Uri.parse("https://www.getpostman.com/collections/fa1296508e65891de558 ");
http.Response response = await http.get(uri);
if (response.statusCode == 200) {
//debugPrint("body: ${response.body}");
Map data = jsonDecode(response.body);
for (MapEntry item in data.entries) {
//debugPrint("key: ${item.key} value: ${item.value}");
if ("item" == item.key) {
List usersResponse = data["item"];
//debugPrint("users: ${users}");
for (dynamic json in usersResponse) {
User user = User.fromJson(json);
users.add(user);
//debugPrint("user: ${_user.name}");
}
}
}
if (!mounted) return;
setState(() {});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("succes -> status: ${response.statusCode}"),
backgroundColor: Colors.green,
),
);
} else {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("fail -> status: ${response.statusCode}"),
backgroundColor: Colors.red,
),
);
}
}
}
class User {
late String name;
late String id;
User.fromJson(Map<String, dynamic> json) {
name = json['name'];
id = json['id'];
}
}
I'm a newbie in Flutter.
I have stored data in firestore in nested collections as you can see hereFirestore1 and hereFirestore2.
I wrote code for that as below:
class Timeline extends StatefulWidget {
#override
_TimelineState createState() => _TimelineState();
}
class _TimelineState extends State<Timeline>
with AutomaticKeepAliveClientMixin<Timeline> {
final eventref = FirebaseFirestore.instance.collection('event');
final slider = SleekCircularSlider(
appearance: CircularSliderAppearance(
spinnerMode: true,
size: 50.0,
));
List<EventCard> event = [];
getEvents() async {
print(user.uid);
QuerySnapshot snapshot =
await eventref.doc(user.uid).collection('post').limit(2).get();
List<EventCard> event = [];
snapshot.docs.forEach((doc) {
print('this is doc ------');
print(doc);
event.add(EventCard.fromMap(doc.data()));
});
return event;
}
#override
bool get wantKeepAlive => true;
#override
Widget build(context) {
return Scaffold(
body: Container(
child: FutureBuilder(
future: getEvents(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return slider;
}
print('reached here:${snapshot.data}');
return ListView(
children: snapshot.data,
);
},
)),
);
}
}
class EventCard extends StatelessWidget {
final String id;
final String event;
final String organiser;
final String description;
final String date;
final String startTime;
EventCard({
this.id,
this.event,
this.organiser,
this.description,
this.date,
this.startTime,
});
factory EventCard.fromMap(Map<String, dynamic> doc) {
return EventCard(
id: doc['id'],
event: doc['Event'],
organiser: doc['Organiser'],
description: doc['Description'],
date: doc['Date'],
startTime: doc['Start Time'],
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Text('Done'),
);
}
}
Sorry for long code, but only response i'm getting with this is here Debug Result
I tried to make 'EventCard' without build method as i saw in a tutorial online, but here it show error 'No concrete implementation of EventCard'
Any help? Thanks in Advance.
class Profile {
final List<String> photos;
final String name;
final int age;
final String education;
final String bio;
final int distance;
Profile({
this.photos,
this.name,
this.age,
this.education,
this.bio,
this.distance
});
}
class _MainControllerState extends State<MainController> {
static List<Profile> demoProfiles = fetchData();
static fetchData() async{
final db = await Firestore.instance;
List<Profile> list = [];
db.collection("users").getDocuments().then((querySnapshot){
querySnapshot.documents.forEach((document) {
list.add(Profile(
photos: document['photoUrl'],
name: document['photoUrl'],
age: document['photoUrl'],
distance: document['photoUrl'],
education: document['photoUrl']
));
});
});
return list;
}
final MatchEngine matchEngine = MatchEngine (
matches:demoProfiles.map((Profile profile) => Match(profile:
profile)).toList()
);
I am new to flutter.
when I run my code , I got the error :type 'Future' is not a subtype of type 'List .and if I change screen I will get the error:NoSuchMethodError: The method 'map' was called on null. How can I solve it ?
Thank you for helping me .
You need to specify the return type of method fetchData
static Future<List<Profile>> fetchData() async{
You need to convert you method to getData
Future<List<Data>> getData() async {
var response =
await http.get(Uri.https('jsonplaceholder.typicode.com', 'users'));
var jsonData = jsonDecode(response.body);
List<Data> dataList = [];
for (var u in jsonData) {
Data data = Data(u["name"], u["phone"], u["email"]);
dataList.add(data);
}
print(dataList.length);
return dataList;
}
And display in a Card
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Data Fetch"),
),
body: Container(
child: Card(
child: FutureBuilder<List<Data>>(
future: getData(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return ListTile(
title: Column(
children: [
Text(snapshot.data![i].name),
Text(snapshot.data![i].phone),
Text(snapshot.data![i].email),
],
),
);
});
}
},
),
),
));
}
Its worked for me :) :) I hope this will help you.
I am trying to use StreamProvider and StreamBuilder to pull data from firestore into my app with the code below. I am getting the error "streamusers and "userslist" are not defined as well as "testuser" is not a type. Here is a picture of my firestore databasefirestore setup]1
does anyone know how I can fix this so that it pulls the data from firestore and updates dynamically when new users are added?
Main.dart:
class _MyHomePageState extends State<MyHomePage> {
final auth = FirebaseAuth.instance;
final db = DatabaseService();
#override
Widget build(BuildContext context) {
var user = Provider.of<FirebaseUser>(context);
bool loggedIn = user != null;
final _width = MediaQuery.of(context).size.width;
final _height = MediaQuery.of(context).size.height;
StreamProvider<List<User>>.value(
value: db.streamUsers(user),
child: UsersList(),
),
StreamBuilder<TestUser>(
stream: db.streamTestUser(user.uid),
builder: (context, snapshot) {
var user = snapshot.data;
if (user != null) {
return Stack(...
I also have my db.dart file as so:
class DatabaseService {
final Firestore _db = Firestore.instance;
Future<User> getUser(String id) async {
var snap = await _db.collection('users').document(id).get();
return User.fromMap(snap.data);
}
Stream<User> streamTestUser(String id) {
return _db
.collection('users')
.document(id)
.snapshots()
.map((snap) => User.fromMap(snap.data));
}
}
And finally my user_model.dart file:
class User {
final String name;
final String photourl;
final int totalquestions;
User({this.name, this.photourl, this.totalquestions});
factory User.fromMap(Map data) {
return User(
name: data['name'] ?? '',
photourl: data['photourl'] ?? '',
totalquestions: data['totalquestions'] ?? '',
);
}
}
Try using Builder inside StreamProvider instead of StreamBuilder.
Mine is working using this approach.
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var user = Provider.of<FirebaseUser>(context);
return StreamProvider<User>.value(
value: db.getUser(user?.uid),
catchError: (_, __) => null,
child: Builder(
builder: (context) {
///Passing UserData Down the Builder
var _userSnapshot = Provider.of<UserData>(context);
///Check UserData Availability
if (_userSnapshot == null) {
return Center(
child: Text('User Empty'),
);
} else {
return Scaffold(
body: Column(
children: <Widget>[
Text(_userSnapshot?.name),
Text(_userSnapshot?.photourl),
Text(_userSnapshot?.totalquestions),
],
),
);
}
},
),
);
}