How to asynchronously call JavaScript in Flutter? - flutter

I have a flutter web where i have a JavaScript function like this:
async function doSomething(value) {
let x = await something(x);
return x
}
When I'm now in dart, I have:
final result = await js.context.callMethod('doSomething', ['someValue']));
This returns [object Promise] when I print it, but it does ignore await, does not have a .then function and is therefore not working with promiseToFuture either.
How can I wait for JavaScript to be executed?

Just await doesn't work for js.context.callMethod.
This must be added somewhere in your code, maybe like javascript_controller.dart
#JS()
library script.js;
import 'package:js/js.dart';
import 'dart:js_util';
#JS()
external dynamic doSomething();
and then
Future getSomething(String someValue) async {
var result = await promiseToFuture(doSomething());
return result;
}

Maybe use a Future builder to wait for JS to execute?
Future getSomething(String someValue) async {
var result = await js.context.callMethod('doSomething', [someValue]));
return result;
}
FutureBuilder(
future: getSomething(someValue),
builder: (context, snapshot) {
if (snapshot.hasData) {
var data = snapshot.data;
print(data);
} else {
return Loading();
}
});

Place it in index.html
<script src="script.js" defer></script>
In Script.js
async function showAlert(href,hashtag,quote) {
if (response) {
window.dartFunc("asd");
dartFunc("asd");
} else if () {
alert("error adding points");
}
else{
alert("error dialog close");
}
});
};
In your dart file in initstate()
setProperty(window, 'dartFunc', js.allowInterop(dartFunc));
sss() async {
await js.context.callMethod('showAlert', [
'',
'',
''
]);
}
String dartFunc(String str) {
Common.showToast('Music');
Common.showToast(str);
return 'Inside dartFunc: ' + str;
}

I tried the same method to do asynchronously from js file using async and used --promisetofuture in dart file but i am unable to wait until we get response from js file for flutter web
async function getPhoneNumber() {
let res = await someFunction to wait for someTime;
return res;
}
function somfunc() async{
var number = await
promiseToFuture(js.context.callMethod('getPhoneNumber'));
}

Related

Pass token between future classes in flutter

I been reading multiple threads about passing data between futures, but for some reason I can get this to work.:(
I have two futures, where the first future is doing post request to retrieve a token
Future<AuthStart> fetchAuthStart() async {
final response = await http.post(
Uri.parse('http://ipsum.com/auth/start'),
body: jsonEncode(<String, String>{
'IdNumber': '198805172387',
}));
if (response.statusCode == 200) {
final responseJson = jsonDecode(response.body);
return AuthStart.fromJson(responseJson);
} else {
throw Exception("Failed");
}
}
this request will generate an GUID that I need in my next future
Future<AuthStatus> fetchAuthStatus(String token) async {
final response = await http.post(Uri.parse('http://ipsum/auth/status'),
body: jsonEncode(<String, String>{
'Token':token,
}),
);
if (response.statusCode == 200) {
return AuthStatus.fromJson(jsonDecode(response.body));
} else {
throw Exception("Failed");
}
}
I have tried multiple ways, one that worked was to pass the variable in my FutureBuilder like this
FutureBuilder(
future: futureAuthStart,
builder: (context, snapshot) {
if (snapshot.hasData) {
fetchAuthStatus(snapshot.data!.Token);
return Text(snapshot.data!.Token);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
But this does not make sense?
I would rather pass it in my InitState something like this.
void initState() {
super.initState();
futureAuthStart = fetchAuthStart();
futureAuthStatus = fetchAuthStatus(token);
}
Am I totally on the wrong path? Any tutorials out there that can give better info :)?
Thanks in advance.
Create a void function and pass it the functions and one at a time it will be executed with async/await. You should take a look at Asynchronous programming: futures, async, await.
void initState() {
super.initState();
_onInit();
}
void _onInit() async {
try {
var futureAuthStart = await fetchAuthStart();
var futureAuthStatus = await fetchAuthStatus(futureAuthStart.data.token);
}catch(e, stackTrace){
//handler error
print(e);
print(stackTrace);
}
}

Dart return Future.value is always null

I am trying to build a URL from a Firebase Storage file but the Future<String> I have built always seems to return null. This is the Future I am calling:
Future<String> getUrlFromStorageRefFromDocumentRef(
DocumentReference docRef) async {
try {
docRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
String filename = documentSnapshot.get('file');
firebase_storage.Reference ref = firebase_storage
.FirebaseStorage.instance
.ref()
.child('/flamelink/media/$filename');
if (ref == null) {
return Future.error("Storage Reference is null");
} else {
print(ref.fullPath);
return Future.value(
'https://storage.googleapis.com/xxxxxxxxx.appspot.com/${ref.fullPath}');
}
} else {
return Future.error('No Snapshot for DocumentReference ${docRef.id}');
}
});
} catch (e) {
print(e);
return Future.error('No DocumentReference for ID ${docRef.id}');
}
}
The line in question is :
return Future.value(
'https://storage.googleapis.com/xxxxxxxxx.appspot.com/${ref.fullPath}');
It's worth noting that the String is generated from the Firebase Storage path and everything looks perfect until it comes to return the value.
It should return the String value back to my calling code which at the moment looks like this:
DocButtonCallback docCallback = () async {
bool isKidsDoc = item.screenId == StringsManager.instance.screenIdKids;
try {
// first we need to get the URL for the document ...
var url = await AssetManager.instance
.getUrlFromStorageRefFromDocumentRef(isKidsDoc
? feature.relatedDocumentKidsRef
: feature.relatedDocumentRef);
String urlString = url.toString();
canLaunch(urlString).then((value) {
launch(urlString);
}).catchError((error) {
// TODO: open alert to tell user
});
} catch (error) {
print(error);
}
};
I have tried many different ways to get that String including:
DocButtonCallback docCallback = () async {
bool isKidsDoc = item.screenId == StringsManager.instance.screenIdKids;
await AssetManager.instance
.getUrlFromStorageRefFromDocumentRef(isKidsDoc
? feature.relatedDocumentKidsRef
: feature.relatedDocumentRef)
.then((urlString) {
canLaunch(urlString).then((value) {
launch(urlString);
}).catchError((error) {
// TODO: open alert to tell user
});
}).catchError((error) {
// TODO: open alert to tell user
});
};
For some reason, the Future always returns null. What am I doing wrong here?
You are returning the Future value inside the then() callback, which essentially returns this value from the callback itself rather than from your getUrlFromStorageRefFromDocumentRef() function. There you should only need to add a return statement before that:
Current:
docRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
...
After:
/// Adding the return statement here to return the actual value
/// returned internally by the then callback
return docRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
...
If you hover over the then() callback, your IDE should show you that this callback will return Future<T> (or whatever generic type placeholder) which need to be returned as well in order to make it available

Return String from a Future function

How can i return a string from a future function?
Future<String> functionA() async {
var x = await fetchX();
return x;
}
Future<String> fetchX() {
return Future.delayed(Duration(seconds: 4), () => 'example');
}
Future<String> la() async {
print(await functionA()); //this works correctly
return await functionA(); //this return always an instance of Future
}
How can i return "example" from the future function, there is a method to do it, and where is my error?
Future<String> fetch() async {
return
http.get('url')
.then((response) => response.body);
}
That way you can sneak a .catchError into there. :)
You need to specify what your function will return. All you have to do is add Future to the beginning of the method.
Future<String> fetch() async {
final response = await http.get('url');
String conteggio = response.body;
return conteggio;
}
And you have to do this in a method. You can only assign constant values in fields other than methods.

Race condition with stream listen

I have an async function like below. However content is being returned null well before the stream listening is done.
I started playing out with Future.delayed, but thought better of it and wanted to ask if there is a better approach to ensure this is async?
import 'package:googleapis/drive/v3.dart' as ga;
static Future<String> getContentsFromFile() async {
String content;
ga.Media mediaResponse = await drive.files.get(fileId);
mediaResponse.stream.listen((data) {
print("DataReceived: "+data);
content = data
}, onDone: () async {
print("Task Done");
}, onError: (error) {
print("Some Error");
});
return content;
}
Im calling the function like so..
String content = await getContentsFromFile();
EDIT: Made the example more complete, with handling of errors and partial content.
You can use Completer for this sort of control flow:
import 'dart:async';
import 'package:googleapis/drive/v3.dart' as ga;
static Future<String> getContentsFromFile() async {
Completer<String> completer = Completer();
String content = "";
ga.Media mediaResponse = await drive.files.get(fileId);
mediaResponse.stream.listen((data) {
print("DataReceived: "+data);
content += data;
}, onDone: () async {
print("Task Done");
completer.complete(content);
}, onError: (error) {
print("Some Error");
completer.completeError(error);
});
return completer.future;
}

Async function doesn't await

I'm trying to upload an image to firebase storage but when I called the function, await is not executed to get the url. What am I missing in this?
Looking at this other topic I've got that the problem may be the "then", but how can I set the code to await the url?
Async/Await/then in Dart/Flutter
Future < String > uploadImage(File imageFile) async {
String _imageUrl;
StorageReference ref =
FirebaseStorage.instance.ref().child(firebaseUser.uid.toString());
await(ref.putFile(imageFile).onComplete.then((val) {
val.ref.getDownloadURL().then((val) {
_imageUrl = val;
print(val);
print("urlupload");
});
}));
print(_imageUrl);
print("urlnoupload");
return _imageUrl;
}
Thanks!
you had async/await when you didn't need it because you were capturing value in the then function
Future<String> uploadImage(File imageFile) async {
String _imageUrl;
StorageReference ref = FirebaseStorage.instance.ref().child(firebaseUser.uid.toString());
return ref.putFile(imageFile).onComplete.then((val) {
return val.ref.getDownloadURL()
}).then((_imageUrl) {
return _imageUrl;
});
},