Flutter how to update list in firebase document - flutter

I am trying to update a field on firebase from my flutter app but it doesn't work.
activities is an array, 0 a map.
I want to update 'daysdone' with 'val' from my flutter app.
ChipsChoice<String>.multiple(
value: activities
.elementAt(i)
.daylistdone,
onChanged: (val) =>
FirebaseFirestore.instance
.collection(
widget.user.user.uid)
.doc(documentName)
.set({
"activities." + i.toString(): {
'title': activities
.elementAt(i)
.title,
'days': activities
.elementAt(i)
.daylist,
'daysdone': val,
'daysbool': activities
.elementAt(i)
.daybool,
// 'daysdonebool': myData2bool2,
'notification': activities
.elementAt(i)
.notification,
'time':
activities.elementAt(i).time
},
}),
choiceItems: C2Choice.listFrom<
String, String>(
source: activities
.elementAt(i)
.daylist,
value: (i, v) => v,
label: (i, v) => v,
),
),
It gives me this result
What can I do to fix this issue?

The first image is a list of maps. The only way you can update the field daysdone is by accessing the entire list, and then traversing through the list to your desired map position (in the first image case, this should be position 0), then editing that particular map. After doing this, you have to update the entire activities field:
FirebaseFirestore.instance.collection('collection').doc('Mydocument').update({'activities': newEditedList})
I would personally recommend a complete re-structure of your database-collection. Like the following:
Step 1
Step 2: Each user has sub-collection: Activities
Step 3: Each activity can now easily be accessed
To access a user's activities:
var result
= await FirebaseFirestore.instance.collection('MyUsers').doc(widget.user.user.uid).collection('Activities').limit(20).get(GetOptions(source:Source.server));
If you want to update color field:
// Color
FirebaseFirestore.instance.collection('MyUsers').doc(widget.user.user.uid).update({'color':'red'});
If you want to update an activity :
//days done
FirebaseFirestore.instance.collection('MyUsers').doc(widget.user.user.uid).collection('Activities').doc('the_activityId').update({'daysdone': "value"});

Related

How to create more children on Firebase Realtime Database

I want to create more children on the Firebase Realtime Database.
Desired effect (example): [
What I have:
MyButton(
label: "Create Ride",
onTap: () {
ref
.child('Database')
.push()
.child('Title')
.set(_titleController.text)//the Title Controller is just the
//data you type in
.asStream();
_titleController.clear();
}),
I can't find a sample anywhere and I don't know how to write it so that there's more than just a title.
If you want to write multiple values under the new child, you can do:
ref
.child('Database')
.push()
.set({
'Title': _titleController.text,
'land': 'Germany',
'stadt': 'Berlin'
})
Also see the example in the Firebase documentation on writing data.

How can I restrict user to select a item only once from DropdownMenuItem in Flutter?

Suppose there is 2 item in my DropdownList. If user choose 1st item initially , next time only 2nd item should available to select( i.e.1st item non-clickable).
child: DropdownButton<Datum>(
enabled= enabled_Item,
value: _selectedTest,
hint: Text(""),
//underline: SizedBox(),
isExpanded: true,
items: data
.map(
(Datum data) => DropdownMenuItem<Datum>(
child: Text("${data.testName}"),
enabled: data.testId != _selectedTest,
value: data,
))
.toList()
.cast<DropdownMenuItem<Datum>>(),
onChanged: (value) {
print(
"This is the TestName : ${value!.testName}");
print(
"This is the EncTestId which is need to get Test Fee : ${value.testId}");
setState(() {
encTestId = value.testId; // == SELCTED TEST from drop down 'encTestId' needed for to get Test Fee
testName = value.testName;
_selectedTest = value;
});
//GetTestByLab(value!.encPartnerId); // passing encid to my next API function
}),
You can't remove the currently selected / default value from the list of selectable items. If you do, this will happen:
https://stackoverflow.com/a/61425939/3410660
TL;DR
You have to disable the currently selected / default value rather than completely removing it
So a workaround is to set the value of enabled (boolean) to each item of the DropdownButton. Like this:
child: DropdownButton<Datum>(
value: _selectedTest,
hint: Text(""),
isExpanded: true,
items: data.map((Datum data) => DropdownMenuItem<Datum>(
child: Text("${data.testName}"),
enabled: data != _selectedTest,
value: data,
)).toList().cast<DropdownMenuItem<Datum>>(),
I'm assuming Datum data is a Model with it's hashCode and bool operator == overriden to make conditionals like this data != _selectedTest posible.
There are different ways to solve this issues, you can create a list of integers and add the clicked element's index to it, and check if the clicked index already exists in that list, then do not perform the operation you want, else you add the current index and execute the code.
Second option:
you might be storing the clicked data to any list or model, check if the current value already exists there, but this way you cannot click same values even the list index is different.
hope this will help you out.

How to update the data permanently in my flutter project?

I have made an app, that basically suggests some music artists and some of their top songs to the user. I want to add a feature that would allow the user to mark some songs as their favorite and I also want to show all the marked as favorite songs on a separate screen. In my flutter project, I have created a class Data in a file "data.dart" which has all the data that all the screens use. In "data.dart", I have a list of Map<String, Object> that has all the songs and each Map has a 'favorite' key which is initially set to false.
var allSongs = [
...
{
'url':
'https://open.spotify.com/track/3E6iea9uEmB7gRru4lyP6h?si=b062300e24cf47d8',
'name': 'Stop this train',
'time': '4:45',
'image':
'https://imagesvc.meredithcorp.io/v3/mm/image?url=https%3A%2F%2Fstatic.onecms.io%2Fwp-content%2Fuploads%2Fsites%2F20%2F2017%2F01%2Fjohn-mayer-wave-one-2000.jpg',
'id': 'jm',
'favorite': false,
},
...
];
I have added a button below each song Widget that is supposed to allow the user to mark the song as their favorite. I call addToFavs(val) (a function) that is called whenever the button is pressed.
InkWell(
onTap: () {
addToFavs(val);
},
child: Icon(
Icons.favorite,
color: color,
size: 30,
),
),
In addToFavs(), I want to access the list allSongs in Data class, and I want to change the value of 'favorite' key for the specific song that user has selected.
This is how my addToFavs() function looks like
void addToFavs(Map<String, Object> info) {
setState(() {
//here I am finding the index of the song that the user wants to mark as favorite
int index = Data().allSongs.indexWhere((element) {
return info['name'] == element['name'];
});
if (Data().allSongs[index]['favorite'] == false) {
Data().allSongs[index]['favorite'] = true;
color = Colors.red;
} else {
Data().allSongs[index]['favorite'] = false;
color = Colors.white;
}
});
}
And then when I go to my favorites screen, I finding all the Maps that have favorite key as true in allSong list.
var favorites = Data().allSongs.where((val) {
return val['favorite'] == true;
});
but I don't see the songs that I have marked as favorite. I think the data is being temporarily changed in the Data class and when I go to favorite screen the data is set to what it was before.
How do I fix this issue?
I think when you call Data(), a new instance of Data is returned. Instead of doing this way, you can declare your allSongs variable static. This way you can call it like this : Data.allSongs (Notice Data without parenthesis).
static var allSongs = [
...
{
'url':
'https://open.spotify.com/track/3E6iea9uEmB7gRru4lyP6h?si=b062300e24cf47d8',
'name': 'Stop this train',
'time': '4:45',
'image':
'https://imagesvc.meredithcorp.io/v3/mm/image?url=https%3A%2F%2Fstatic.onecms.io%2Fwp-content%2Fuploads%2Fsites%2F20%2F2017%2F01%2Fjohn-mayer-wave-one-2000.jpg',
'id': 'jm',
'favorite': false,
},
...
];
But unless you store your data in a database or a shared_preference, changes made to your data will be lost on next launch of the app.

Group radio button in listView

How to use group button in listView ? In each row, it has two radio button.
The problem now is if I select one of the radio button , the radio button not showing it is selected.
int value;
Map<int, bool> answers = {};
String _radioValue;
String choice;
int count = 0;
...item['questions']
.asMap()
.entries
.map((items) {
count++;
return TableRow(children: [
Padding(
padding: EdgeInsets.all(10),
child: Text(items.value['name'])),
Row(
children: [
Radio(
value: items.value['id'],
groupValue: count,
onChanged: (val) {
setSelectedRadioTile(val);
},
),
Text("Yes"),
Radio(
value: items.value['id'] + count,
groupValue: count,
onChanged: (val) {
setSelectedRadioTile(val);
},
),
Text("N/A")
],
)
]);
}).toList()
setSelectedRadioTile(int val) {
print(val);
setState(() {
count = val;
});
}
Okay well I have built you a working version based on what you provided here. Please keep in mind that it would probably be a good idea to look at the documentation more in-depth so you get a feeling of how some widgets behave and what specific properties (like groupValue) are for. Also keep in mind that the following code is not optimised or whatsoever, I just got it worked out for your case - thinking about how to structure your data overall is some fundamental thing you should take a look at. Maybe try some out some flutter courses which are available or look at some youtube content from known flutter coders. But now back to some code stuff.
I used those properties in my StatefulWidget to work with. Since you use some kind of question map and I don't know how it looks like, I just used something bare bones:
/// Map which has the question ID as its key and the answer from the user (currently true for yes and false for no (or n/a as in your case)
Map<int, bool> _answers = {};
/// Map which holds the information of your questions. Right now only an ID to be able to reference it and the actual question - again very bare bones
Map<String, dynamic> _item = {
'questions': [
{
'id': 0,
'question': 'Is this legit?',
},
{
'id': 1,
'question': 'Oh really?',
},
]
};
Then the method which will be called by the Radio widget once onChanged is triggered:
/// We need to know which question has been answered (therefore the ID) and which (bool) answer has been clicked by the user
_setSelectedRadioTile(int id, bool answer) {
setState(() {
_answers[id] = answer;
});
}
And now the widget part - since your code starts where you iterate over the questions, I also share this part specifically:
/// Since the map itself is typed as <String, dynamic>, accessing 'questions' will return dynamic. Only we, as we know the structure, know that this is indeed a list. Therefore we need to cast this as "List<dynamic>" so we can iterate over it and won't get exceptions
(_item['questions'] as List<dynamic>)
.map(
(question) => TableRow(children: [
Padding(
padding: EdgeInsets.all(10),
child: Text(question['question'])),
Row(
children: [
Radio(
/// The [value] property of Radio tells us, which property is used in [onChanged] - therefore now once this Radio is clicked, true is provided in the [onChanged] callback
value: true,
/// [groupValue] is the value which this Radio is bound to. As you probably know, only one Radio button should be active for a group. So if you have a question which has several possible answers as radio buttons, we only want one of them to be active at a time. Thats what the [groupValue] is for. Since we iterate over all questions and every entity of a question (currently) has two possible answers (Yes and N/A), both those answers are for a specific question - the question with the current ID
groupValue: _answers[question['id']],
onChanged: (answer) {
_setSelectedRadioTile(question['id'], answer);
},
),
Text("Yes"),
Radio(
value: false,
groupValue: _answers[question['id']],
onChanged: (answer) {
_setSelectedRadioTile(question['id'], answer);
},
),
Text("N/A")
],
)
]),
)
.toList(),
This should work on your side once you updated this example to fit with your data model. Again: I advise you to think about how you structure your data generally.

Can Anyone Explain how to make a Searchable DropDown to select countries using api/json? in Flutter

I want to make a dropdown list, in which one can select the country. The drop down list must be searchable, whenever we type a letter, the drop down list changes.
The drop down list is using a api/json data.
We are not making selection Manually.
you can use searchable_dropdown or dropdown_search packages
For API/JSON question :
check out the second package example in Readme
example
DropdownSearch<UserModel>(
label: "Name",
onFind: (String filter) async {
var response = await Dio().get(
"http://5d85ccfb1e61af001471bf60.mockapi.io/user",
queryParameters: {"filter": filter},
);
var models = UserModel.fromJsonList(response.data);
return models;
},
onChanged: (UserModel data) {
print(data);
},
);