Flutter: filter a List<Map<String, dynamic>> to only contain certain items - flutter

I have a list of maps where one of the fields in the map is a boolean called "completed". I want to be able to filter the map so that I only get the items for which "completed" is true or false. My current code is the following:
try {
String? email = FirebaseAuth.instance.currentUser!.email;
for (int i = startingIndex; i < endingIndex; ++i) {
var doc = await FirebaseFirestore.instance
.collection(email!)
.doc("goals")
.collection(Utils.goalsCategoriesDropdownItems[i])
.get();
if (doc.size > 0) {
allData.addAll(doc.docs.map((doc) => doc.data()).toList());
}
}
allData.sort(((a, b) {
Timestamp one = a["dueDate"];
Timestamp two = b["dueDate"];
return one.compareTo(two);
}));
return allData;
}
but I don't want to return allData, I want to filter and see if all the items are true or false, so I want something like this:
if (completed == true) {
allData.map((e) => e["completed"] == true);
} else {
allData.map((e) => e["completed"] == false);
}
return allData;

It is not entirely clear what your expected outcome is, but here are two possibilities:
a) If you want to check if every Map in your List has the key completed with a value of true you can use every:
return allData.every((e) => e["completed"] === true)
b) If you want to have a list containing only Maps which contain the key completed with a value of true you can use where:
return allData.where((e) => e["completed"] === true)

Related

How to search for 2 different parameters in dart list?

How to search for 2 different parameters in a dart list?
Is there a simple method?
Can I solve the problem using contains?
void _runFilter(String searchKeyword) {
List<Product> results = [];
if (searchKeyword.isEmpty) {
results = allProducts;
} else {
results = allProducts.where(
(element) =>
element.name.toLowerCase().contains(searchKeyword.toLowerCase()) || element.image.toLowerCase().contains(searchKeyword.toLowerCase()),
),
)
.toList();
results = results +
allProducts
.where(
(element) => element.image.toLowerCase().contains(
searchKeyword.toLowerCase(),
),
)
.toList();
}
// refresh the UI
setState(() {
filteredProducts = results;
});
}
You can write all sorts of if-else-combinations in a closure. If you use the {} notation instead of => it will become clearer. Something like this will accomplish what you are looking for:
results = allProducts.where( (element) {
if ( element.name.toLowerCase().contains(searchKeyword.toLowerCase()) {
return true;
} else if ( element.image.toLowerCase().contains(searchKeyword.toLowerCase()) {
return true;
} else {
return false;
}
}).toList();
If this step is clear, you can then try to combine individual statements into a boolean combination via || or && if this looks more convenient in your code.

how to check if a typing value contains a list of map

I have a list of map, so I want to check If the value I type contains any of the key value before adding.
here is my code:
for (var check in disciplineList) {
if (check.containsKey('degree') ||
!check.containsKey('degree')) {
if (check['degree'] != discipline.text) {
disciplineList.add({
'degree': discipline.text,
'date': currentDate
});
setState1(() {});
setState(() {});
discipline.clear();
currentDate = DateTime.now();
print(disciplineList);
} else {
openCustomDialog(
context: context,
body: '',
heading: 'Item Already Exists!');
print("Item Already Exists!");
}
}
}
In case you have some List of Maps listOfMaps and you want to check if it contains
1- a specific key
you can do so like this:
bool doesItContainKey(var key)
{
return listOfMaps.any((element) => element.keys.contains(key));
}
2- a specific value
you can do so like this:
bool doesItContainValue(var value)
{
return listOfMaps.any((element) => element.values.contains(value));
}
3- a specific map:
you can do so like this:
bool doesItContainMap(var map)
{
return listOfMaps.any((element) => element==map);
}

Flutter Firestore Pagination (add/remove items)

I'm struggling to get this done, after two days I decided to ask you guys for help.
I'm using Mobx as state management, the issue is related to adding/removing an item to/from the list, e.g. if I retrieve two queries of 5 items each, according to the limit and then remove an item from the first query the first item from the second query is duplicate and if I add a new item, the first item from the second query is hidden. I have also set a scrollListener to the ListView.builder to get the bottom of the list and call for more items.
Thanks in advance,
#override
Stream<QuerySnapshot> teste(DocumentSnapshot lastDoc) {
if (lastDoc == null) {
return firestore.collection('teste')
.orderBy('name')
.limit(5)
.snapshots();
} else {
return firestore.collection('teste')
.orderBy('name')
.limit(5)
.startAfterDocument(lastDoc)
.snapshots();
}
}
#observable
ObservableList<List<TesteModel>> allPagedResults = ObservableList<List<TesteModel>>();
#observable
ObservableList<TesteModel> listTeste = ObservableList<TesteModel>();
#observable
DocumentSnapshot lastDoc;
#observable
bool hasMoreItem;
#action
void teste() {
var _currentRequestIndex = allPagedResults.length;
primaryRepository.teste(lastDoc).listen((query) {
if (query.docs.isNotEmpty) {
var _query = query.docs.map((doc) => TesteModel.fromFirestore(doc))
.toList();
var _pageExists = _currentRequestIndex < allPagedResults.length;
if (_pageExists) allPagedResults[_currentRequestIndex] = _query;
else allPagedResults.add(_query);
listTeste = allPagedResults.fold<List<TesteModel>>(<TesteModel>[],
(initialValue, pageItems) => initialValue..addAll(pageItems)).asObservable();
if (_currentRequestIndex == allPagedResults.length - 1) lastDoc = query.docs.last;
hasMoreItem = _query.length == 5;
}
});
}
Any luck with this issue?
For adding new items and having multiple pages you could do something like this:
if (allPagedResults.contains(allPagedResults[0].last) == false) {
allPagedResults.last.add(allPagedResults[0].last);
allPagedResults.last.remove(allPagedResults[0].first);
}

How to assign values from storage to a variable in ionic 3

I tried few methods to assign values to variable but could succeed please help.
Method 1:-
getData() {
return this.storage.get('products')
.then(res => {
return this.cart = res;
});;
}
Console.log shows undefined
Method 2:-
cart = [];
getData() {
return this.storage.get('products')
.then(res => {
return this.cart.push(res);
});;
}
Output :
How can i achieve
Cart variable as directly the array list from 0, 1,? [as shown in picture]
Found the Solution
//set Cart Storage
this.storage.get('products').then((data) => {
if (data == null) {
data = [];
}
this.cart = data;//re-initialize the items array equal to storage value
this.cart.push(this.cartItem());
this.storage.set('products', this.cart);
console.log("Cart" + this.cart);
});
On Another Page
// Retrieving data
public getData() {
return this.storage.get('products')
.then(res => {
this.cart = [];
this.cart = res;
console.log(this.cart);
});
}
Try logging the value of the res parameter in the console. From there, you can assign the value of cart to the correct property in the res object.

Ionic 2 search bar

I'm implementig a search bar, it filters the way I want, but after 2 seconds, it shows the whole array again, and I dont really understand why.
Thanks for your help.
This is the .ts
getCatalog() {
this.http.get('url', {}, {}).then(data => {
console.log("Data:", JSON.parse(data.data));
this.catalogList = JSON.parse(data.data);
// console.log(data.status);
// console.log(data.data); // data received by server
// console.log(data.headers);
})
.catch(error => {
console.log(error.status);
console.log(error.error); // error message as string
console.log(error.headers);
});
}
getItems(ev: any) {
// Reset items back to all of the items
this.getCatalog();
// set val to the value of the searchbar
let val = ev.target.value;
//console.log("VALUE", ev);
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {
this.catalogList = this.catalogList.filter((item) => {
console.log("ITEM", item)
return (item.name.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
This is where i have the *ngFor
<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>
<ion-grid>
<ion-row *ngFor="let item of catalogList">
Other code here
I think the problem is that your HTTP request finishs after you've already filtered your array, this'll make the catalogList receive the parsed JSON after you've filtered, this is why it resets.
Do you really need to get your catalog from the server every time the ser types something in the searchbar? Is your catalog that dynamic? If not you can simply save it in your catalogList when the user enters the page and create another object to be used at your filter:
public catalogListFiltered: any[] = []; // CREATE A NEW VARIABLE THAT'LL BE USED ON YOUR NGFOR
ionViewDidEnter() { // or ionViewDidLoad, depends on what lifecycle you need
this.http.get('url', {}, {}).then(data => {
this.catalogList = JSON.parse(data.data);
this.initializeCatalogs();
});
}
// THIS'LL SET YOUR FILTERED ARRAY TO THE FIRST/FULL VERSION OF YOUR CATALOG
initializeCatalogs(){
this.catalogListFiltered = this.catalogList;
}
getItems(ev: any) {
// Reset items back to all of the items
this.initializeCatalogs();
// set val to the value of the searchbar
let val = ev.target.value;
//console.log("VALUE", ev);
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {
this.catalogList = this.catalogList.filter((item) => {
console.log("ITEM", item)
return (item.name.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
If you really need to call your API everytime to get your catalog just work with promises
getCatalog = (): Promise<any> {
return new Promise<any>(resolve => {
this.http.get('url', {}, {}).then(data => {
resolve(JSON.parse(data.data));
});
});
}
// maybe this'll have the same effect as the above, maybe someone can say if that'll work with some changes on your 'getItem' method:
// getCatalog(){ return this.http.get('url', {}, {}); };
getItems(ev: any) {
// Reset items back to all of the items
this.getCatalog().then(res => {
this.catalogList = res;
// set val to the value of the searchbar
let val = ev.target.value;
//console.log("VALUE", ev);
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {
this.catalogList = this.catalogList.filter((item) => {
return (item.name.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
});
}
Hope this helps.