Flutter - Async method in Navigator callback refresh screen - async-await

I have a Navigator.push like this:
Navigator.pushNamed(context, "NovoCNPJ").then((value) {
setState(() {
setupList();
});
});
And i need to update my list variable with this setState, my setupList method:
setupList() async {
var banco = await db.initDB();
list = await banco.rawQuery('SELECT * FROM Empresa');
return list;
}
This method is async and so I think it is not running on this code. When i come back from the last screen, the setupList should be activated and reloaded my list with the new item, but the method isn't called.

If async is the problem, Can you try this ?
Navigator.pushNamed(context, "NovoCNPJ").then((value) async {
var banco = await db.initDB();
var tempList = await banco.rawQuery('SELECT * FROM Empresa');
setState(() {
list = tempList
});
});
EDIT:
Navigator.pushNamed(context, "NovoCNPJ").then((value) async {
var banco = await db.initDB();
var tempList = await banco.rawQuery('SELECT * FROM Empresa');
setState(() {
list = new List();
listArray = new List();
list = new List.from(tempList);
});
});

Related

How can I throwError with an rxjs Observable in this case?

I have code like this:
loadImageFile(url: string, progressCallback: (progress: number) => void): Observable<string> {
return new Observable<string>(observer => {
const xhr = new XMLHttpRequest();
const nativeWindow = this.windowRef.nativeWindow;
let notifiedNotComputable = false;
xhr.open("GET", url, true);
xhr.responseType = "arraybuffer";
xhr.onprogress = event => {
if (event.lengthComputable) {
const progress: number = (event.loaded / event.total) * 100;
progressCallback(progress);
} else {
if (!notifiedNotComputable) {
notifiedNotComputable = true;
progressCallback(-1);
}
}
};
xhr.onloadend = function() {
if (!xhr.status.toString().match(/^2/)) {
// Here I want that the user of the Observable created at the top with
// "return new Observable" can use "pipe(catchError(...))".
}
if (!notifiedNotComputable) {
progressCallback(100);
}
const options: any = {};
const headers = xhr.getAllResponseHeaders();
const m = headers.match(/^Content-Type:\s*(.*?)$/im);
if (m && m[1]) {
options.type = m[1];
}
const blob = new Blob([this.response], options);
observer.next((nativeWindow as any).URL.createObjectURL(blob));
observer.complete();
};
xhr.send();
});
}
How can I make the xhr.onloadend act so the Observable returned by this loadImageFile method will throwError?
I believe my issue is that I am already inside new Observable, while it's the main function loadImageFile that should return throwError.
How can I overcome this?
PS: Please ignore this text: StackOverflow won't let me post this because it's mostly code, but in this case, I believe it makes sense, so I'm just writing this paragraph here to make the post validation pass :)
Thanks!
Here's the solution:
observer.error(xhr)

How to start a new thread in channel with a Proactive Channel Dialog?

My bot can create a new thread in a channel like this. Now I want to start a proactive dialog in this new thread. I am starting the dialog in a subsequent ContinueConversationAsync callback. The dialog seems to start, but as soon as a user is prompted, the users reply is not handled by the dialog but the MainDialog.
If I initiate the dialog with a user sent activity, then the dialog handles prompts correctly. Only the proactive dialog does not seem to work in a newly created channel.
This is my code
var conversationParameters = new ConversationParameters
{
IsGroup = true,
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo(teamsChannelId)
},
Activity = (Activity)message
};
ConversationReference newConversationReference = null;
await adapter.CreateConversationAsync(
teamsChannelId,
serviceUrl,
credentials,
conversationParameters,
(t, c) =>
{
newConversationReference = t.Activity.GetConversationReference();
return Task.CompletedTask;
}, cancellationToken);
await adapter.ContinueConversationAsync(
_appId,
newConversationReference,
async (t, c) =>
{
var dialogStateAccessor = this.conversationState.CreateProperty<DialogState>(nameof(DialogState));
var dialogState = await dialogStateAccessor.GetAsync(t, () => new DialogState());
var dialogSet = new DialogSet(dialogStateAccessor);
dialogSet.Add(dialog);
var dialogContext = await dialogSet.CreateContextAsync(t, cancellationToken);
await dialogContext.BeginDialogAsync(dialog.Id, options, cancellationToken);
await conversationState.SaveChangesAsync(t, false, cancellationToken);
},
cancellationToken);
Any ideas?
My Problem was that I took the ConversationReference from the the callback of the newly created channel post and tried to use that in ContinueConverationAsync(). That ConversationReference however is not enough. So I merged my original ConversationReference with the new ConversationReference and used that instead. Now it works like a charm.
Here is my updated code:
ConversationReference newConversationReference = null;
await adapter.CreateConversationAsync(
conversationChannelId,
serviceUrl,
credentials,
conversationParameters,
(t, c) =>
{
newConversationReference = t.Activity.GetConversationReference();
return Task.CompletedTask;
}, cancellationToken);
if (dialog != null)
{
// Proactive channel dialogs dont seem to work with the newConversationReference: responses to the dialog are handled by the MainDialog.
// So I just create a new ConversationReference from the topic subscription and the new conversation. That works.
var newNewConversationReference = new ConversationReference
{
ActivityId = newConversationReference.ActivityId,
Bot = conversationReference.Bot,
ChannelId = conversationReference.ChannelId,
ServiceUrl = conversationReference.ServiceUrl,
User = conversationReference.User,
Conversation = new ConversationAccount
{
Id = newConversationReference.Conversation.Id,
AadObjectId = conversationReference.Conversation.AadObjectId,
ConversationType = conversationReference.Conversation.ConversationType,
IsGroup = conversationReference.Conversation.IsGroup,
Name = conversationReference.Conversation.Name,
Properties = conversationReference.Conversation.Properties,
TenantId = conversationReference.Conversation.TenantId,
Role = conversationReference.Conversation.Role,
},
};
await adapter.ContinueConversationAsync(
_appId,
newNewConversationReference,
async (t, c) =>
{
var dialogStateAccessor = this.conversationState.CreateProperty<DialogState>(nameof(DialogState));
var dialogState = await dialogStateAccessor.GetAsync(t, () => new DialogState());
var dialogSet = new DialogSet(dialogStateAccessor);
dialogSet.Add(dialog);
var dialogContext = await dialogSet.CreateContextAsync(t, cancellationToken);
await dialogContext.BeginDialogAsync(dialog.Id, options, cancellationToken);
await conversationState.SaveChangesAsync(t, false, cancellationToken);
},
cancellationToken);
}

JavaScript - How to pass a variable from one async function to another?

I have spent a good few hours on trying to figure this out but drawing a blank.
I need to pass an array from one async function to another. Problem is, I am very new to this whole async/await world.
My code is below. I need to pass elems to the step2 function
var selenium = require('selenium-webdriver');
var Builder = selenium.Builder;
var By = selenium.By;
var Key = selenium.Key;
var util = selenium.util;
var firefox = require('selenium-webdriver/firefox');
var http = require('http');
var querystring = require('querystring');
async function startBot() {
var driver = await new Builder().forBrowser('firefox').build();
await driver.get('randomSite');
if(true){//Putting this here as it may have to do with scope. I am not sure
async function step1(){
for(var p=0; p <5 ; p++){//elems is undefined
var elem1 = await driver.findElement(By.xpath("/html/body/div/div[1]")).getText();
var elem2 = await driver.findElement(By.xpath("/html/body/div/div[2]")).getText();
var elems = [elem1, elem2]; //How do I pass this array to tge step2 funtion?
}
}
if(true){//Putting this here as it may have to do with scope. I am not sure
var char1 = 1;
var char2 = 2;
//button1
async function step2(){
for (var i = 0; i < 2; i++) {
if(elems[i] == char1){//elems is undefined
await driver.findElement(By.xpath("/html/body/div/div[" + i + "]")).click().then(function(res, err){
if(err){ reject(err); };
});
break;
}
}
}
await step1();
await step2();
}
}
};
startBot();
You can pass the elems array as a parameter to the step2 function. However, you have to do some modifications:
async function step1(){
for(var p=0; p <5 ; p++){
var elem1 = await driver.findElement(By.xpath("/html/body/div/div[1]")).getText();
var elem2 = await driver.findElement(By.xpath("/html/body/div/div[2]")).getText();
var elems = [elem1, elem2];
}
return step2(elems);
}
async function step2(elems){
for (var i = 0; i < 2; i++) {
if(elems[i] == char1){
await driver.findElement(By.xpath("/html/body/div/div[" + i + "]")).click().then(function(res, err){
if(err){ reject(err); };
});
break;
}
}
}
And only use await with the step1 function:
await step1();
That's because we returned another promise step2(elems) from the step1 function. Therefore, the await keyword will have to wait for both step1 and step2. Remember that when you call an asynchronous function you always get a promise.
Define elems outside the function.

How to get rid of 'return new Promise' and not to lose data?

In this case, there is nothing easier to wait until the data is received, and then resolve the Promise:
// Using Promise resolve/reject
module.exports = () => {
return new Promise(async (resolve, reject) => {
let doc = await Document();
doc.on('data', async (data) => {
resolve(data);
});
})
}
But what do I do in this case?
// Using async/await
module.exports = async () => {
let doc = await Document();
doc.on('data', (data) => {
// ???
});
}
You still need the new Promise, you just should use it as the operand of an await inside the async function, not using an async function as the executor:
module.exports = async () => {
const doc = await Document();
return new Promise(resolve, reject) => {
doc.on('data', resolve);
});
};
However, I would recommend to use once instead of on so that the event handler is removed after the first occurrence of the event - the promise can be resolve only once anyway. Also if you have node v11.13.0 or higher you can just use the events.once method so that you don't have to build the promise yourself - and it also handles error events correctly:
const { once } = require('events');
module.exports = async () => {
const doc = await Document();
return once(doc, 'data');
};

multiple Async/await JS function

In my controller, the fn function executes return.suucess() before my variables are properly defined. In this case, the ytb object.
The sails.log of "items" is correct, but "ytb" did not return.
I also tried with Promise.then, and .all. Also, with async.each() and removing the await inside this function.
fn: async function (inputs, exits) {
var url = require('url');
var items = await Collection.find({});
_.each(items, async item => {
if (item.youtube_url) {
var ytbUrl = item.youtube_url;
var regexBaseUrlYtb = new RegExp('(https://www.youtube.com/channel/)');
if (regexBaseUrlYtb.test(ytbUrl)) {
var ytbIdChannel = ytbUrl.replace(regexBaseUrlYtb, '');
var ytbChannel = await sails.helpers.youtubeApi(ytbIdChannel);
item.ytb = {};
Object.assign(item.ytb, ytbChannel);
}
}
sails.log('items: ', item)
});
return exits.success({
items
});
}
I expect that the ytb object will also be passed with the object item at the view, but the items object is passed without the ytb object.
Also, in general, I expect the return exits.success() runs only once the function finished
Thanks.

Resources