Fixed List is not updating with for loop - Flutter - flutter

I've a fixed list reservedGuest. After checking the condition in for loop I want to update the seats if the membership date has expired. The list is not updating. The code is as follows. PS. The List is filled through API on init().
class MyClubController extends GetxController {
List goldLane = List.filled(3, null, growable: false);
void _alterLanesOnContractEnds() {
for (var i in goldLane) {
print("\n\n I: $i");
if (i == null ||
DateTime.parse(i['contractEnds']).isBefore(
DateTime.now(),
)) {
i = null;
print('Can be removed');
} else {
print('Cannot be removed');
}
}
update();
}
}

A for-in loop will not allow you to reassign elements of the List. When you do:
for (var i in goldLane) {
// ...
i = null;
}
you are reassigning what the local i variable refers to, not mutating the goldLane List.
You instead can iterate with an index:
void _alterLanesOnContractEnds() {
for (var i = 0; i < goldLane.length; i += 1) {
var element = goldLane[i];
print("\n\n I: $element");
if (element == null ||
DateTime.parse(element['contractEnds']).isBefore(
DateTime.now(),
)) {
goldLane[i] = null;
print('Can be removed');
} else {
print('Cannot be removed');
}
}
update();
}

You can just create a new List where unqualified guests are nullified. For example,
void _alterLanesOnContractEnds() {
goldLane = goldLane.map(
(guest) => guest == null || DateTime.parse(guest['contractEnds']).isBefore(DateTime.now()) ? null: guest
).toList(growable: false);
update();
}
You should not and cannot modify a list while iterating with its iterator.
Elaborated by Jamesdlin,
Modifying the elements of a List while iterating is fine. Modifying
the length of the List while iterating is not, but that won't be a
problem for a non-growable List.
The bottom line is you should not mutate the size of the list while iterating.

I solved it by using
goldLane.forEach(
(element) {
print('\n\n ELEMENT: $element');
if (element == null ||
DateTime.parse(element['contractEnds']).isBefore(
DateTime.now(),
)) {
int ix = goldLane.indexWhere(
(element) => element != null
? DateTime.parse(element['contractEnds']).isBefore(
DateTime.now(),
)
: true,
);
goldLane[ix] = null;
} else {
print('Cannot be removed');
}
},
);
Yet I'll test the other answers. Thank You.

Related

The method 'add' can't be unconditionally invoked because the receiver can be 'null'

I'm trying to handle some data for a flutter application, however I am getting the following error on my code:
The method 'add' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
Map<String, List<SourcefulListing>> sortedSkills = {};
QuerySnapshot listingSnapshot = await listingsRef.get();
List<SourcefulListing> listings = [];
for (int i = 0; i < listingSnapshot.docs.length; i++) {
listings.add(SourcefulListing.fromJson(
listingSnapshot.docs[i].data() as Map<String, dynamic>));
}
for (String skill in skills) {
for (SourcefulListing listing in listings) {
if (listing.selectedSkill == skill) {
if (sortedSkills[skill] == null || sortedSkills[skill] != []) {
sortedSkills[skill] = [listing];
} else {
sortedSkills[skill] = sortedSkills[skill].add(listing);
}
}
}
}
Basically I have a Map with Strings as key and List for the values. The for each loop should add the SourcefulListing object to the map, however there is an error on the .add method.
Any help would be much appreciated.
Try this,
Map<String, List<SourcefulListing>> sortedSkills = {};
QuerySnapshot listingSnapshot = await listingsRef.get();
List<SourcefulListing> listings = [];
for (int i = 0; i < listingSnapshot.docs.length; i++) {
listings.add(SourcefulListing.fromJson(
listingSnapshot.docs[i].data() as Map<String, dynamic>));
}
for (String skill in skills) {
for (SourcefulListing listing in listings) {
if (listing.selectedSkill == skill) {
if (sortedSkills[skill] == null || sortedSkills[skill] != []) {
sortedSkills[skill] = [listing];
} else {
sortedSkills[skill]?.add(listing); // changes made here
setState(() {}); // update ui
}
}
}
}
Null Safety : https://dart.dev/null-safety

The function finds only one element, even if there is more than one

The function below finds only one item in the list, even if there are multiple items, how do I fix this function to find all items?
List newList = [];
if (value.isNotEmpty) {
for (var element in pressures) {
if (element.pressure.contains(value) ||
element.date.toString().contains(value)) {
newList.clear();
newList.add(element);
}
}
items.value = newList;
} else {
items.value = pressures;
}
You are clearing the list on loop
if (value.isNotEmpty) {
newList.clear(); // you can clear it on top of the loop
for (var element in pressures) {
if (element.pressure.contains(value) ||
element.date.toString().contains(value)) {
// newList.clear(); //remove this
newList.add(element);
}
}
items.value = newList;
} else {
items.value = pressures;
}

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.

multidimensional list wont update state

how i can update my state in multidimensional list like screen. I can update state in first list level, but if i go on next level, state won't update
[0]:MegaFileModel (FileM(id: 714a55f4-d620-4fcb-a723-16af2c6115e3, fileName: Альбомы, extension: folder, preview: null, type: DIRECTORY, uploadUrl: null, serverfileName: null, addDate: 14.12.2021 09:04:14, checked: false))
addDate:"14.12.2021 09:04:14"
checked:false
content:List (3 items)
dir:Map (2 items)
extension:"folder"
fileName:"Альбомы"
id:"714a55f4-d620-4fcb-a723-16af2c6115e3"
preview:null
serverfileName:null
type:"DIRECTORY"
uploadUrl:null
hashCode:92220431
isDirectory:true
runtimeType:Type (MegaFileModel)
This is my function which i call every time when i want update state
List<MegaFileModel> getNewContentListState(List<MegaFileModel> state,
List<MegaFileModel> newState, bool value, String id) {
for (var i = 0; i < state.length; i++) {
if (state[i].id == id) {
newState.add(state[i].copyWith(checked: value, content: []));
} else {
newState.add(state[i].copyWith(content: []));
}
if (state[i].type == 'DIRECTORY') {
getNewContentListState(
state[i].content, newState[i].content, value, id);
}
}
return newState;
}
void doPick(bool value, String id) {
List<MegaFileModel> newState = [];
state = getNewContentListState(state, newState, value, id);
}

w2ui filter option "contains not" possible?

I am using w2ui (1.5) and I would be interested in whether it is possible to use a filter that only delivers negative results
That means only records/keys which not fullfilling a certain criteria.
Like a condition "contains not" or "is not" in addition to
http://w2ui.com/web/docs/1.5/w2grid.textSearch.
Thanks!
Gordon
okay, a possible solution is
w2ui['grid'].search([{ field: var1, value: var2, operator: 'not in'}], 'OR');
I coded my own solution to this problem. This adds a way to use "not" for string and "!=" for number searches.
This function does the search and it is also used to store the grid advanced search popup in history state.
I'm sure this can be even more optimized, so please use this more like a guideline. Hope this helps somebody.
function searchExtend(event, grid) {
// if event is null, we do just the local search
var searchObj;
if (event == null) {
searchObj = grid;
} else {
searchObj = event;
}
// make a copy of old data
const oldSearchData = structuredClone(searchObj.searchData);
const oldSearchLogic = structuredClone(searchObj.searchLogic);
var searchData = searchObj.searchData;
var invertedSdata = [];
var toSplice = [];
// check operator if it's "not" or "!="
for (var i = 0; i < searchData.length; i++) {
var sdata = searchData[i];
// invert the condition
if (sdata.operator == "not") {
toSplice.push(i);
invertedSdata.push({
field: sdata.field,
type: sdata.type,
operator: "contains",
value: sdata.value
});
}
if (sdata.operator == "!=") {
toSplice.push(i);
invertedSdata.push({
field: sdata.field,
type: sdata.type,
operator: "=",
value: sdata.value
});
}
}
// remove all "not" and "!=" from searchData
for (var i in toSplice) {
searchData.splice(i, 1);
}
var foundIds = [];
// use inverted criteria to search
if (invertedSdata.length > 0) {
grid.searchData = invertedSdata;
grid.searchLogic = "OR";
grid.localSearch();
grid.searchLogic = oldSearchLogic;
// store found ids
foundIds = structuredClone(grid.last.searchIds);
}
if (foundIds.length > 0) {
// perform a search with original criteria - spliced "not" and "!="
grid.searchData = searchData;
grid.localSearch();
var allRecIds = structuredClone(grid.last.searchIds);
// if there's not any results, push push all recIds
if (grid.last.searchIds.length == 0) {
for (let i = 0; i < grid.records.length; i++) {
allRecIds.push(i);
}
}
// remove all ids found with inverted criteria from results. This way we do the "not" search
for (const id of foundIds) {
allRecIds.splice(allRecIds.indexOf(id), 1);
}
if (event != null) {
// let the search finish, then refresh grid
event.onComplete = function() {
refreshGrid(grid, allRecIds, oldSearchData);
setSearchState(grid);
}
} else {
// refresh the grid
refreshGrid(grid, allRecIds, oldSearchData);
setSearchState(grid);
}
return;
}
if (event != null) {
event.onComplete = function() {
setSearchState(grid); // store state
}
} else {
// refresh whole grid
refreshGrid(grid, allRecIds, oldSearchData);
setSearchState(grid);
}
}
function refreshGrid(grid, allRecIds, oldSearchData) {
grid.last.searchIds = allRecIds;
grid.total = grid.last.searchIds.length;
grid.searchData = oldSearchData;
grid.refresh();
}
function setSearchState(grid) {
history.replaceState(JSON.stringify(grid.searchData), "Search");
}
To use this, you have to call it from the grid's onSearch:
onSearch: function(event) {
searchExtend(event, w2ui["grid"]);
}
Also, if you want to use the history.state feature, it needs to be called from onLoad function:
onLoad: function(event) {
event.onComplete = function() {
console.log("History state: " + history.state);
if (history.state != null) {
w2ui["grid"].searchData = JSON.parse(history.state);
searchExtend(null, w2ui["grid"]);
}
}
To add operators, please use this reference.
This is my solution to the problem:
operators: {
'text': ['is', 'begins', 'contains', 'ends', 'not'], // could have "in" and "not in"
'number': ['=', 'between', '>', '<', '>=', '<=', '!='],
'date': ['is', 'between', {
oper: 'less',
text: 'before'
}, {
oper: 'more',
text: 'after'
}],
'list': ['is'],
'hex': ['is', 'between'],
'color': ['is', 'begins', 'contains', 'ends'],
'enum': ['in', 'not in']
}