This question already has answers here:
How can I access the value of a promise?
(14 answers)
Async function returning promise, instead of value
(3 answers)
How to return many Promises and wait for them all before doing other stuff
(6 answers)
Closed 3 months ago.
I have already resolve promises in the cardcounter function but still gives me the same [object Promise] error. I do not know which promise i should be resolving and im stuck please help me
function paginator (mainembed, max, mentioned, author) {
async function cardcounter (cardcode, user) {
const results = await printcounter.findOne({code: cardcode, printowner: user})
let finalresult = results.amounts
if (!results) {
finalresult = 0
} else {
finalresult = results.amounts
}
console.log(`Number should be: ${finalresult}`)
return Promise.resolve(finalresult).then(function(val) {
console.log(val);
});
}
var last = max
const embeds = []
for (var i = 0 ; i < mainembed.length ; i+= max) {
const sliced = mainembed.slice(i, last)
console.log(sliced)
var index = i
last += max
const cardline = sliced.map(card => ` **${card.role}** \`${card.code}\` ${card.rarity} | **${card.group}** ${card.name} (${card.theme}) - ${cardcounter(card.code, mentioned)} `).join("\n")
console.log(cardline) // will define how the line of each card will look like in the embed.
const embed = new EmbedBuilder()
.setAuthor({name: `${author.tag} - Card Book`})
.setDescription(`**Featured Member**
> <#${mentioned}>
${cardline}`)
embeds.push(embed)
}
return embeds;
} //this function will generate the enough embed needed for the cards.
I want to get a value from a document and put it in slice.map section using the cardcounter function i made. I already resolve promises in that function
Related
I need to sort the elements by their data.
For example:
When I have 4 entries and 2 of them have the same date, the result will be 3 entries in the result list
This is my code:
Future<List<List<MoodData>>> moodData() async {
var result = await database
.ref()
.child("users/")
.child(user!.uid)
.child("moodData")
.once();
List<MoodData> x = [];
List<List<MoodData>> resultdata = [];
result.snapshot.children.forEach((element) {
maxID = int.parse(element.key.toString());
print(element.child("date").value);
if (x.length != 2) {
x.add(MoodData(
id: int.parse(element.key.toString()),
date: element.child("date").value.toString(),
moodValue: double.parse(element.child("y_value").value.toString()),
text: element.child("text").value.toString()));
} else {
resultdata.add(x);
x.clear();
}
});
print(resultdata);
return resultdata;
}
The problem is, that in the result list, all the elemts are empty lists.
What is my code doing wrong?
When you adding x to resultdata it not produces the copy of x, x just becomes an element of resultdata.
Then you have 2 options for accessing x data:
Using given name x
Get it from resultdata by index
So when you call x.clear() after resultdata.add(x) it's the same as calling resultdata.last.clear().
The right solution is adding a copy of x([...x]) to resultdata:
resultdata.add([...x]);
x.clear();
I'm working on a friend suggestion algorithm for a flutter social media application. I'm still an amateur when it comes to Dart so I'm stuck on the following line of code:
class FriendSuggestionAlgorithm {
User friendSuggestion(User user) {
int max = -1;
User suggestion;
Map<User, int> map = new HashMap();
for (User friend in user.friends) {
for (User mutualFriend in friend.friends) {
if (mutualFriend.id != user.id && !user.friends.contains(mutualFriend)) {
map.putIfAbsent(mutualFriend, map.getOrDefault(mutual, 0) + 1);
}
}
}
for (MapEntry<User, int> mutualFriend in map.entries) {
if (mutualFriend.value > max) {
max = mutualFriend.value;
suggestion = mutualFriend.key;
}
}
return suggestion;
}
}
map.getOrDefault is underlined (I know the method doesn't exist in Dart). Do you know what the equivalent is in Dart? (PS, I'm just translating Java code into Dart.
Any help is appreciated!
Your code doesn't make sense. map.putIfAbsent will do work only if the key doesn't exist, so the hypothetical map.getOrDefault call with the same key would always return the default value anyway. That is, your logic would be the equivalent of map.putIfAbsent(mutual, () => 1), where nothing happens if the key already exists.
Map.putifAbsent takes a callback as its argument to avoid evaluating it unless it's actually necessary. I personally prefer using ??= when the Map values are non-nullable.
I presume that you actually want to increment the existing value, if one exists. If so, I'd replace the map.putIfAbsent(...) call with:
map[mutual] = (map[mutual] ?? 0) + 1;
Also see: Does Dart have something like defaultdict in Python?
You could do it like this:
map.putIfAbsent(mutual, (map.containsKey(mutual) ? map[mutual] : 0) + 1)
Maybe take a look at this for more info: https://dart.dev/guides/language/language-tour#conditional-expressions
Edit:
This code should work
class FriendSuggestionAlgorithm {
User? friendSuggestion(User user) {
int max = -1;
User? suggestion;
Map<User, int> map = {};
for (User friend in user.friends) {
for (User mutualFriend in friend.friends) {
if (mutualFriend.id != user.id && !user.friends.contains(mutualFriend)) {
map.putIfAbsent(mutualFriend, () => (map[mutualFriend] ?? 0) + 1);
}
}
}
for (MapEntry<User, int> mutualFriend in map.entries) {
if (mutualFriend.value > max) {
max = mutualFriend.value;
suggestion = mutualFriend.key;
}
}
return suggestion;
}
}
Note that suggestion nullable because it could happen that suggestion is never assigned. And therefore friendSuggestion(user) can return null;
To come back to your question
the correct code is
map.putIfAbsent(mutualFriend, () => (map[mutualFriend] ?? 0) + 1);
My mistake on my original answer, the ifAbsent part of this is a function. In the function the value of mutualFriend is retrieved. If that is null use 0.
I have a function which creates a sublist from a large(very large list). After creating this list, the function goes on treating it (deleting duplicates, sorting...).
As long as the list was not too big, it worked fine. But now, I get "The Getter length was called on null". I suppose, it's because the second part of the function (after the loop) starts before the sublist is completed... so it doesn't work...
How can we force the function to wait for the loop to be over to continue the rest of the treatment ?
Is it with Async /Await ? Or can we do something like "While... something is not over...", or "As soon as something is done... do that" ? (My suggestions might be naive, but I am a beginner...)
Here is the code :
List themeBankFr() {
List<Map> themeBankFr = [];
for (Word word in wordBank) {
for (Thematique wordTheme in word.theme) {
themeBankFr.add({
'themeFr': wordTheme.themeFr,
'image': wordTheme.image,
});
}
}
// convert each item to a string by using JSON encoding
final jsonList = themeBankFr.map((item) => jsonEncode(item)).toList();
// using toSet - toList strategy
final uniqueJsonList = jsonList.toSet().toList();
// convert each item back to the original form using JSON decoding
final result = uniqueJsonList.map((item) => jsonDecode(item)).toList();
// sort the list of map in alphabetical order
result.sort((m1, m2) {
var r = m1['themeFr'].compareTo(m2['themeFr']);
if (r != 0) return r;
return m1['image'].compareTo(m2['image']);
});
return result;
}
i think i have a good answer that may helps you and it will as following
first create another function to do the work of for loops and this function returns a future of list that you need like below
Future<List<Map>> futureList(List wordBank){
List<Map> themeBankFr = [];
for (Word word in wordBank) {
for (Thematique wordTheme in word.theme) {
themeBankFr.add({
'themeFr': wordTheme.themeFr,
'image': wordTheme.image,
});
}
}
return Future.value(themeBankFr);
}
after that you can use this function inside your code and use it as async await and now you will never run the below lines before you return this array like below
List themeBankFr() async {
List<Map> themeBankFr = await futureList(wordBank);
// convert each item to a string by using JSON encoding
final jsonList = themeBankFr.map((item) => jsonEncode(item)).toList();
// using toSet - toList strategy
final uniqueJsonList = jsonList.toSet().toList();
// convert each item back to the original form using JSON decoding
final result = uniqueJsonList.map((item) => jsonDecode(item)).toList();
// sort the list of map in alphabetical order
result.sort((m1, m2) {
var r = m1['themeFr'].compareTo(m2['themeFr']);
if (r != 0) return r;
return m1['image'].compareTo(m2['image']);
});
return result;
}
i think this will solve your problem and i hope this useful for you
This question already has answers here:
The default 'List' constructor isn't available when null safety is enabled. Try using a list literal, 'List.filled' or 'List.generate'
(4 answers)
Flutter: List is deprecated? [duplicate]
(4 answers)
Closed 1 year ago.
List has been deprecated. How do I re-write the following code?
RosterToView.fromJson(Map<String, dynamic> json) {
if (json['value'] != null) {
rvRows = new List<RVRows>();
json['value'].forEach((v) {
rvRows.add(new RVRows.fromJson(v));
});
}
}
According to the official documentation:
#Deprecated("Use a list literal, [], or the List.filled constructor instead")
NOTICE: This constructor cannot be used in null-safe code. Use List.filled to create a non-empty list. This requires a fill value to initialize the list elements with. To create an empty list, use [] for a growable list or List.empty for a fixed length list (or where growability is determined at run-time).
You can do this instead:
RosterToView.fromJson(Map<String, dynamic> json) {
if (json['value'] != null) {
rvRows = <RVRows>[];
json['value'].forEach((v) {
rvRows.add(new RVRows.fromJson(v));
});
}
}
Another option is:
List<RVRows> rvRows = [];
Instead of:
rvRows = new List();
Write:
rvRows = [];
The error message tells you what to do. When I run dart analyze, I get:
info • 'List' is deprecated and shouldn't be used. Use a list literal, [],
or the List.filled constructor instead at ... • (deprecated_member_use)
Try replacing the use of the deprecated member with the replacement.
error • The default 'List' constructor isn't available when null safety is
enabled at ... • (default_list_constructor)
Try using a list literal, 'List.filled' or 'List.generate'.
The documentation for the zero-argument List constructor also states:
This constructor cannot be used in null-safe code. Use List.filled to create a non-empty list. This requires a fill value to initialize the list elements with. To create an empty list, use [] for a growable list or List.empty for a fixed length list (or where growability is determined at run-time).
Examples:
var emptyList = [];
var filledList = List<int>.filled(3, 0); // 3 elements all initialized to 0.
filledList[0] = 0;
filledList[1] = 1;
filledList[2] = 2;
var filledListWithNulls = List<int?>.filled(3, null);
var generatedList = List<int>.generate(3, (index) => index);
You also could use collection-for for both cases:
var filledList = [for (var i = 0; i < 3; i += 1) 0];
var filledListWithNulls = <int?>[for (var i = 0; i < 3; i += 1) null];
var generatedList = [for (var i = 0; i < 3; i += 1) i];
I am using For loop to iterate over a table. When a certain condition is met against a row, I will break from for loop. But as per my code, FOR seems to run asynchronously causing iteration in parallel which I do not intend my program to do. Can someone help in working with this problem which I assume is due to promise resolution.
element.all(by.css('tbody tr')).then(function(rows){
for(var i = 1; i < (rows.length); i++) {
var count=0;
var pass=0;
//TEST VALUES BELOW
var appNameCreated="Test App 534";
//TEST VALUES ABOVE
console.log(i);
element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)')).getText().then(function(appname){
console.log(i,appname);
if(appname==appNameCreated){
console.log(appname,appNameCreated,i);
element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(6)')).getText().then(function(result){
console.log(result,i);
// if (result==data.resultSubmit){
if (result=="Activated"){
pass += 1;
element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)')).element(by.css('a')).click().then(function(){
browser.sleep(4000);
});
element(by.id("btnTab3")).element(by.xpath('span')).click();
browser.wait(EC.visibilityOf(element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr[1]/td[1]'))),15000); browser.wait(EC.visibilityOf(element(by.id("button-basic"))),15000);
browser.wait(EC.visibilityOf(element(by.id("button-basic"))),15000);
element(by.id("button-basic")).click();
element.all(by.css('ul[class="dropdown-menu"]')).each(function(item1){
item1.element(by.css('li:nth-child(7)')).element(by.css('a')).click();
})
element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+i+']')).element(by.css('td:nth-child(6)')).getText().then(function(resultFin){
console.log(resultFin);
browser.actions().mouseMove(element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)'))).perform();
expect(resultFin).toBe(data.resultFinal);
})
}
})
}
})
if(pass==1){
break;
}
}
})
You can use Array-like object's reduce() to iterate the rows and use Promise.reject() once the row meet your condition to break the loop.
Because you reject the promise, you should use Promise.catch() to capture it, and click the matched row to enter next page and do operations , then back to table page inside the catch()
let appName = 'Test App 534',
tbl = element(by.xpath(
'/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table')),
rows = tbl.all(by.css('tbody > tr'));
rows.reduce((initValue, row, rowIndex)=>{
return row.all(by.css('td:nth-child(1),td:nth-child(6)'))
.getText()
.then((txts)=>{
console.log('row ' +rowIndex+ ', txts: ' + txts)
if(txts[0] === appName && txts[1] === 'Activated') {
console.log('this is matched row');
// when the row meet the condition
// reject a promise with the row index of matched row.
// Promise.reject() will break out the loop
// and code will run into the following catch() section
return Promise.reject(rowIndex);
}
})
}, -1)
.catch((rowIndex)=>{
// use catch() to obtains the row index of matched row via
// Promise.reject(rowIndex) in previous rows.reduce()
console.log('matched row:' + rowIndex);
// click on matched row to enter next page
rows.get(rowIndex).element(by.css('td:nth-child(1) > a')).click();
browser.sleep(4000);
// do other operations and back to the table page
...
return rowIndex;
// still return the rowIndex for as argument for
// the following then() which we will check
// the status of matched row is still Activated
})
.then((rowIndex)=>{
console.log('matched row2:' + rowIndex);
console.log("Check matched row's status is still 'Activated'")
let status = rows.get(rowIndex).element(by.css('td:nth-child(6)')).getText();
expect(status).toEqual('Activated');
return browser.sleep(5000)
})
Update your code:
- change promise resolving using async ... await
- change var to let, const
- counting in a loop should begin from 0 instead of 1
- change == to ===
- .each() does not work properly with async operations as click()
Questions:
- from where you take data.resultSubmit ?
const rows = await element.all(by.css('tbody tr'));
const appNameCreated = "Test App 534";
let count = 0;
let pass = 0;
for (let i = 0; i < rows.length; i++) {
console.log('Index is ', i);
const appname = await element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)')).getText();
console.log('App name for current loop is ', appname);
if(appname === appNameCreated) {
console.log('App name is the same as created app name for loop with index ', i);
const result = await element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(6)')).getText();
console.log('Result for current run is ' result);
if (result === data.resultSubmit && result === "Activated") {
pass += 1;
await element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)')).element(by.css('a')).click();
await browser.sleep(4000);
});
await element(by.id("btnTab3")).element(by.xpath('span')).click();
await browser.wait(EC.visibilityOf(element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr[1]/td[1]'))),15000);
await browser.wait(EC.visibilityOf(element(by.id("button-basic"))),15000);
await browser.wait(EC.visibilityOf(element(by.id("button-basic"))),15000);
await element(by.id("button-basic")).click();
const menus = await element.all(by.css('ul[class="dropdown-menu"]'));
const amount = await menus.count();
for (let i = 0; i < amount; i++) {
const item = await menus.get(i);
await item.element(by.css('li:nth-child(7)')).element(by.css('a')).click();
}
const resultFin = await element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+i+']')).element(by.css('td:nth-child(6)')).getText();
console.log('resultFin is ', resultFin);
await browser.actions().mouseMove(element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)'))).perform();
expect(resultFin).toBe(data.resultFinal);
})
}
})
}
})
if(pass ===1 ){
break;
}
}
})
I have tried to remove as much mistakes as I can. Your code is bad because you don't split this BIG amount of "What a hell is there???" to smaller functions.