I'm trying to create a Dropdown from Firestore in Flutter. So this is what I have:
So what I would like to do is to have a Select Dropdown or even a Search Box which displays the field nombre from the document and depending on the selected name save the Document ID into a Variable.
Basically the Dropdown should show as Lable's the Nombre and save the DocumentID if it could be a combination of both (Searchable Dropdown) would be even better.
Any Ideas?
Kind Regards.
This question has already been answered in the past.
new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('categories').snapshots(),
builder: (context, snapshot){
if (!snapshot.hasData) return const Center(
child: const CupertinoActivityIndicator(),
);
var length = snapshot.data.documents.length;
DocumentSnapshot ds = snapshot.data.documents[length - 1];
_queryCat = snapshot.data.documents;
return new Container(
padding: EdgeInsets.only(bottom: 16.0),
width: screenSize.width*0.9,
child: new Row(
children: <Widget>[
new Expanded(
flex: 2,
child: new Container(
padding: EdgeInsets.fromLTRB(12.0,10.0,10.0,10.0),
child: new Text("Category",style: textStyleBlueBold,),
)
),
new Expanded(
flex: 4,
child:new InputDecorator(
decoration: const InputDecoration(
//labelText: 'Activity',
hintText: 'Choose an category',
hintStyle: TextStyle(
color: primaryColor,
fontSize: 16.0,
fontFamily: "OpenSans",
fontWeight: FontWeight.normal,
),
),
isEmpty: _category == null,
child: new DropdownButton(
value: _category,
isDense: true,
onChanged: (String newValue) {
setState(() {
_category = newValue;
dropDown = false;
print(_category);
});
},
items: snapshot.data.documents.map((DocumentSnapshot document) {
return new DropdownMenuItem<String>(
value: document.data['title'],
child: new Container(
decoration: new BoxDecoration(
color: primaryColor,
borderRadius: new BorderRadius.circular(5.0)
),
height: 100.0,
padding: EdgeInsets.fromLTRB(10.0, 2.0, 10.0, 0.0),
//color: primaryColor,
child: new Text(document.data['title'],style: textStyle),
)
);
}).toList(),
),
),
),
],
),
);
}
);
Souce: How to bind a Firestore documents list to a Dropdown menu in Flutter?
I have a problem querying my geolocation data from my database in Cloud Firestore. I went through the documentation on Youtube and came to the conclusion that it will work best for me when i save the geolocation data in subcollections.
Here is my databse structure:
And if you go into one of the documents in the subcollection:
The database itself has a collection called "tourguides", with each document containing basic info like the name of the tour and the region where the tour is (both are Strings). Each of the documents then have a subcollection called "locations", where each document has the Strings "Name" and "ID" and also a geopoint with latitude and longitude data.
The documents from the "Tourguides" collection are shown in a ListView. Whenever i tap on one of the entries, a map shall open where all the markers from the respective subcollection are shown.
Here is my ListView Builder:
#override
void initState() {
super.initState();
_pointsofinterest = Firestore.instance.collection('tourguides').document('sydney_downtown_guide').col lection('locations').orderBy('name').snapshots();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<QuerySnapshot>(
stream: _pointsofinterest,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return new ListView(
children:
snapshot.data.documents.map((DocumentSnapshot document) {
return InkWell(
child: new ListTile(
title: new Text(document['name']),
subtitle: new Text(document['region']),
onTap: () {
return TourMap(
documents: snapshot.data.documents,
initialPosition: const LatLng(-33.868210, 151.208391),
mapController: _mapController,
);
},
),
);
}).toList(),
);
}
},
),
);
}
I put my map into a StatlessWidget (I am not sure. Maybe this has to be a StatefulWidget?):
class TourMap extends StatelessWidget {
const TourMap({
Key key,
#required this.documents,
#required this.initialPosition,
#required this.mapController,
}) : super(key: key);
final List<DocumentSnapshot> documents;
final LatLng initialPosition;
final Completer<GoogleMapController> mapController;
#override
Widget build(BuildContext context) {
return GoogleMap(
initialCameraPosition: CameraPosition(
target: initialPosition,
zoom: 12,
),
markers: documents
.map((document) => Marker(
markerId: MarkerId(document['placeId']),
icon: BitmapDescriptor.defaultMarker,
position: LatLng(
document['geolocation'].latitude,
document['geolocation'].longitude,
),
infoWindow: InfoWindow(
title: document['location_name'],
),
))
.toSet(),
onMapCreated: (mapController) {
this.mapController.complete(mapController);
},
);
}}
Now i dont exactly know how to set up the query in my OnTap function. The Firestore documentation showed that i always have to refer to specfic documents if i go down the collections from my database.
For example (collection/document/collecion). But in my query, the "document" in the middle of the path is always different, depending on which tourguide the user clicks.
Any ideas on that? Looking Forward to your replies!
UPDATE: I slightly configured my database structure! I now use two seperate databases. One database holds information about the available tourguides (just two Strings currently: Name and Region) and the other stores the actual individual Locations.
I now use where-queries to get the correct locations based on the tourguide´s Name they´re belonging to.
The query itself works on the OnTap function now:
return new ListView(
children:
snapshot.data.documents.map((DocumentSnapshot document) {
return InkWell(
child: new ListTile(
title: new Text(document['name']),
subtitle: new Text(document['region']),
onTap: () {
Firestore.instance.collection('locations').where(
"toActivity",
isEqualTo: document['name'],
)
.snapshots()
.listen((data) =>
data.documents.forEach((doc) => print(doc["location_name"])));
},
),
);
}).toList(),
);
The database structure:
The correct entries are printed into the console if i tap on one of the entries in the ListView. But i will need a Google Map to pop up that shows the appropriate markers based on the "geolocation" values from the database.
Bro, I did. I can retrieve it by two ways.
1. manually by using simple 'initState'.
2. second by using provider (but by using the second method, i have not succeed to show the marker, yet). Hope can help you, although it was long time ago. Here is mine by using 'initState':
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:provider/provider.dart';
import 'package:visitmalang/provider/aktivitas_provider.dart';
import 'package:visitmalang/ui/home/beranda/aktivitas/profil_agen_wisata.dart';
import 'package:visitmalang/ui/widget/textcustom.dart';
class MapAktivitas extends StatefulWidget {
#override
_MapAktivitasState createState() => _MapAktivitasState();
}
class _MapAktivitasState extends State<MapAktivitas> {
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
GoogleMapController mapController;
bool mapToggle = false;
bool geraiToggle = false;
var currentLocation;
var clients = [];
#override
void initState() {
// TODO: implement initState
super.initState();
Geolocator().getCurrentPosition().then((lokasiSekarang) {
setState(() {
currentLocation = lokasiSekarang;
mapToggle = true;
populateClients();
});
});
}
populateClients() {
clients = [];
Firestore.instance.collection('trail').getDocuments().then((docs) {
if (docs.documents.isNotEmpty) {
setState(() {
geraiToggle = true;
});
for (int i = 0; i < docs.documents.length; i++) {
clients.add(docs.documents[i].data);
initMarker(docs.documents[i].data, docs.documents[i].documentID);
}
}
});
}
void initMarker(request, requestId) {
var markerIdVal = requestId;
final MarkerId markerId = MarkerId(markerIdVal);
final Marker marker = Marker(
markerId: markerId,
position: LatLng(
request['koordinat'].latitude, request['koordinat'].longitude),
infoWindow: InfoWindow(title: request['nama']));
setState(() {
markers[markerId] = marker;
});
}
Widget clientCard(client) {
return Padding(
padding: const EdgeInsets.only(left: 8.0, top: 8.0),
child: InkWell(
onTap: () {
zoomInMarker(client);
},
child: Stack(
alignment: FractionalOffset(0.5, 0.94),
children: <Widget>[
Material(
elevation: 4.0,
borderRadius: BorderRadius.circular(10.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.white,
),
height: 108,
width: 200,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
//
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
bottomLeft: Radius.circular(10.0)),
child: Container(
width: 96,
height: 108,
child: Image.asset(
'assets/trail.png',
fit: BoxFit.cover,
),
),
),
SizedBox(
width: 4,
),
Stack(
alignment: FractionalOffset(0.5, 0.9),
children: <Widget>[
Container(
width: 100,
child: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0),
child: Container(
alignment: Alignment.center,
child: textCustom(client['nama'],
Colors.black87, 14, 'Montserrat'),
),
),
],
),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: InkWell(
onTap: () => Navigator.of(context).push(
CupertinoPageRoute(
builder: (BuildContext context) =>
ProfilAgenWisata(
nama: client['nama'],
deskripsi: client['deskripsi'],
website: client['website'],
email: client['email'],
noTelepon: client['noTelepon'],
whatsApp: client['whatsApp'],
alamat: client['alamat'],
fasilitas: client['fasilitas'],
))),
child: Container(
alignment: Alignment.center,
color: Color(0xFFDB5C48),
height: 40,
width: 88,
child: textCustom(
'Detail', Colors.white, 14, 'Montserrat'),
),
),
)
],
),
],
),
),
),
],
)),
);
}
zoomInMarker(client) {
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(
client['koordinat'].latitude, client['koordinat'].longitude),
zoom: 16.0,
bearing: 19.0,
tilt: 15.0),
),
);
}
#override
Widget build(BuildContext context) {
// AktivitasNotifier aktivitasNotifier = Provider.of<AktivitasNotifier>(context);
return Scaffold(
appBar: AppBar(
title: textCustom('Ngetrail', Colors.black87, 18, 'Montserrat'),
centerTitle: true,
elevation: 0.0,
backgroundColor: Colors.transparent.withOpacity(0.0),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios, color: Colors.black87),
onPressed: (){Navigator.pop(context);},),
),
body: Stack(
children: <Widget>[
Column(
children: <Widget>[
Container(
width: double.infinity,
height: MediaQuery.of(context).size.height - 80,
child: mapToggle
? GoogleMap(
myLocationEnabled: true,
myLocationButtonEnabled: true,
markers: Set<Marker>.of(markers.values),
compassEnabled: false,
zoomControlsEnabled: false,
mapType: MapType.normal,
initialCameraPosition: CameraPosition(
target: LatLng(currentLocation.latitude,
currentLocation.longitude),
zoom: 15),
onMapCreated: (controller) {
setState(() {
mapController = controller;
});
},
)
: Center(
child: textCustom(
'Loading...', Colors.black87, 20, 'Hind')),
),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
height: 140.0,
width: MediaQuery.of(context).size.width,
child: geraiToggle
? ListView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.all(8.0),
children: clients.map((element) {
return clientCard(element);
}).toList(),
)
: Container(),
),
SizedBox(
height: 56.0,
)
],
)
],
));
}
}
Here is the second method, by using provider.
First, you have to decide the model (just focus on 'koordinat'):
class ModelAktivitas {
String idAktivitas;
var koordinat;
String nama;
String deskripsi;
String alamat;
String email;
String noTelepon;
String website;
String gambarUtama;
List galeri;
List fasilitas;
ModelAktivitas.fromMap(Map<String, dynamic> data) {
idAktivitas = data['idAktivitas'];
koordinat = data['koordinat'];
nama = data['nama'];
deskripsi = data['deskripsi'];
noTelepon = data['nomorTelepon'];
galeri = data['galeri'];
fasilitas = data['fasilitas'];
alamat = data['alamat'];
email = data['alamat'];
gambarUtama = data['gambarUtama'];
website = data['website'];
}
}
second, make provider for it:
import 'dart:collection';
import 'package:flutter/cupertino.dart';
import 'package:visitmalang/models/aktivitas_model.dart';
class AktivitasNotifier with ChangeNotifier {
List<ModelAktivitas> _listAktivitas = [];
ModelAktivitas _detailAktivitas;
UnmodifiableListView<ModelAktivitas> get listAktivitas =>
UnmodifiableListView(_listAktivitas);
ModelAktivitas get detailAktivitas => _detailAktivitas;
set listAktivitas(List<ModelAktivitas> listAktivitas) {
_listAktivitas = listAktivitas;
notifyListeners();
}
set detailAktivitas(ModelAktivitas aktivitas) {
_detailAktivitas = aktivitas;
notifyListeners();
}
}
After that, add the "get" from your firestore services:
getListAktivitas(AktivitasNotifier aktivitasNotifier) async {
QuerySnapshot snapshot =
await Firestore.instance.collection('trail').getDocuments();
List<ModelAktivitas> _listAktivitas = [];
snapshot.documents.forEach((doc) {
ModelAktivitas modelAktivitas = ModelAktivitas.fromMap(doc.data);
_listAktivitas.add(modelAktivitas);
});
aktivitasNotifier.listAktivitas = _listAktivitas;
}
then, the last step stream it to your UI code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:provider/provider.dart';
import 'package:visitmalang/provider/aktivitas_provider.dart';
import 'package:visitmalang/ui/home/beranda/aktivitas/profil_agen_wisata.dart';
import 'package:visitmalang/ui/widget/textcustom.dart';
import 'package:visitmalang/service/user_service.dart';
class MapAktivitasTandingan extends StatefulWidget {
#override
_MapAktivitasTandinganState createState() => _MapAktivitasTandinganState();
}
class _MapAktivitasTandinganState extends State<MapAktivitasTandingan> {
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
GoogleMapController mapController;
bool mapToggle = false;
bool geraiToggle = false;
var currentLocation;
#override
void initState() {
// TODO: implement initState
super.initState();
Geolocator().getCurrentPosition().then((lokasiSekarang) {
setState(() {
currentLocation = lokasiSekarang;
mapToggle = true;
});
});
AktivitasNotifier aktivitasNotifier =
Provider.of<AktivitasNotifier>(context, listen: false);
getListAktivitas(aktivitasNotifier);
}
#override
Widget build(BuildContext context) {
AktivitasNotifier aktivitasNotifier =
Provider.of<AktivitasNotifier>(context);
return Scaffold(
appBar: AppBar(
title: textCustom('Ngetrail', Colors.black87, 18, 'Montserrat'),
centerTitle: true,
elevation: 0.0,
backgroundColor: Colors.transparent.withOpacity(0.0),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios, color: Colors.black87),
onPressed: () {
Navigator.pop(context);
},
),
),
body: Stack(
children: <Widget>[
Column(
children: <Widget>[
Container(
width: double.infinity,
height: MediaQuery.of(context).size.height - 80,
child: mapToggle
? GoogleMap(
myLocationEnabled: true,
myLocationButtonEnabled: true,
markers: {
},
compassEnabled: false,
zoomControlsEnabled: false,
mapType: MapType.normal,
initialCameraPosition: CameraPosition(
target: LatLng(currentLocation.latitude,
currentLocation.longitude),
zoom: 15),
onMapCreated: (controller) {
setState(() {
mapController = controller;
});
},
)
: Center(
child: textCustom(
'Loading...', Colors.black87, 20, 'Hind')),
),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
height: 140.0,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: aktivitasNotifier.listAktivitas.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(left: 8.0, top: 8.0),
child: InkWell(
onTap: () {
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(
aktivitasNotifier
.listAktivitas[index]
.koordinat
.latitude,
aktivitasNotifier
.listAktivitas[index]
.koordinat
.longitude),
zoom: 16.0,
bearing: 19.0,
tilt: 15.0),
),
);
},
child: Stack(
alignment: FractionalOffset(0.5, 0.94),
children: <Widget>[
Material(
elevation: 4.0,
borderRadius: BorderRadius.circular(10.0),
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(10.0),
color: Colors.white,
),
height: 108,
width: 200,
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
//
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
bottomLeft:
Radius.circular(10.0)),
child: Container(
width: 96,
height: 108,
child: Image.asset(
'assets/trail.png',
fit: BoxFit.cover,
),
),
),
SizedBox(
width: 4,
),
Stack(
alignment:
FractionalOffset(0.5, 0.9),
children: <Widget>[
Container(
width: 100,
child: Padding(
padding:
const EdgeInsets.only(
top: 8.0),
child: Column(
children: <Widget>[
Padding(
padding:
const EdgeInsets
.symmetric(
horizontal:
8.0),
child: Container(
alignment:
Alignment.center,
child: textCustom(
aktivitasNotifier
.listAktivitas[
index]
.nama,
Colors.black87,
14,
'Montserrat'),
),
),
],
),
),
),
ClipRRect(
borderRadius:
BorderRadius.circular(10),
child: InkWell(
onTap: () => Navigator.of(
context)
.push(CupertinoPageRoute(
builder: (BuildContext
context) =>
ProfilAgenWisata(
nama: aktivitasNotifier
.listAktivitas[
index]
.nama,
website: aktivitasNotifier
.listAktivitas[
index]
.website,
noTelepon: aktivitasNotifier
.listAktivitas[
index]
.noTelepon,
email: aktivitasNotifier
.listAktivitas[
index]
.email,
alamat: aktivitasNotifier
.listAktivitas[
index]
.alamat,
deskripsi: aktivitasNotifier
.listAktivitas[
index]
.deskripsi,
))),
child: Container(
alignment: Alignment.center,
color: Color(0xFFDB5C48),
height: 40,
width: 88,
child: textCustom(
'Detail',
Colors.white,
14,
'Montserrat'),
),
),
)
],
),
],
),
),
),
],
)),
);
},
)),
SizedBox(
height: 56.0,
)
],
)
],
));
}
}
I want to build a view to show some events inside a listview in my app like this:
I have these two tables:
Users
Events
But I don't know how do a "inner join" between the tables USERS and EVENTS...
I tried this:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:project/Methods.dart';
import 'package:project/Views/CadastroUsuario.dart';
import 'dart:math';
class EventClass{
String owner;
String description;
String city;
String state;
String place;
}
class EventsListing extends StatefulWidget {
#override
EventsListingState createState() => new EventsListingState();
}
class EventsListingState extends State<EventsListing> {
List<EventClass> events;
#override
void initState() {
super.initState();
events = new List<EventClass>();
}
void buildEventClass(DocumentSnapshot doc) async {
EventClass oneEvent = new EventClass();
DocumentReference document = Firestore.instance.collection("users").document(doc["userid"]);
document.get().then((DocumentSnapshot snapshot){
oneEvent.owner = snapshot["name"].toString();
});
oneEvent.description = doc["description"];
oneEvent.place = doc["place"];
oneEvent.city = doc["city"];
oneEvent.state = doc["state"];
events.add(oneEvent);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Events'),
),
body: new StreamBuilder(
stream: Firestore.instance.collection("events").snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (snapshot.connectionState == ConnectionState.waiting)
return Text("Loading...");
return new ListView(
padding: EdgeInsets.only(left: 5.0, right: 5.0, top: 5.0),
children: snapshot.data.documents.map((document){
buildEventClass(document);
return events.length == 0 ? new Card() : item(events.last);
}).toList()
);
},
),
floatingActionButton: new FloatingActionButton(
tooltip: 'New',
child: new Icon(Icons.add),
onPressed: () async {
Navigation navigation = new Navigation();
navigation.navigaTo(context, CadastroUsuario());
},
),
);
}
Widget item(EventClass oneEvent) {
return new Card(
elevation: 4.0,
child: new Column(
children: <Widget>[
new Row(
children: <Widget>[
new Column(
children: <Widget>[
new Text(oneEvent.owner.toString(),
style: TextStyle(fontSize: 20.0),
overflow: TextOverflow.ellipsis,),
],
),
new Column(
children: <Widget>[
],
)
],
),
new Container(
color: Colors.blue,
height: 150.0,
),
new Row(
children: <Widget>[
new Row(
children: <Widget>[
new Text(oneEvent.description.toString(),
style: TextStyle(fontSize: 20.0),
overflow: TextOverflow.ellipsis,),
],
),
new Row(
children: <Widget>[
new Text(oneEvent.place.toString(),
style: TextStyle(color: Colors.grey[350]),
overflow: TextOverflow.ellipsis,),
],
),
new Row(
children: <Widget>[
new Text(oneEvent.city.toString() +' - '+ oneEvent.state.toString(),
style: TextStyle(color: Colors.grey[350]),
overflow: TextOverflow.ellipsis,),
],
)
]
)
],
)
);
}
}
But every time that I try to show these events I get this exception
Exception has occurred.
PlatformException(error, Invalid document reference. Document references must have an even number of segments, but users has 1, null)
What I'm doing wrong? How I can do a "inner join" between thesse tables and show the events?
I'm using the Firebase Firestore.
PS: I already know that Firestore is a noSQL database and have no "joins", but I want to do something like a join.
As I was telling in the coments Firestore does not support multi collection querys cause its no relational DB. If you need to access multiple collections you would manage querys independently.
This is how I usually get related collections data (Sorry this is JS code but I dont know DART):
var data = {};
//First you get users data
DocumentReference document = Firestore.collection("users")
document.get().then((snapshot) => {
//In this case I will store data in some object, so I can add events as an array for a key in each user object
snapshot.forEach((userDoc) => {
var userDocData = userDoc.data()
if (data[userDoc.id] == undefined) {
data[userDoc.id] = userDocData
}
})
//So in this moment data object contains users, now fill users with events data
//In this var you count how many async events have been downloaded, with results or not.
var countEvents = 0
Object.keys(data).forEach((userDocId) => {
//Here Im creating another query to get all events for each user
SnapshotReference eventsForCurrentUserRef = Firestore.collection("events").where("userId", "==", userDocId)
eventsForCurrentUserRef.get.then((eventsForUserSnapshot) => {
//Count events
countEvents++
eventsForUserSnapshot.forEach((eventDoc) => {
var eventDocData = eventDoc.data()
//Check if array exists, if not create it
if (data[eventDocData.userId].events == undefined) {
data[eventDocData.userId].events = []
}
data[eventDocData.userId].events.push(eventDocData)
})
if(countEvents == Object.keys(data).length){
//Lookup for events in every user has finished
}
})
})
})
I am trying to change the query according to the selected community.
When you select the community you must show the content of this community.
I have found a solution but I do not think it is the right one, because the application has 39 countries.
Those 39 require you to have a query for each one and there are many lines of code.
I hope there is some better solution than what I found.
GIF APP
- The error that appears is because there is no other country.
SearchClub.dart
This is the function that returns a query related to the countries.
I want to use one and not make several queries for each country.
searchClubs(TextEditingController countryChanged) {
var widgetFireUpdate;
setState(() {
if(countryChanged.text == 'SPAIN') {
widgetFireUpdate = new FirebaseAnimatedList(
query: FirebaseDatabase.instance.reference().child(widget.player.platform).child("CLUB").orderByChild('country').equalTo(countryChanged.text),
sort: (a, b) => a.value['createdDate'].compareTo(b.value['createdDate']),
reverse: true,
shrinkWrap: true,
defaultChild: new CircularProgressIndicator(),
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return new StreamBuilder<Event>(
stream: itemRef2.orderByKey().onValue,
builder: (context, AsyncSnapshot<Event> snapshot2){
if(snapshot2.hasData) {
try {
return new Container(
decoration: new BoxDecoration(
color: Colors.grey[300],
),
child: new ListTile(
leading: snapshot.value['logoURL'].toString().indexOf('images/assets/logo_notfound.png') == -1 ? new CachedNetworkImage(imageUrl: snapshot.value['logoURL'], width: MediaQuery.of(context).size.width/8) : new Image.asset(snapshot.value['logoURL'], width: MediaQuery.of(context).size.width/8),
title: new Text(snapshot.value['name'].toUpperCase(), style: new TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: MediaQuery.of(context).size.width/30)),
subtitle: new RichText(
text: new TextSpan(
children: <TextSpan>[
new TextSpan(text: "CAPITÁN:", style: new TextStyle(color: Colors.black, fontSize: MediaQuery.of(context).size.width/35, fontWeight: FontWeight.bold)),
new TextSpan(text: " ${snapshot.value['captain'].toUpperCase()}", style: new TextStyle(color: Colors.black, fontSize: MediaQuery.of(context).size.width/35)),
]
),
),
),
);
}catch(e) {
return new Container();
}
} else if(snapshot2.hasError){
return new Container();
} else {
return new Container(
child: new Center(
child: new CircularProgressIndicator(
backgroundColor: Colors.red,
),
),
);
}
},
);
},
);
} else if(countryChanged.text == 'BRAZIL') {
widgetFireUpdate = new FirebaseAnimatedList(
query: FirebaseDatabase.instance.reference().child(widget.player.platform).child("CLUB").orderByChild('country').equalTo(countryChanged.text),
sort: (a, b) => a.value['createdDate'].compareTo(b.value['createdDate']),
reverse: true,
shrinkWrap: true,
defaultChild: new CircularProgressIndicator(),
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return new StreamBuilder<Event>(
stream: itemRef2.orderByKey().onValue,
builder: (context, AsyncSnapshot<Event> snapshot2){
if(snapshot2.hasData) {
try {
return new Container(
decoration: new BoxDecoration(
color: Colors.grey[300],
),
child: new ListTile(
leading: snapshot.value['logoURL'].toString().indexOf('images/assets/logo_notfound.png') == -1 ? new CachedNetworkImage(imageUrl: snapshot.value['logoURL'], width: MediaQuery.of(context).size.width/8) : new Image.asset(snapshot.value['logoURL'], width: MediaQuery.of(context).size.width/8),
title: new Text(snapshot.value['name'].toUpperCase(), style: new TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: MediaQuery.of(context).size.width/30)),
subtitle: new RichText(
text: new TextSpan(
children: <TextSpan>[
new TextSpan(text: "CAPITÁN:", style: new TextStyle(color: Colors.black, fontSize: MediaQuery.of(context).size.width/35, fontWeight: FontWeight.bold)),
new TextSpan(text: " ${snapshot.value['captain'].toUpperCase()}", style: new TextStyle(color: Colors.black, fontSize: MediaQuery.of(context).size.width/35)),
]
),
),
),
);
}catch(e) {
return new Container();
}
} else if(snapshot2.hasError){
return new Container();
} else {
return new Container(
child: new Center(
child: new CircularProgressIndicator(
backgroundColor: Colors.red,
),
),
);
}
},
);
},
);
}
});
return widgetFireUpdate;
}
// OPEN LIST COMMUNITY
Widget _buildBottomPicker() {
final FixedExtentScrollController scrollController = new FixedExtentScrollController();
return new Container(
height: MediaQuery.of(context).size.height/3.5,
color: CupertinoColors.white,
child: new DefaultTextStyle(
style: const TextStyle(
color: CupertinoColors.black,
fontSize: 22.0,
),
child: new SafeArea(
child: new CupertinoPicker(
scrollController: scrollController,
itemExtent: MediaQuery.of(context).size.height/15,
magnification: 0.7,
diameterRatio: 0.5,
backgroundColor: CupertinoColors.white,
onSelectedItemChanged: (int index) {
setState(() {
_comunidad.text = _comunidades[index];
_imgComunidad = _imgComunidades[index];
});
},
children: new List<Widget>.generate(_comunidades.length, (int index) {
return new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(_comunidades[index]),
],
);
}),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
appBar: searchBar.build(context),
body: new Container(
color: widget.themeConsole,
child: new Column(
children: <Widget>[
new Card(
elevation: 0.0,
color: Colors.grey[50],
child: new Container(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Container(
width: MediaQuery.of(context).size.width/1.35,
child: new TextFormField(
controller: _comunidad,
style: new TextStyle(color: Colors.white),
enabled: false,
decoration: new InputDecoration(
labelText: 'Community:',
labelStyle: new TextStyle(color: Colors.white),
icon: new Image.asset(_imgComunidad, width: 24.0),
filled: true,
fillColor: Colors.grey[800],
),
validator: (String value){
player.country = value;
},
),
),
new IconButton(
icon: new Icon(Icons.flag, color: Colors.grey[800], size: 30.0,),
color: Colors.black,
onPressed: ()async {
await showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return _buildBottomPicker();
},
);
},
),
],
),
),
),
new Flexible(child: searchClubs(_comunidad))
],
)
),
);
}
SearchClub Complete: https://pastebin.com/zbeU6M1u
From what I have understood, you are using firebase real time database where you have child name as country and have data inside that node. You want to make queries in such a way that when you select a country, that particular query should be made like when selecting Argentina everything inside Argentina in your database should be called.
Store value of country names in a list and make a string for calling countries.
String country="";
List<String> country_name=["Argentina","Brazil","Spain"....];
Now on press function can be like this-
onPressed: () {
setState(() {
country=country_name[1];//example
});
country_call();
}
This will help us when we change the country name.
Lastly make changes in your firebase reference-
Future<void> country_call()async{
final FirebaseDatabase database = FirebaseDatabase().instance();
setState(() {
itemRef = database.reference().child(country);
itemRef.onChildAdded.listen(_onEntryAdded);
itemRef.onChildChanged.listen(_onEntryChanged);
});
}
By changing you can call different queries without writing for 39 different countries. If you are using a list view to show our data, make sure to empty it in country_call function. That can be done by simply equating it to null list("[]").
I was searching for something similar but could not find anything on the website. I used this approach to fix my problem. I hope it was helpful for you too.