Why does Map<String,List> List update fail? - flutter

I have comments variable which is dictionary type and holds the second parameter as a list
Unfortunately, despite I get the data (inputDataSnapshot) I can not get it added to the dictionary. The dictionary with the relevant key always return null
Can someone please help why this happens?
Map<String?, List<Commentp?>?>? comments;
int _pageIndex = 0;
int _limit = 3;
String get pageIndex {
return _pageIndex.toString();
}
String get limit {
return _limit.toString();
}
List<Commentp?>? commentsP({required String postuuid}) {
return comments?[postuuid] ?? [];
}
void add({
required String postuuid,
required List inputDataSnapshot,
}) {
for (int i = 0; i < inputDataSnapshot.length; i++) {
comments?[postuuid]!.add(Commentp.fromJson(inputDataSnapshot[i]));
print(comments?[postuuid]);
}
}
}```

The mistake I made was uninitialized comments variable.
I added below code to my add method and it is fine now
if (comments[postuuid] == null) {
comments[postuuid] = [];
}

Related

Flutter: Concurrent modification during iteration

So I know that my mistake lies in trying to change my data when im iterating through it
this is the exact error
"Expected Non-error `Concurrent modification during iteration:
Instance of 'LinkedMap<dynamic, dynamic>'.
and this is my code:
_products.forEach((key, value) {
if (key.titel == product.titel) {
_products[key] += 1;
} else {
_products[product] = 1;
}
}
but I don't really get how I would be able to modify my data without iterating through it. Any suggestions?
----------------my Attempt -------------------
var _products = {}.obs;
var temp = {}.obs;
void addProduct(Product product) {
temp = _products;
if (_products.length > 0) {
_products.forEach((key, value) {
if (key.titel == product.titel) {
temp[key] += 1;
} else {
temp[product] = 1;
}
});
}
I get the same error; I think that is because in this line:
temp = _products;
I just get the reference on _products & I don't write _products in temp
So as mmcdon suggested you need make a copy of your existing thing that you want to iterate upon & iterate through that instead of your original piece
So in my case I need to do this:
var _products = {}.obs;
var temp = {}.obs;
void addProduct(Product product) {
temp = RxMap<dynamic, dynamic>.from(_products);
if (_products.length > 0) {
temp.forEach((key, value) {
if (key.titel == product.titel) {
_products[key] += 1;
} else {
_products[product] = 1;
}
});
}
So as you can see I iterate through temp, that basically is _products & Im writing the data that I need in _products

Flutter generating list with FOR loop via GET method

Good morning. I am building simple workout app in Flutter. I want to generate list of custom class Excersise:
class Excersise{
int id;
String name;
int duration;
int type;
Excersise({
required this.id,
required this.duration,
required this.name,
required this.type,
});
I want to pass parameter rounds, wtime(workout time) and ctime(cooldown time) from parent widget and then my app should create list of excersises. It should be pairs of workout and cool down time like this: wo 30sec, cd 15sec, wo 30sec, cd 15sec and so one (based on rounds value). I tried to generate this list via GET but after building this widget i get Stack overflow error. Maybe there is some error in code, maybe this is completely wrong method. Here is a code and thank for your advices.
class QuickWorkoutList extends StatelessWidget {
final int rounds;
final int wtime;
final int ctime;
QuickWorkoutList({
required this.rounds,
required this.wtime,
required this.ctime,
});
List<Excersise> get _qList {
var newEx = Excersise(id: 0, duration: 0, name: '', type: 0);
for (var i = 0; i < rounds * 2; i++) {
if (i.isEven) {
newEx.id = i;
newEx.name = 'Workout';
newEx.type = 0;
newEx.duration = wtime;
} else {
newEx.id = i;
newEx.name = 'Cooldown';
newEx.type = 1;
newEx.duration = ctime;
}
_qList.add(newEx);
}
throw 'No data';
}
Your getter method _qList is wrong implemented. You should create an empty List<Excersise> and add the Workout and Cooldown there. Currently you are recursively calling your _qList which has no anchor to stop. Consequently you have an endless loop. Btw I think you mean Exercise instead of Excersise.
List<Exercise> get _qList {
// All exercises stored
final List<Exercise> exercises = [];
// Exercise properties
int duration;
String name;
int type;
for (int i = 0; i < rounds * 2; i++) {
// Get exercise properties depending on id
if (i.isEven) {
name = 'Workout';
type = 0;
duration = wtime;
} else {
name = 'Cooldown';
type = 1;
duration = ctime;
}
// Add new exercise to list
exercises.add(
Excersise(
id: i,
duration: duration,
name: name,
type: type,
),
);
}
return exercises;
}
You shouldn't call add on your _qList getter, and that creates stack overflow I guess. You should use new List and return it from your _qList getter like this:
List<Excersise> get _qList {
var newEx = Excersise(id: 0, duration: 0, name: '', type: 0);
List<Excersise> exercises = [];
for (var i = 0; i < rounds * 2; i++) {
if (i.isEven) {
newEx.id = i;
newEx.name = 'Workout';
newEx.type = 0;
newEx.duration = wtime;
} else {
newEx.id = i;
newEx.name = 'Cooldown';
newEx.type = 1;
newEx.duration = ctime;
}
exercises.add(newEx);
}
return exercises;
}

Can we perform "Not null or return" in flutter with null safety feature?

I'm trying to migrate null safety feature into my Flutter project because it's good for my future of project. Since I already have experience of developing Android app via Kotlin, I already got used to this null safety feature. But it seems I can't perform one thing which can be done in Kotlin.
user?.name ?? "Unknown"
I noticed that in Dart, I can set default value with this code line.
Now I'm trying to perform this
fun performOrReturn(users: Map<String, User>, id: String) {
val user = users[id] ?: return //This line
println("User info gotten : ${user.name}")
}
In Kotlin, I can perform this thing. I can make method return itself if specific variable is null, so Kotlin can handle null safety flexibly.
So here is what I'm trying to do, there is table in my code. I want to check if there is data existing in specified column and row in this field.
Map<int, List<MyData>> table = Map();
...
int _findDataExisting(int row, int col) {
List<MyData> data = table[row]; //This is causing problem because table[row] can be null
//Alternative solution is
//List<MyData> data = table[row] ?? List.empty();
//
//if(data.isEmpty) {
// return -1;
//}
//
for(int i = 0; i < data.length; i++) {
if(data[i].column == col) {
return i;
}
}
return -1;
}
I want to make it return -1 rather than initializing default value because it's not good for handling memory, and code becomes inefficient.
List<MyData> data = map[row] ?? return -1;
I tried line below just like Kotlin, but Dart seems that it can't handle this.
Is there any equivalent thing in Dart? Making it return method if specific variable is null.
Don't be fancy.
int _findDataExisting(int row, int col) {
if (table[row] != null) {
List<MyData> data = table[row]!;
for(int i = 0; i < data.length; i++) {
if(data[i].column == col) {
return i;
}
}
}
return -1;
}
You could initially declare data as nullable and let the null check automatically promote it to a non-nullable type, avoiding the need to use null assertions (!) later:
int _findDataExisting(int row, int col) {
List<MyData>? data = table[row];
if (data == null) return -1;
for (int i = 0; i < data.length; i++) {
if (data[i].column == col) {
return i;
}
}
return -1;
}

How to fix both Found 'DD'-anomaly and only one return statement

I have some difficulties when fixing PMD warnings, this was my simplified method:
public String rank(String keyword, int pageSize, int totalPage)
{
String result = "0"; // A: DataflowAnomalyAnalysis: Found 'DD'-anomaly for variable 'result'
if (isNotBlank(keyword))
{
boolean find = false; // B: DataflowAnomalyAnalysis: Found 'DD'-anomaly for variable 'find'
for (int page = 1; page < totalPage; page++)
{
int rank = getRank(keyword, pageSize, totalPage);
if (rank != 0)
{
find = true; // B(1)
result = String.valueOf(rank); // A(1)
break;
}
}
if (!find)
{
result = format("{0}+", totalPage * pageSize - 1); // A(2)
}
}
return result;
}
I tried this and got "OnlyOneReturn" warnings:
public String rank(String keyword, int pageSize, int totalPage)
{
if (isNotBlank(keyword))
{
for (int page = 1; page < totalPage; page++)
{
int rank = getRank(keyword, pageSize, totalPage);
if (rank != 0)
{
return String.valueOf(rank); // OnlyOneReturn
}
}
return format("{0}+", totalPage * pageSize - 1); // OnlyOneReturn
}
return "0";
}
How do I have to write this code please?
A 'DD'-anomaly an a dataflow analysis tells you that you assign a variable more than once without using it between the assignments. So all but the last assignment are unnecessary. It usually indicates that you didn't separate your scenarios properly. In your case you have three scenarios:
If the keyword is blank then the return value is "0".
Otherwise loop through all pages and if getRank() returns a rank other than zero then this is the return value.
Otherwise the return value is "totalPage * pageSize - 1+"
If you implement those scenarios one by one you end up with a method that has not any dataflow or other PMD issues:
public String rank(String keyword, int pageSize, int totalPage) {
String result;
if (isNotBlank(keyword)) {
result = "0";
} else {
int rank = 0;
for (int page = 1; page < totalPage && rank == 0; page++) {
rank = getRank(keyword, pageSize, totalPage);
}
if (rank != 0) {
result = String.valueOf(rank);
} else {
result = format("{0}+", totalPage * pageSize - 1);
}
}
return result;
}
If you take a closer look at the for loop you see that page is only used for looping. It is not used inside the loop. This indicates that the for loop is probably not necessary. getRank(keyword, pageSize, totalPage) should always return the same value as its arguments never change during the loop. So it might be enough to call getRank(...) just once.

How to check if text is found in column in Protractor

I'm trying to assert that a name is displayed in a column of a table. I've written an inResults function that will iterate through a column's text to see if a name exists. Here's what I'm trying:
Page object:
this.names = element.all(by.repeater('row in rows').column('{{row}}'));
this.inResults = function(nameString) {
var foundit = '';
this.names.each(function(name) {
name.getText().then(function(it) {
console.log(it); // each name IS printed...
if(it == nameString) {
console.log('it\'s TRUE!!!!'); // this gets printed...
foundit = true;
}
});
});
return foundit; // returns '' but should be true?
};
Spec expect:
expect(friendPage.inResults('Jo')).toBeTruthy();
Both console statements print as expected... but my expect fails as foundit's value is still ''. I've tried this a number of ways and none are working. What am I missing?
I've devised what I think is a better/cleaner way to solve this. It's less complex and doesn't require locator/css code in the method.
friend.page.js
// locator
this.friendName = function(text) { return element.all(by.cssContainingText('td.ng-binding', text)) };
// method
this.inResults = function(name) {
return this.friendName(name).then(function(found) {
return found.length > 0;
});
};
friend.spec.js
expect(friendPage.inResults('Jo')).toBeTruthy();
I've added this to my protractor_example project on GitHub...
I would recommend you to use filter: http://angular.github.io/protractor/#/api?view=ElementArrayFinder.prototype.filter
this.inResults = function(nameString) {
return this.names.filter(function(name) {
return name.getText().then(function(text) {
return text === nameString;
});
}).then(function(filteredElements) {
// Only the elements that passed the filter will be here. This is an array.
return filteredElements.length > 0;
});
});
// This will be a promise that resolves to a boolean.
expect(friendPage.inResults('Jo')).toBe(true);
Use map to do this.This will return a deferred that will resolve with the values in an array, so if you have this:
this.mappedVals =element.all(by.repeater('row in rows').column('{{row}}')).map(function (elm) {
return elm.getText();
});
It will resolve like this:
this.inResults = function(nameString) {
var foundit = '';
mappedVals.then(function (textArr) {
// textArr will be an actual JS array of the text from each node in your repeater
for(var i=0; i<textArr.length; i++){
if(it == textArr[i]) {
console.log('it\'s TRUE!!!!'); // this gets printed...
foundit = true;
}
}
return foundit;
});
}
And Use that in Spec file like,
friendPage.inResults('Jo').then(function(findIt){
expect(findIt).toBeTruthy();
});