Dart Not understanding how forEach is supposed to work - flutter

I simply wanted to use forEach to set all values in a List to false, but I don't understand why it doesn't work. I created a filled list with fixed length like this:
List<bool> myList = List<bool>.filled(6, false);
Then I set one value to true:
setState(() => myList[3] = true);
Then I try to reset all values to false again, but as you can see from the print output it does not work:
setState(() {
myList.forEach((val) => val = false);
print(myList);
});
I/flutter (29049): [false, false, false, true, false, false]

You can check the answer why you can't update the values inside forEach here: List.forEach unable to modify element?
Dart does not have variable references, all elements are passed as a reference to an object, not to a variable. (In other words, Dart is purely "call-by-sharing" like both Java and JavaScript).
That means that the e parameter to the forEach callback is just a normal local variable, and assigning to it has no effect outside the callback. The same goes for iterators: they return the value in the iterable, but it has no reference back to the iterable after that.
You can do what you want using filled method like you used to create the list.
setState(() {
myList = List<bool>.filled(myList.length, false);
print(myList);
});

forEach element can not modify the actual element in the list. Assume this code:
var list = [false, true, false, false];
list.forEach((item) {
item = false;
});
print("List: $list");
The output is still:
List: [false, true, false, false]
So what you can do is using an indexed for:
for (int i=0; i < list.length; i++) {
list[i] = false;
}
Or map it and reassign it:
var list = [true, true, false];
list = list.map((item) {
return false;
}).toList();
You'll get:
List: [false, false, false, false]

As pointed out above, the forEach function does not give you write access to the list, it just provides you with the value. Changing the parameter of the forEach callback function has no effect outside of that function call, it's just changing a local variable.
To change the list, you must store to its element slots directly. Either:
for (int i = 0; i < list.length; i++) list[i] = false;
or
list.fillRange(0, list.length, false);
should do the job.

Related

How to preselect checkbox in showQuickPick in vscode

I am using quickpick to display list of items and allowing user to do multiselect. I am using quickpick like this.
context.subscriptions.push(vscode.commands.registerCommand('command', async () => {
const list = await vscode.window.showQuickPick(filedsList, { ignoreFocusOut: true, canPickMany: true});
}));
I trying to make like if user previously selected some items in the quick pick and next time use opened this quick pick I want to preselect the previously selected values.
Is it feasible to do it in vscode extension development.
There are two options. In both cases you'll have to make QuickPickItems out of your AccurevOperations.cpkFieldsList as you cannot just pass strings as the first argument and use the pre-selection capability. It isn't difficult to do this, just loop through that AccurevOperations.cpkFieldsList array and create objects with the QuickPickItem properties you want, like:
const arr = ["1", "2", "3"];
// const quickPickItems = arr.map(item => ( { label: item, picked: true } ) ); // but this would select them all
const quickPickItems = arr.map(item => {
if (Number(item) % 2 != 0) return { label: item, picked: true };
else return { label: item }
});
So you would use your logic to set the items you want pre-selected to have the picked:true object property. Then
const options = { canPickMany: true };
const qp = vscode.window.showQuickPick(quickPickItems, options);
should show a QuickPick with your selected items.
The other option is to use the createQuickPick method instead, because with that you can use its selectedItems property. So starting with your array:
const arr = ["1", "2", "3"];
const quickPickItems = arr.map(item => ( { label: item } ) ); // and whatever other properties each item needs, perhaps nothing other than label
const qp = vscode.window.createQuickPick();
qp.canSelectMany = true;
qp.items = quickPickItems;
qp.selectedItems = [quickPickItems[0], quickPickItems[2]]; // your logic here
qp.show();
You will have to create an array of objects to assign to the selectedItems property. Perhaps by filtering the quickPickItems array (from above) for the labels you want pre-selected:
qp.selectedItems = quickPickItems.filter(item => {
return item.label === "1" || item.label === "3";
});
the object vscode::QuickPickItem has a property
picked
Optional flag indicating if this item is picked initially.

How to keep the current option in group button flutter

I was used group_button package from flutter to make user can select many options. After upgrading the library to version 5.0.0 or above, the selectedButtons property has been deprecated. I was save options of user by it but no I can't use it now. I was use it as:
GroupButton(
selectedButtons: setSelectedBtn(index),
isRadio: false,
spacing: 10,
onSelected: (i, isSelected) =>
onFilterSelect(index, i, isSelected),
buttons: widget.filters[index].value
.map((e) => e.value)
.toList())),
setSelectedBtn(index) {
List<int> result = [];
var valueSet = widget.filters[index].value;
bool isSelected = valueSet
.firstWhere((element) => element.isSelected,
orElse: () => CategoryFilterValues("", false))
.isSelected;
if (!isSelected) {
return result;
}
for (int index = 0; index < valueSet.length; index++) {
if (valueSet.elementAt(index).isSelected) {
result.add(index);
}
}
return result;
}
group_button
How I can save the options now in new version? Anyone can help me to do it.
thank you
Use GroupButtonController.
Controller have list of methods to interact with options.
selectIndex(int i) - Select button by index in radio type
unselectIndex(int i) - Unselect button by index in checkbox and radio type
... etc.
More docs and examples you can find here

How do I calculate a percentage based on a List of booleans?

I have a list of booleans here:
List<bool> list = [false, false, false, false];
Using that as an example, if I were to find the percentage of values that are true, it would be 0%.
Using another example:
List<bool> list = [true, true, false, false];
The percentage of values that are true would be 50%.
I was able to find something similar to what I need here: Flutter - Count List with bool which works.
However, the calculations to percentages are a little lost on me.
It's basically just the number of true elements divided by the total number of elements.
void main() {
List<bool> list = [true, true, false, false];
double percent = list.where((v) => v).length / list.length;
String percentString = '${(percent * 100).round()}%';
print(percent);
print(percentString);
}
You should probably do something like :
int trueValues = list.fold(0, (acc, val) => val ? ++acc : acc);
double truePercent = trueValues / list.length;
count the number of 'true' value and divide it by the list size (total number of values)

If statement inside a For loop - (If null don't add)

I'm working on a project with Firestore, I'm gathering Button data to create each button with a For loop. I could manage to get this data and store it to a List and create the buttons. Now I'm attempting to let the User Add or Delete his own buttons inside the App.
This is an ExampleIf I have 5 buttons in my App, I'm gathering info from firestore to know if these buttons are OFF or ON. I'm storing this bool states into a List, so if I have 5 buttons, I would have a list that you be:
List<bool> cardsValue = [false, false, true, false, true];
But when I delete one of these buttons, so Let's say I deleted the middle one, I would get an array, like this:
List<bool> cardsValue = [false, false, null, false, true];
I would need to Add an If statement so when I receive null as response, It won't add that null into my List. So my list would be:
List<bool> cardsValue = [false, false, false, true];
End of example
Actual code:
This is how my List actually looks:
List<bool> cardsValue = [for (int i = 0; i < cardamount; i++) snapshot.data[devices[i]]];
What I though on doing but unfortunatly didn`t work was:
List<bool> cardsValue = [for (int i = 0; i < cardamount; i++) if (snapshot.data[devices[i]] == null){}else{snapshot.data[devices[i]]}];
You can use where method of List class to filter out null values
List<bool> cardsValue = [for (int i = 0; i < cardamount; i++) snapshot.data[devices[i]]]
.where((v) => v != null)
.toList()
.cast<bool>()
Output
[false, false, false, true]
Your initial approach was close, but Dart's collection-for and collection-if constructs cannot use braces; they must be used with expressions, not statements.
List<bool> cardsValue = [
for (int i = 0; i < cardamount; i++)
if (snapshot.data[devices[i]] != null)
snapshot.data[devices[i]]
];

is there an alternative to DOMAttrModified that will work in webkit

I need to leverage this DOM event. IE has onpropertychange, which does what I need it to do also. Webkit doesn't seem to support this event, however. Is there an alternative I could use?
Although Chrome does not dispatch DOMAttrModified events, the more lightweighted mutation observers are supported since 2011 and these work for attribute changes, too.
Here is an example for the document body:
var element = document.body, bubbles = false;
var observer = new WebKitMutationObserver(function (mutations) {
mutations.forEach(attrModified);
});
observer.observe(element, { attributes: true, subtree: bubbles });
function attrModified(mutation) {
var name = mutation.attributeName,
newValue = mutation.target.getAttribute(name),
oldValue = mutation.oldValue;
console.log(name, newValue, oldValue);
}
For a simple attribute change, the console.log statement would print:
<body color="black">
<script type="text/html">
document.body.setAttribute("color", "red");
</script>
</body>
Console:
> color red black
If you are happy with merely detecting calls to setAttribute() (as opposed to monitoring all attribute modifications) then you could over-ride that method on all elements with:
Element.prototype._setAttribute = Element.prototype.setAttribute
Element.prototype.setAttribute = function(name, val) {
var e = document.createEvent("MutationEvents");
var prev = this.getAttribute(name);
this._setAttribute(name, val);
e.initMutationEvent("DOMAttrModified", true, true, null, prev, val, name, 2);
this.dispatchEvent(e);
}
I had the same question and was thinking of modifying setAttribute, so seeing what Sean did, I copied that. Worked great, except that it was firing when an attribute was repeatedly set to the same value, so I added a check to my copy to skip firing the event if the value is not being changed. I also added val = String(val), based on the rationale that setAttribute will coerce numbers to strings, so the comparison should anticipate that.
My modified version is:
var emulateDOMAttrModified = {
isSupportedNatively: function () {
var supported = false;
function handler() {
supported = true;
}
document.addEventListener('DOMAttrModified', handler);
var attr = 'emulateDOMAttrModifiedTEST';
document.body.setAttribute(attr, 'foo'); // aka $('body').attr(attr, 'foo');
document.removeEventListener('DOMAttrModified', handler);
document.body.removeAttribute(attr);
return supported;
},
install: function () {
if (!this.isSupportedNatively() &&
!Element.prototype._setAttribute_before_emulateDOMAttrModified) {
Element.prototype._setAttribute_before_emulateDOMAttrModified = Element.prototype.setAttribute
Element.prototype.setAttribute = function(name, val) {
var prev = this.getAttribute(name);
val = String(val); /* since attributes do type coercion to strings,
do type coercion here too; in particular, D3 animations set x and y to a number. */
if (prev !== val) {
this._setAttribute_before_emulateDOMAttrModified(name, val);
var e = document.createEvent('MutationEvents');
e.initMutationEvent('DOMAttrModified', true, true, null, prev, val, name, 2);
this.dispatchEvent(e);
}
};
}
}
};
// Install this when loaded. No other file needs to reference this; it will just make Chrome and Safari
// support the standard same as Firefox does.
emulateDOMAttrModified.install();
Please refer code:
https://github.com/meetselva/attrchange/blob/master/attrchange.js
'DOMAttrModified' + ('propertychange' for IE) are used there like in your case. If it's not suitable for you, the "ugly" solution that can satisfy this demand should be setInterval(function(){}, delay)
Otherwise see Sean Hogan post above.
The solution provided by #Filip is close (and may have worked at the time) but now you need to request delivery of the old attribute value.
Thus, you'll want to change :
observer.observe(element, { attributes: true, subtree: bubbles });
to this:
observer.observe(element, { attributes: true, attributeOldvalue:true, subtree: bubbles });
Otherwise, you won't see the oldValues (you'll get null instead.) This was tested in Chrome 34.0.1847.131 (Official Build 265687) m.