How can I take document from Firebase in Flutter? - android

I am dealing with the Futurebuilder in the Flutter, and I want to create a Future function that is going to take data from my Firebase. After that, I want to use that data inside of the text widget, so I tried to write this function to take data from firebase.
Future getData() async {
var fb = Firestore.instance;
DocumentSnapshot dr = (await fb.collection("records").document("the record").get());
return dr.toString();
}
But when I tried to use that data inside of the FutureBuilder, I am taking just Instance of 'DocumentSnapsot' text.
Here you can see my FutureBuilder codes
body: Center(
child: FutureBuilder(
future: getData(),
builder: (_ ,snapshot){
if(snapshot.connectionState==ConnectionState.waiting) {
return RaisedButton(
child: Text("loading" ),
onPressed: null,
);
}
if(snapshot.connectionState==ConnectionState.done) {
return RaisedButton(
child: Text(snapshot.data),
onPressed: () {},
);
}
return null;
}
And this is the result, after the running program:
Also, This my firebase. I just want to reach, and manipulate 0 value inside of the program.

The DocumentSnapshot toString method does not provide the data contained within the document you are trying to retrieve. To obtain the data in the document from a DocumentSnapshot, do dr.data, which returns a Map containing the fields and the associated data of those fields stored in the document. This should be done in your getData() method.
The toString method for DocumentSnapshot returns "Instance of 'DocumentSnapshot'", hence why your button is showing that instead of what you intend.

Related

How to Shrink Characters of Incoming Data from Flutter Firestore?

I wrote a code like this:
StreamBuilder(
stream: _firestore.collection("Products").where("Name", isGreaterThanOrEqualTo: SearchText.toLowerCase()).snapshots(),
builder: (BuildContext context, snapshot) {
if (snapshot.data == null) {
return const Text("No data");
}
return ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(snapshot.data.docs[index].data()["Name"]),
),
);
},
);
}
),
I want to shrink the data from Firestore with .toLowerCase() or otherwise. In order to make a search system, I need to shrink the incoming data. How can I do that?
Thanks for help.
I don't understand what you mean by shrink. You mentioned toLowerCase() so this is what I think the problem is
You have a stream of product names from firestore and you want to be able to make them searchable. The user search query text might be lowercase so you want to run your search on the products from firestore(lowercased)
One way to do this is to modify the stream of products that you are getting from your firestore . You can run this on dartpad.dev/
Here is a simple example with a fake list of products. I have illustrated how to use something called a streamTransformer
// A mock list of products
final List<String> productList = [
"Airpods",
"Wallet",
"Glasses",
"Gatorade",
"Medicine"
];
// A stream that exposes the product list
Stream<String> productStream() async* {
for(var product in productList){
yield product;
}
}
void main() {
// Use a stream transformer to transform or modify the stream
StreamTransformer<String, dynamic> lowerCaser = StreamTransformer.fromHandlers(handleData: (data,sink)=> sink.add(data.toString().toLowerCase()));
// Transform the stream with the .transform function
productStream().transform(lowerCaser).listen(
(product)=>print(product)
);
}

Flutter get Data Value from GetStorage List

i wanna get a Data from GetStorage(),
i got a Shop List and i can use it as Static for only page, that way im saving my List in GetStorage,if i go to another Page that will showed also. Like a SharedPreferences. How can i show a data from GetStorage List Value , like
Text(basket[name]), that will show only the Names,
Text(basket[price]), that will show only Prices,
var basketsd = GetStorage("totalList");
My ProductModel for Shop,
class PriceModel2 {
final String name;
final double price;
PriceModel2({
this.name,
this.price,
});
}
its also not worked.
Text(controller.basketsd.read(["name"])
Container(
height: Get.size.height * 0.3,
child: Obx(() => ListView.builder(
itemCount: controller.basket.length,
itemBuilder: (BuildContext context, int index) {
return Column(
children: [
SizedBox(
height: 20,
),
Container(
width: Get.size.width,
child: ElevatedButton(
onPressed: () {
controller.basket
.remove(controller.basket[index]);
},
child: (Text(controller.basketsd.read(["name"]) +
" " +
controller.basket[index].price.toString() +
" €"))),
),
SizedBox(
height: 20,
),
],
);
})),
),
Codes show like this ,
(https://prnt.sc/1fs6mbf)
There's a couple issues here. At least from what you're sharing, you're never really storing your PriceModel2 object properly. If you try and store a random custom object, GetStorage will not know what to do with it. (Neither would SharedPreferences in the same scenario).
So for starters, you can implement a toMap function that converts it to a map that GetStorage can read.
Add this to your PriceModel2 class.
Map<String, dynamic> toMap() {
return {
'name': name,
'price': price,
};
}
Then you add a named constructor in the same class so you can create your object from the Map that you stored.
PriceModel2.fromMap(Map map)
: name = map['name'],
price = map['price'];
I also suggest, regardless of whichever storage library you're using, keeping all storage related functionality, including boxes in this case, in its own class, that stores and returns whatever data you need. This way if you ever need to upgrade to Hive, ObjectBox etc... you do it in one class and not all over your app.
An example would look like this.
class Database extends GetxController {
final box = GetStorage();
Future<void> initStorage() async {
await GetStorage.init();
}
void storePriceModel(PriceModel2 model) {
box.write('model', model.toMap());
}
PriceModel2 restoreModel() {
final map = box.read('model') ?? {};
return PriceModel2.fromMap(map);
}
}
Then you would initialize your controller and storage in main.
void main() async {
await Get.put(Database()).initStorage();
runApp(MyApp());
}
An example of storing a model would look like this.
ElevatedButton(
onPressed: () {
final model = PriceModel2(name: 'test name', price: 23.0);
Get.find<Database>().storePriceModel(model);
},
child: Text('Store Model'),
),
And displaying the storage data in the UI could be done like so.
Text(Get.find<Database>().restoreModel().name)
You don't need an Obx just to display the stored data because its not an observable stream based variable.
As for displaying a list of products you do the same thing but store a list of maps instead of a single map.
If you need help with that then share how you're trying to add and store to the PriceModel2 list.

Stuck Loader in FutureBuilder

I'm new of Flutter and Dart in general, I'm trying to do a expansive computation during the loading of the page but the loader is stuck when I try to do something like this:
body: Center(
child:FutureBuilder(
future: _lorem()
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done){
print("loader");
return Center(
child: CircularProgressIndicator(
backgroundColor: Theme.of(context).primaryColor)
);
}
[...]
Future<void> _lorem() async {
//there is not a request to service, there is a more than one filter on map and some lists. I set the for loop for example of a local computation
return Future(() {
for (int i = 0; i < 50000; i++){
print(i);
}
}
);
}
I think the easier way to implement this is using a field in your widget of type Completer, eg Completer calc. You can start your expensive computation in your widget initialization (never in your build function), and when the computation is done you complete that Completer by calling calc.complete().
In your widget's FutureBuilder you should then listen to calc's future by including future: calc.future instead of your future: _lorem().
See FutureBuilder for an example of this UI paradigm.
Solved with a Future and compute.
In the detail:
Future<List<CustomObject>> _retrieveCustomObjects() async {
SourceData data = SourceData(CustomSourceData());
return compute(getFilteredClients, data);
}
List<CustomObject> computeCustomObject(SourceData data) {
List<CustomObject> list = [];
// expensive logic on data, not only network call
return list;
}
class LoremIpsumClass {
// use where you need `List<CustomObject> value = await _retrieveFilteredClient();`
}

Flutter validator only trigger on double tap

i stored phone numbers in a firebase document(table). What i want is to detect if the number already existed by using validators and display a message under a textbox that the phone number is already exists i had no problem with this , my problem is a have to double tap the button to execute to complete the task.
var _formKey = GlobalKey<FormState>();
var validate;
String validateNumber(String value){
if (value.isEmpty) {
return 'Please enter number';
}if(validate == true){
return "Phone number already exists";
}
return null;
}
addPhoneNumber(phoneNumber) async{
var exist = await db.checkPhoneNumber(phoneNumber); //my query to firestore so far i have no problem with this.
if(exist == true){
validate = true;
print(validate);
}
if(exist == false){
validate = false;
Navigator.of(context).push(_verifyPhone(_phoneNumber.text));
await db.addPhoneNumber(phoneNumber);
}
} //my function to detect if the number exists
#override
Widget build(BuildContext context) {
_get1();
return WillPopScope(
onWillPop: () async {
Navigator.pop(context);
return true;
},
child: Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Form(
key:_formKey,
child:Expanded(
child:Scrollbar(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
TextFormField(
controller: _phoneNumber,
validator: validateNumber, //my validator
),
],
),
),
),
),
FlatButton(
onTap: (){
if(_formKey.currentState.validate()){
addPhoneNumber(phoneNumber)
}
},
)
],
),
),
);
}
}
You need to call the validate() method on your form state. Look here for API reference.
This is not invoked automatically by the framework for you. You need to invoke it inside the onTap() method of your button. Add there a line _formKey.currentState.validate().
When this method is invoked then the form calls the validator for each form field.
---------------------------UPDATE---------------------------------------
Ok, #ppdy, you are one step closer now. It doesn't work yet because your validator only checks if the value is not empty. Just look carefully at what happens when you push the button. It runs the validateNumber and if the value is empty the framework will render your validate message. Then if the value is not empty you run the addPhoneNumber method, but you run it yourself. This is important, notice that it is not get run as part of the text form field validator property function. So you need to handle the output of the await db.checkPhoneNumber(phoneNumber); yourself and render the validation red message in the text form field if the check is false.
For this please note first that the TextFormField class has the decoration property. Type of this property is the InputDecoration. Please read the documentation of this class here. So by setting the errorText property of the decoration you will be able to add the red validation message to the form field manually.
Try to think it all over, play with it, stick this all together and you will have what you want :)

Is there a way to set the inital value of textformfield with data from cloud firestore without the displayed data being enclosed in braces?

I'm retrieving data from firestore and setting the inital value of the textformfield with this data. I am able to get the data, However the data displayed is enclosed in braces and have tried to use regex patterns to work with this but to no avail. Any help will be appreciated
I have tried using regex expression to work around this but nothings working so far.
Widget _nextOfKinFirstName() {
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('farmer_profile').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snap) {
var name = snap.data.documents.map((DocumentSnapshot docs) {
return docs['first_name'];
}).toString();
return TextFormField(
initialValue: name,
validator: (name) {
Pattern pattern = r'^[a-zA-Z]+$';
RegExp exp = new RegExp(pattern);
if (!exp.hasMatch(name))
return 'enter name';
else
return null;
},
);
},
);
}
i expect the output to be a string value not enclosed in braces.
This is the output i have
output on textformfield
while this is the database am testing how to implement with.
simple database i'm trying this with

Categories

Resources