How to pass data between classes? Flutter - firebase

I have a class which I get email data from the user. It's basicly a textfield so I wont post the textfield code. After I get the email and password data, I check if these data is in my Firestore database. If it is, I want to pass this email data to my other class which I get the other informations about customer.
Here is the code of trying to check if user exists when I click the button.This is my LoginScreen() class' Material Button's onPressed action. I only get the email from the user here and want to pass this email data to my CustomerInfo class if the user already exists in my FirebaseAuth.Also the CustomerScreen class is for the show all customer information on the screen. I will add some code to push the customer information after I successfully get the data form database.
try {
final user = await _auth.signInWithEmailAndPassword(
email: email!, password: password!);
if (user != null) {
CustomerInfo(email: email);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CustomerScreen()));
}
} catch (e) {
print(e);
}
Also I have another class which I'm trying to get customers data.
class CustomerInfo {
String? email;
String? name;
String? surname;
String? avatarLink;
int? balance;
CollectionReference customers =
FirebaseFirestore.instance.collection('customers');
CustomerInfo({this.email});
Future getCustomerData() async {
print("Email: $email");
await customers.where('email', isEqualTo: email).get().then((value) {
value.docs.forEach((result) {
name = result['name'];
surname = result['surname'];
balance = result['balance'];
avatarLink = result['image'];
});
});
}
}
Also CustomerInfo class:
import 'package:banking_app_firebase/constants.dart';
import 'package:banking_app_firebase/networking.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'login_screen.dart';
class CustomerScreen extends StatefulWidget {
const CustomerScreen({Key? key}) : super(key: key);
#override
_CustomerScreenState createState() => _CustomerScreenState();
}
class _CustomerScreenState extends State<CustomerScreen> {
String? name;
String? surname;
int? balance;
String? image;
void getData() async {
CustomerInfo customerInfo = CustomerInfo();
await customerInfo.getCustomerData();
name = customerInfo.name;
print("Name: $name");
}
#override
void initState() {
// TODO: implement initState
super.initState();
getData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: IconThemeData(
color: Colors.black,
),
title: Text(
"Account Summary",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
actions: [
Container(
padding: EdgeInsets.only(right: 10),
child: Row(
children: [
Icon(
CupertinoIcons.bell,
color: Colors.black,
),
SizedBox(
width: 10,
),
CircleAvatar(
backgroundImage: NetworkImage(
"https://cdn.pixabay.com/photo/2016/03/23/04/01/woman-1274056_960_720.jpg"),
),
],
),
),
],
elevation: 0,
),
body: Container(
child: Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Text(
"Deneme",
style: kInfoTextDecoration,
),
),
Align(
alignment: Alignment.topLeft,
child: Text(
"Deneme",
style: kInfoTextDecoration,
),
),
],
),
),
);
}
}
How can I pass the email data to my CustomerInfo class so I can use getCustomerData()? Using CustomerInfo(email:email) did not work.

I am sorry, I think I misunderstood your question.
Is this what you are trying to do? You are passing email correctly. You just need to call getCustomerData()
try {
final user = await _auth.signInWithEmailAndPassword(
email: email!, password: password!);
if (user != null) {
var customerInfo = CustomerInfo(email: email);
await customerInfo.getCustomerData();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CustomerScreen(customerInfo: customerInfo)));
}
} catch (e) {
print(e);
}
Then in CustomerScreen it would look like this
class CustomerScreen extends StatefulWidget {
final CustomerInfo customerInfo;
const CustomerScreen({Key? key, this.customerInfo}) : super(key: key);
#override
_CustomerScreenState createState() => _CustomerScreenState();
}
class _CustomerScreenState extends State<CustomerScreen> {
String? name;
String? surname;
int? balance;
String? image;
void getData() {
name = widget.customerInfo.name;
surname = widget.customerInfo.surname;
balance = widget.customerInfo.balance;
image = widget.customerInfo.image;
}
But I would recommend you take a look into FutureBuilder.

this will not work as the email field is not static so you can't use CustomerInfo.getCustomerData(). You need to create an instance of custom user and then use the getCustomerData() method.
For example: var data = await CustomerInfo(email: email).getCustomerData();
or if you are going to use the CustomerInfo()` multiple times you can do the following:
final CustomerInfo info = CustomerInfo(email: email);
var data = info.getCustomerData();
or something similar to that.
If you are trying to display the info inside of the CustomScreen() I think it might be easier to just create a CustomerInfo() there and get whatever data you need.
All I can do is guess as you haven't provided a sample for CustomScreen() or what it is meant to do. If you are trying to the customer data in the CustomScreen() then it might be better to use a FutureBuilder() to show your user that the data is loading then display it once the future completes rather than just having an async callback before pushing the route making the user think that they didn't click the button.

It depends on your preferences. For example, usually, I create a global.dart and store temporary variables there. for example in your global.dart:
CustomerInfo selectedUser;
then you can set it wherever you want. for example:
import './global.dart' as global;
try {
final user = await _auth.signInWithEmailAndPassword(
email: email!, password: password!);
if (user != null) {
CustomerInfo(email: email);
global.selectedUser = CustomeInfo(SET PARAMETERS);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CustomerScreen()));
}
} catch (e) {
print(e);
}
the you can use it by calling global.selectedUser wherever you want.
Other approach is using Provider but it is useful when you want to change the variable in many files.
Also, you can use firebase methods for getting active user and his/her info like getEmail() but I do not recommend it because of unnecessary API call.

Get the email info from _auth.
try {
final user = await _auth!.signInWithEmailAndPassword(
email: email!, password: password!);
if (user.user !=null) { // added user.user
CustomerInfo(email: user.user!.email); //added user.user!.email
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CustomerScreen()));
}
} catch (e) {
print(e);
}

Related

How can I check if value exists in Firebase using Flutter? [duplicate]

I have a collection called company.
All the companies are going to be stored like in my screenshot.
When I add another company, I want to check if the name already exists or not.
How to perform that?
Here, "Nova" and "Tradetech" are two companies.
When I try to add "Nova" with the field name: "nova" again, I want to show a notice: "Company already exists!".
I have solved this issue with the follwoing code, thanks for helping me!
IN THE FOLLOWING CODE I USED TO FIND
1)A DOCUMENT IS EXISTING OR NOT?
2)A KEY IS EXISTING OR NOT?
3)A VALUE IS EXISTING OR NOT?
SIMPLE METHOD
//////////////////////////////////////////////////////////////////////
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
String myText1 = 'temp1';
String myText2 = 'temp2';
String myText3 = 'temp3';
String myText4 = 'temp4';
String myText5 = 'temp5';
String myText6 = 'temp6';
StreamSubscription<DocumentSnapshot> subscription;
final DocumentReference documentReference =
Firestore.instance.document("company/Nova");
class Clean extends StatefulWidget {
#override
_CleanState createState() => _CleanState();
}
class _CleanState extends State<Clean> {
#override
void initState() {
super.initState();
subscription = documentReference.snapshots().listen((datasnapshot) {
//FINDING A SPECIFICDOCUMENT IS EXISTING INSIDE A COLLECTION
if (datasnapshot.exists) {
setState(() {
myText1 = "Document exist";
});
} else if (!datasnapshot.exists) {
setState(() {
myText2 = "Document not exist";
});
}
//FINDING A SPECIFIC KEY IS EXISTING INSIDE A DOCUMENT
if (datasnapshot.data.containsKey("name")) {
setState(() {
myText3 = "key exists";
});
} else if (!datasnapshot.data.containsKey("name")) {
setState(() {
myText4 = "key not exists";
});
}
//FINDING A SPECIFIC VALUE IS EXISTING INSIDE A DOCUMENT
if (datasnapshot.data.containsValue("nova")) {
setState(() {
myText5 = "value exists";
});
} else if (!datasnapshot.data.containsValue("nova")) {
setState(() {
myText6 = "value not exists";
});
}
});
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
new Text(myText1),
new Text(myText2),
new Text(myText3),
new Text(myText4),
new Text(myText5),
new Text(myText6),
],
);
}
}
MY OLD COMPLEX METHOD BASED ON MY EXISTING CODE
////////////////////////////////////////////////////////
Concept
it has a search bar,when you type it will show the company name ie existing or not in
A Card and a RaisedButton. I am using lower case in Firestore in order to avoid the search error. I have forced the TextFormField output to be lower case with toLowercase(). You can change it to your own text format.
Code
//if the name is not existing it will show a raised button so u can clcik on that to
//go to a COMPANY ADDING PAGE,otherwise it will only show a **CARD** so that you
//can't go to the next page to add your company
//code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
import './fullscreen.dart';
const blue = 0xFF3b78e7;
String filter = '';
StreamSubscription<DocumentSnapshot> subscription;
final TextEditingController _usercontroller = new TextEditingController();
class CheckAvail extends StatefulWidget {
#override
HomeState createState() => HomeState();
}
class HomeState extends State<CheckAvail> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
// CHILD1
new Flexible(
child: StreamBuilder(
stream: Firestore.instance
.collection('company')
.where('name', isGreaterThanOrEqualTo: filter.toLowerCase())
.limit(1)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return new Column(
children: <Widget>[
new Card(
elevation: 5.0,
child: new Image.asset('assets/progress.gif'),
)
],
);
} else {
return FirestoreListView1(documents: snapshot.data.documents);
}
},
),
),
new Card(
elevation: 0.0,
color: Colors.white,
shape: new RoundedRectangleBorder(
borderRadius: BorderRadius.circular(60.0)),
child: Container(
padding: new EdgeInsets.only(left: 8.0),
child: new TextField(
controller: _usercontroller,
onChanged: (String z) {
setState(() {
filter = z;
});
},
decoration: const InputDecoration(
hintText: "Search...",
hintStyle: TextStyle(
fontFamily: 'roboto',
color: Colors.black38,
fontSize: 16.0,
letterSpacing: -0.500),
fillColor: Colors.white,
border: InputBorder.none,
),
),
),
),
],
),
backgroundColor: Color(blue),
);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FirestoreListView1 extends StatelessWidget {
final List<DocumentSnapshot> documents;
FirestoreListView1({this.documents});
#override
Widget build(BuildContext context1) {
return ListView.builder(
itemCount: documents.length,
padding: new EdgeInsets.all(1.0),
itemBuilder: (BuildContext context1, int index) {
String name = documents[index].data['name'];
if (name.contains(filter.toLowerCase()) &&
name.length == filter.length) {
return new Container(
padding: new EdgeInsets.only(top: 45.0),
child: new Card(
child: new Text(
"Error:Already a Company Exists with this name\nTry another name")),
);
} else {
return (filter.length >= 1)
? new Container(
padding: new EdgeInsets.only(top: 15.0),
child: new RaisedButton(
onPressed: () => Navigator.push(
context1,
new MaterialPageRoute(
builder: (context1) => new NextPage(
value1: name,
))),
disabledColor: Colors.white,
child: new Text(
"Good!You can use this company name",
),
),
)
: new Container(padding: new EdgeInsets.only(top: 250.0),
child: new Card(child: new Text("CHECK IF YOUR COMPANY NAME \n AVAILABLE OR NOT",style: new TextStyle(fontSize: 20.0),)),
);
}
});
}
}
You can simply use a where query to only receive documents that have that name and then check whether you get documents. Here is an async example method that would perform what you want to know.
Example method
Future<bool> doesNameAlreadyExist(String name) async {
final QuerySnapshot result = await Firestore.instance
.collection('company')
.where('name', isEqualTo: name)
.limit(1)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
return documents.length == 1;
}
As you can see, I am only receiving documents, where the name field matches the given name. I also add limit(1) to make sure that I do not unnecessarily retrieve more than 1 document (which would never happen in theory) and then I just check if the length of all documents in the company collection is equal to 1 or not. If it is equal to 1, there already is a company that has that name and otherwise not.
You could also remove the limit(1) and make the check documents.length > 1 and that would work too, but might retrieve unnecessary documents.
Example implementation
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: doesNameAlreadyExist('nova'),
builder: (context, AsyncSnapshot<bool> result) {
if (!result.hasData)
return Container(); // future still needs to be finished (loading)
if (result.data) // result.data is the returned bool from doesNameAlreadyExists
return Text('A company called "Nova" already exists.');
else
return Text('No company called "Nova" exists yet.');
},
);
}
Here, I am not displaying an error message, which would be easily possible with the example method as well. However, the build method of some widget is used. This would e.g. work in a dialog, but I decided to do it to keep it simple and understandable. The FutureBuilder takes in doesNameAlreadyExist, in this case with the name "Nova" from your question and will, in the end, return a Text widget stating whether the name already exists.
Be careful
The where query is case-sensitive. This means that the check would not work if you typed e.g. "noVa" instead of "nova". As this might be important to you, you can make use of this nice method, where you would create an extra field that is insensitive, e.g. all letters are small and then you would simple query like this:
.where('name_insensitive', isEqualTo: name.toLowerCase())
final QuerySnapshot result =
await Firestore.instance.collection('users').where('nickname', isEqualTo:
nickname).getDocuments();
final List < DocumentSnapshot > documents = result.documents;
if (documents.length > 0) {
//exists
} else {
//not exists
}
Use the function:
snapshot.data!.data()!.containsKey('key_name')
to check if a field exists in your document.
PS. I just used this in my code RN and it works
I know I am late.
Posting for future users.
Try this:
DocumentReference datab = db.collection("Company").document("Nova");
datab.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if(documentSnapshot.contains("name"))
{
Toast.makeText(YourActivity.this, "Child exixts.", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(YourActivity.this, "Doesnt exits.", Toast.LENGTH_SHORT).show();
}
});

TextEditingController doesn't clear the text after .clear()

So im trying to clear the textform after sending a message and if the message is empty the send button should be disabled , what i'm having is the onPressed for the button is never null , it's never disabled , and the text is cleared but if i send again it sends the previous text before clearing if that makes sense
so if i send Hello , it shows as empty but the button still active , if i resend again without entering anything it sends the same cleared text , any idea what i could be doing wrong ?
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class NewMessage extends StatefulWidget {
#override
_NewMessageState createState() => _NewMessageState();
}
class _NewMessageState extends State<NewMessage> {
final _controller = TextEditingController();
String _enteredMessage = '';
void _sendMessage() async {
setState(() {
_controller.clear();
});
FocusScope.of(context).unfocus();
final user = FirebaseAuth.instance.currentUser;
final userData = await FirebaseFirestore.instance
.collection('users')
.doc(user.uid)
.get();
FirebaseFirestore.instance.collection('chat').add({
'text': _enteredMessage,
'createdAt': Timestamp.now(),
'userId': user.uid,
'username': userData['username'],
});
}
void sayHello() {
print('hello');
}
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: 8),
padding: EdgeInsets.all(8),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(labelText: 'Send a message...'),
onChanged: (value) {
setState(() {
_enteredMessage = value;
});
},
),
),
IconButton(
icon: Icon(Icons.send, color: Theme.of(context).primaryColor),
onPressed: _enteredMessage.trim().isEmpty ? null : _sendMessage,
)
],
),
);
}
}
Problem
The reason you are having the error is that you are storing in the input in the enteredText variable but are clearing the controller's text, both of which are different. Which is why your enteredText still holds and send the same string after clearing.
Solution
You don't have to use a separate variable to hold your input text if you have given a controller. The controller already holds the value of the input. Make the following changes:
IconButton(
...,
onPressed: (){
_controller.text = _controller.text.trim();
if(_controller.text.isNotEmpty) {
_sendMessage();
}
}
)
Use the text from _controller with _controller.text
void _sendMessage() async {
FocusScope.of(context).unfocus();
final user = FirebaseAuth.instance.currentUser;
final userData = await FirebaseFirestore.instance
.collection('users')
.doc(user.uid)
.get();
FirebaseFirestore.instance.collection('chat').add({
'text': _controller.text, //<-- Update here
'createdAt': Timestamp.now(),
'userId': user.uid,
'username': userData['username'],
});
setState(() { //<-- Clear at the end
_controller.clear();
});
}
Finally
You can now get rid of the enteredText variable and the onChange callback.

Exception: Bad state: cannot get a field on a DocumentSnapshotPlatform which does not exist

The method mentioned in this thread https://stackoverflow.com/a/50867881/13153574 I am trying to fetch data from Firestore. But getting the following exception. The 'name' field is a String and 'overview' field is a List of Strings.
Bad state: cannot get a field on a DocumentSnapshotPlatform which does not exist
My code is as below:
import 'package:firebaseAuth/firebaseAuthDemo.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class FindDiseases extends StatefulWidget {
final User user;
const FindDiseases({Key key, this.user}) : super(key: key);
#override
_FindDiseasesState createState() => _FindDiseasesState();
}
class _FindDiseasesState extends State<FindDiseases> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
FirebaseAuth _auth = FirebaseAuth.instance;
List diseasesList = [];
//dynamic data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.teal,
automaticallyImplyLeading: false,
title: Text(
"Diseases List",
),
),
key: _scaffoldKey,
body: Center(
child: FlatButton(
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("get Disease Record"),
StreamBuilder<DiseaseRecord>(
stream: getDisease(),
builder: (BuildContext c, AsyncSnapshot<DiseaseRecord> data) {
if (data?.data == null) return Text("Error");
DiseaseRecord r = data.data;
return Text("${r.name}");
},
),
],
),
onPressed: () {
getDisease();
},
),
),
);
}
Future _signOut() async {
await _auth.signOut();
}
}
Stream<DiseaseRecord> getDisease() {
return FirebaseFirestore.instance.collection("diseases").doc().get().then(
(snapshot) {
try {
return DiseaseRecord.fromSnapshot(snapshot);
} catch (e) {
print(">>> Error:"+e.toString());
return null;
}
},
).asStream();
}
class DiseaseRecord {
String name;
List<String> overview = new List<String>();
DiseaseRecord.fromSnapshot(DocumentSnapshot snapshot)
: name = snapshot['name'],
overview = List.from(snapshot['overview']);
}
Data is something like as below:
name: "name--"
overview: "['a', 'b', 'c']"
The problem is here:
return FirebaseFirestore.instance.collection("diseases").doc().get()
Calling doc() without any arguments creates a reference to a new, non-existing document. Then calling get() on that, returns a DocumentSnapshot for a non-existing document, and trying to get fields from that is an invalid operation.
Most likely you'll need to know the ID of the disease document you're trying to load, and pass that in to the call to doc(id).

Saving a value as a string with Flutter Firestore Firebase

I want to save a value from my Cloud Firestore as a string. I am using Flutter with Dart. I have been able to save it when building the page using MaterialepageRoute:
MaterialPageRoute(
builder: (context) => MainScreen(
currentUserId: firebaseUser.uid,
currentUserGender: document['gender'],
currentUserPreference: document['preference'],
)),
But this isn't an option with all of my pages, so I have to look for something else. I want to get the value from my Firestore Database, and then save it as a string, since I want to:
if (currentUserGender == 'male') {
//then do something
}
I have no idea how to do this, I have thought about using a Class, maybe the "get"-function with Firebase, but none have worked. I am not really sure how to do this, so any help is appreciated. I am able to get the currentUser. Here is a picture of my database:
https://imgur.com/KL7HX6P
Thanks in advance.
A Minimal Example: To fetch a Single Document Fields. Swap Collection & Document name in the code with your Own Names.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class GetUser extends StatefulWidget {
#override
_GetUserState createState() => _GetUserState();
}
class _GetUserState extends State<GetUser> {
Map<String, dynamic> userDetails = {};
Future<Null> getUser() async {
await Firestore.instance
.collection('users') // Your Collections Name
.document('eMAE4XF9cTYS12MpfOuWBW4P2WH3') // Your user Document Name
.get()
.then((val) {
userDetails.addAll(val.data);
}).whenComplete(() {
print('Data Fetched');
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
textColor: Colors.white,
color: Theme.of(context).accentColor,
onPressed: () async {
await getUser();
},
child: Text('Get User Detail from Cloud'),
),
userDetails.length > 0
? Column(
children: <Widget>[
Text('${userDetails['gender']}'),
Text('${userDetails['id']}'),
Text('${userDetails['nickname']}'),
userDetails['gender'] == 'male'
? Text('Its Boy')
: Text('Girl'),
],
)
: Text('No user Data, Please Fetch'),
],
),
),
);
}
}

Check if Field Already exists in Flutter Firestore

I have a collection called company.
All the companies are going to be stored like in my screenshot.
When I add another company, I want to check if the name already exists or not.
How to perform that?
Here, "Nova" and "Tradetech" are two companies.
When I try to add "Nova" with the field name: "nova" again, I want to show a notice: "Company already exists!".
I have solved this issue with the follwoing code, thanks for helping me!
IN THE FOLLOWING CODE I USED TO FIND
1)A DOCUMENT IS EXISTING OR NOT?
2)A KEY IS EXISTING OR NOT?
3)A VALUE IS EXISTING OR NOT?
SIMPLE METHOD
//////////////////////////////////////////////////////////////////////
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
String myText1 = 'temp1';
String myText2 = 'temp2';
String myText3 = 'temp3';
String myText4 = 'temp4';
String myText5 = 'temp5';
String myText6 = 'temp6';
StreamSubscription<DocumentSnapshot> subscription;
final DocumentReference documentReference =
Firestore.instance.document("company/Nova");
class Clean extends StatefulWidget {
#override
_CleanState createState() => _CleanState();
}
class _CleanState extends State<Clean> {
#override
void initState() {
super.initState();
subscription = documentReference.snapshots().listen((datasnapshot) {
//FINDING A SPECIFICDOCUMENT IS EXISTING INSIDE A COLLECTION
if (datasnapshot.exists) {
setState(() {
myText1 = "Document exist";
});
} else if (!datasnapshot.exists) {
setState(() {
myText2 = "Document not exist";
});
}
//FINDING A SPECIFIC KEY IS EXISTING INSIDE A DOCUMENT
if (datasnapshot.data.containsKey("name")) {
setState(() {
myText3 = "key exists";
});
} else if (!datasnapshot.data.containsKey("name")) {
setState(() {
myText4 = "key not exists";
});
}
//FINDING A SPECIFIC VALUE IS EXISTING INSIDE A DOCUMENT
if (datasnapshot.data.containsValue("nova")) {
setState(() {
myText5 = "value exists";
});
} else if (!datasnapshot.data.containsValue("nova")) {
setState(() {
myText6 = "value not exists";
});
}
});
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
new Text(myText1),
new Text(myText2),
new Text(myText3),
new Text(myText4),
new Text(myText5),
new Text(myText6),
],
);
}
}
MY OLD COMPLEX METHOD BASED ON MY EXISTING CODE
////////////////////////////////////////////////////////
Concept
it has a search bar,when you type it will show the company name ie existing or not in
A Card and a RaisedButton. I am using lower case in Firestore in order to avoid the search error. I have forced the TextFormField output to be lower case with toLowercase(). You can change it to your own text format.
Code
//if the name is not existing it will show a raised button so u can clcik on that to
//go to a COMPANY ADDING PAGE,otherwise it will only show a **CARD** so that you
//can't go to the next page to add your company
//code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
import './fullscreen.dart';
const blue = 0xFF3b78e7;
String filter = '';
StreamSubscription<DocumentSnapshot> subscription;
final TextEditingController _usercontroller = new TextEditingController();
class CheckAvail extends StatefulWidget {
#override
HomeState createState() => HomeState();
}
class HomeState extends State<CheckAvail> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
// CHILD1
new Flexible(
child: StreamBuilder(
stream: Firestore.instance
.collection('company')
.where('name', isGreaterThanOrEqualTo: filter.toLowerCase())
.limit(1)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return new Column(
children: <Widget>[
new Card(
elevation: 5.0,
child: new Image.asset('assets/progress.gif'),
)
],
);
} else {
return FirestoreListView1(documents: snapshot.data.documents);
}
},
),
),
new Card(
elevation: 0.0,
color: Colors.white,
shape: new RoundedRectangleBorder(
borderRadius: BorderRadius.circular(60.0)),
child: Container(
padding: new EdgeInsets.only(left: 8.0),
child: new TextField(
controller: _usercontroller,
onChanged: (String z) {
setState(() {
filter = z;
});
},
decoration: const InputDecoration(
hintText: "Search...",
hintStyle: TextStyle(
fontFamily: 'roboto',
color: Colors.black38,
fontSize: 16.0,
letterSpacing: -0.500),
fillColor: Colors.white,
border: InputBorder.none,
),
),
),
),
],
),
backgroundColor: Color(blue),
);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FirestoreListView1 extends StatelessWidget {
final List<DocumentSnapshot> documents;
FirestoreListView1({this.documents});
#override
Widget build(BuildContext context1) {
return ListView.builder(
itemCount: documents.length,
padding: new EdgeInsets.all(1.0),
itemBuilder: (BuildContext context1, int index) {
String name = documents[index].data['name'];
if (name.contains(filter.toLowerCase()) &&
name.length == filter.length) {
return new Container(
padding: new EdgeInsets.only(top: 45.0),
child: new Card(
child: new Text(
"Error:Already a Company Exists with this name\nTry another name")),
);
} else {
return (filter.length >= 1)
? new Container(
padding: new EdgeInsets.only(top: 15.0),
child: new RaisedButton(
onPressed: () => Navigator.push(
context1,
new MaterialPageRoute(
builder: (context1) => new NextPage(
value1: name,
))),
disabledColor: Colors.white,
child: new Text(
"Good!You can use this company name",
),
),
)
: new Container(padding: new EdgeInsets.only(top: 250.0),
child: new Card(child: new Text("CHECK IF YOUR COMPANY NAME \n AVAILABLE OR NOT",style: new TextStyle(fontSize: 20.0),)),
);
}
});
}
}
You can simply use a where query to only receive documents that have that name and then check whether you get documents. Here is an async example method that would perform what you want to know.
Example method
Future<bool> doesNameAlreadyExist(String name) async {
final QuerySnapshot result = await Firestore.instance
.collection('company')
.where('name', isEqualTo: name)
.limit(1)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
return documents.length == 1;
}
As you can see, I am only receiving documents, where the name field matches the given name. I also add limit(1) to make sure that I do not unnecessarily retrieve more than 1 document (which would never happen in theory) and then I just check if the length of all documents in the company collection is equal to 1 or not. If it is equal to 1, there already is a company that has that name and otherwise not.
You could also remove the limit(1) and make the check documents.length > 1 and that would work too, but might retrieve unnecessary documents.
Example implementation
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: doesNameAlreadyExist('nova'),
builder: (context, AsyncSnapshot<bool> result) {
if (!result.hasData)
return Container(); // future still needs to be finished (loading)
if (result.data) // result.data is the returned bool from doesNameAlreadyExists
return Text('A company called "Nova" already exists.');
else
return Text('No company called "Nova" exists yet.');
},
);
}
Here, I am not displaying an error message, which would be easily possible with the example method as well. However, the build method of some widget is used. This would e.g. work in a dialog, but I decided to do it to keep it simple and understandable. The FutureBuilder takes in doesNameAlreadyExist, in this case with the name "Nova" from your question and will, in the end, return a Text widget stating whether the name already exists.
Be careful
The where query is case-sensitive. This means that the check would not work if you typed e.g. "noVa" instead of "nova". As this might be important to you, you can make use of this nice method, where you would create an extra field that is insensitive, e.g. all letters are small and then you would simple query like this:
.where('name_insensitive', isEqualTo: name.toLowerCase())
final QuerySnapshot result =
await Firestore.instance.collection('users').where('nickname', isEqualTo:
nickname).getDocuments();
final List < DocumentSnapshot > documents = result.documents;
if (documents.length > 0) {
//exists
} else {
//not exists
}
Use the function:
snapshot.data!.data()!.containsKey('key_name')
to check if a field exists in your document.
PS. I just used this in my code RN and it works
I know I am late.
Posting for future users.
Try this:
DocumentReference datab = db.collection("Company").document("Nova");
datab.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if(documentSnapshot.contains("name"))
{
Toast.makeText(YourActivity.this, "Child exixts.", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(YourActivity.this, "Doesnt exits.", Toast.LENGTH_SHORT).show();
}
});

Resources