Value returning from an async function is not the actual value - string

I'm calling an async function that has the file path as a parameter and reads and displays the content in the file.
this is the place where I'm invoking the function.
this is the function.
After reading the contents in the file, the data is printed in the console.
But when I try to use the same value to display in the emulator I'm getting error.
Why actual string value is not returned from the function??
error.

readContent is a future method, you need to wait to complete the fetching.
For future method, try using FutureBuilder.
late Future future = readContent();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text("${snapshot.data}");
}
return CircularProgressIndicator();
},
),
);
}
Find more about using FutureBuilder.

An async function in dart can only return a Future.
Your readContent function signature doesn't declare a return value:
readContent(String path) async {
var result = await File(path).readAsString();
print(result);
return result
}
If you explicitly declare the return value as String you'll get a compilation error. Async methods can only return a future:
Future<String> readContent(String path) async {
var result = await File(path).readAsString();
print(result);
return result
}
The await keyword allows you to access the value returned by a Future, it is not the same as calling the function synchronously.
The only reason you need the await keyword in your code is because you're printing the value to console when the Future completes. You could do this instead, which is the same function without printing to console and without async await.
readContent(String path) {
return File(path).readAsString();
}
To address the issue described in your question, you might call readAsString synchronously:
readContent(String path) {
return File(path).readAsStringSync();
}
Or use await on the calling side
var val = await readContent(path);
Or
var txt = "";
readContent(path).then((value) {
txt = value;
setState(() {});
});
Or use the FutureBuilder widget

Related

TS decorator to wrap function definition in try catch

Is it possible to use TS decorator to wrap a function definition into a try-catch block. I don't want to use try-catch in every function so I was thinking maybe decorators can help.
For example
function examleFn(errorWrapper: any) {
try{
// some code
} catch (err) {
errorWrapper(err)
}
}
Something like this can be done in a decorator so that it can be used for other functions too.
No, you cannot decorate functions.
TypeScript's implementation of decorators can only apply to classes, class methods, class accessors, class properties, or class method parameters. The relevant proposal for JavaScript decorators (at Stage 3 of the TC39 Process as of today, 2022-07-21) also does not allow for decorating functions.
Function decorators are mentioned as possible extensions to the decorator proposal, but are not currently part of any proposal for either TypeScript or JavaScript.
You can, of course, call a decorator-like function on another function, but this is just a higher-order function and not a decorator per se, and it won't affect the original function declaration:
const makeErrorWrapper = <T,>(errorHandler: (err: any) => T) =>
<A extends any[], R>(fn: (...a: A) => R) =>
(...a: A): R | T => {
try {
return fn(...a);
} catch (err) {
return errorHandler(err);
}
};
The makeErrorWrapper function takes an error handler and returns a new function that wraps other functions with that error handler:
const errToUndefined = makeErrorWrapper(err => undefined);
So now errToUndefined is a function wrapper. Let's say we have the following function which throws errors:
function foo(x: string) {
if (x.length > 3) throw new Error("THAT STRING IS TOO LONG");
return x.length;
}
// function foo(x: string): number
If you call it directly, you can get runtime errors:
console.log(foo("abc")); // 3
console.log(foo("abcde")); // 💥 THAT STRING IS TOO LONG
Instead you can wrap it:
const wrappedFoo = errToUndefined(foo);
// const wrappedFoo: (x: string) => number | undefined
Now wrappedFoo is a new function that behaves like foo and takes the same parameter list as foo, but returns number | undefined instead of just number:
console.log(wrappedFoo("abc")) // 3
console.log(wrappedFoo("abcde")) // undefined
Playground link to code
maybe this can help you, it took me a long time to do it, but here it is
function Execpetion (methodName: string) {
return (target: any, nameMethod: string, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value
descriptor.value = async function (...args: any[]) {
try {
const executionMethod = await originalMethod.apply(this, args)
return executionMethod
} catch (error) {
return errorWrapper(error as Error)
}
}
}
}
in your class
class TestController {
#Execpetion('TestController')
public async handler (teste: any) {
return {
statusCode: 200,
data: 'nothing'
}
}
}
with the parent function, you can modify and add to receive the errorPersonalized and instantiated type parameter... and on the return put it

how to implement string list from _ListItem to assetPath?

i've been working with wallpaper app.
i manage to call the path list for wallpaper,
i can make this work on image card list but i can't manage to do it work with assetPath for WallpaperManager
Please help, is there any way to do it?
Future<void> setWallpaperFromAsset() async {
setState(() {
_wallpaperAsset = "Loading";
});
String result;
String assetPath = ('Load List here');
You can add a parameter assetPath to setWallpaperFromAsset
Future<void> setWallpaperFromAsset(String assetPath) async {
setState(() {
_wallpaperAsset = "Loading";
});
String result;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await WallpaperManager.setWallpaperFromAsset(
assetPath, WallpaperManager.HOME_SCREEN);
} on PlatformException {
result = 'Failed to get wallpaper.';
}
}
And you register the onPressed callback with:
RaisedButton.icon(
onPressed: () => setWallpaperFromAsset(item),
icon: Icon (Icons.wallpaper, size: 20),
label: Text('homescreen')),
)

Get text from ".txt" file and save it in String variable dart

I have a ".txt" file called "bio.txt" inside the Document folder of my application.
I want to read its content and store it inside a String variable.
My problem is that the "reading action" is a "Future" function and I have some troubles to save its value in a "String".
I read the file with :
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> _localFile(String name) async {
final path = await _localPath;
return File('$path/$name');
}
Future<String> _read(String filename) async {
try {
final file = await _localFile(filename);
// Read the file.
return await file.readAsString();
} catch (e) {
// If encountering an error, return 0.
return "Can't read";
}
}
And I would like to save it with :
String _bio = _read("bio.txt").then((value) => String);
Do you know why this solution isn't working?
Any suggestion?
Because the then of Futures won't return a value, it should be like this,
var _bio;
_read("bio.txt").then((value) {
_bio = value;
});
or by making the context _bio is in to an asynchronous one,
var _bio = await _read("bio.txt");
You can either use a then block or use the async/await
_read ('file.txt').then((value){
bio = value;
});
Or:
bio = await _read ('file.txt');
This is my solution :
String _myRead( String filename){
var _bio;
_read("bio.txt").then((String) {
_bio = String;
});
return _bio;
}
String _bio=_myRead("bio.txt");

Return String from Future Object

I am trying to fetch html page via localproxy to parse and get urls from it. I can't find any library which works without Future in Dart. So i have difficulty returning String from a Future Object. Below is full code of dart file.
import 'package:universal_html/driver.dart';
import 'package:universal_html/prefer_universal/html.dart';
String proxyUrl='http://localhost/php-proxy/index.php?q=';
String hallTicketUrl='http://www.ignou.ac.in/ignou/studentzone/results/6';
Future<String> getList()async{
final driver = HtmlDriver();
await driver.setDocumentFromUri(Uri.parse(proxyUrl+hallTicketUrl));
final items = driver.document.querySelectorAll('.middleconten2column a');
Element urls=Element.tag('urls');
items.forEach((item)=>urls.append(Element.tag('url')
..setAttribute('href',item.getAttribute('href'))
..text=item.text
)
);
print('${items.length} items found');
return Future.value(urls.outerHtml);
}
String Handler(String app){
switch(app){
case 'list': return getList() as String;
}
return "";
}
main(){
print(Handler('list'));
}
I think you have misunderstood what the async keyword does to methods. When a method are marked as async it will always automatically returns a Future of something. That is the reason why you need to specify e.g. Future<String> as the return type.
But because the creation are done "automatically" you don't really need to do the following:
return Future.value(urls.outerHtml);
But can just do:
return urls.outerHtml;
After this your have discovered the problem with using asynchronous programming where everything in your call stack needs to be marked as async since you have an await somewhere in your code.
I have fixed your code so it now hope it works correctly with all the future stuff:
import 'package:universal_html/driver.dart';
import 'package:universal_html/prefer_universal/html.dart';
String proxyUrl = 'http://localhost/php-proxy/index.php?q=';
String hallTicketUrl = 'http://www.ignou.ac.in/ignou/studentzone/results/6';
Future<String> getList() async {
final driver = HtmlDriver();
await driver.setDocumentFromUri(Uri.parse(proxyUrl + hallTicketUrl));
final items = driver.document.querySelectorAll('.middleconten2column a');
Element urls = Element.tag('urls');
items.forEach((item) => urls.append(Element.tag('url')
..setAttribute('href', item.getAttribute('href'))
..text = item.text));
print('${items.length} items found');
return urls.outerHtml;
}
Future<String> Handler(String app) async {
switch (app) {
case 'list':
return await getList();
}
return "";
}
main() async {
print(await Handler('list'));
}

passing function to a class in nodejs

I have a function that I need to pass to a class I have defined in nodeJs.
The use case scenario is I want to give the implementer of the class the control of what to do with the data received from createCall function. I don't mind if the method becomes a member function of the class. Any help would be appreciated.
//Function to pass. Defined by the person using the class in their project.
var someFunction = function(data){
console.log(data)
}
//And I have a class i.e. the library.
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall(){
var result = new Promise (function(resolve,reject) {
resolve(callApi());
});
//doesn't work. Keeps saying notificationHandler is not a function
result.then(function(resp) {
this.notificationHandler(resp);
}) ;
//I want to pass this resp back to the function I had passed in the
// constructor.
//How do I achieve this.
}
callApi(){ ...somecode... }
}
// The user creates an object of the class like this
var obj = new A("abc#gmail.com", someFunction);
obj.createCall(); // This call should execute the logic inside someFunction after the resp is received.
Arrow functions (if your Node version supports them) are convenient here:
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall() {
var result = new Promise(resolve => {
// we're fine here, `this` is the current A instance
resolve(this.callApi());
});
result.then(resp => {
this.notificationHandler(resp);
});
}
callApi() {
// Some code here...
}
}
Inside arrow functions, this refers to the context that defined such functions, in our case the current instance of A. The old school way (ECMA 5) would be:
createCall() {
// save current instance in a variable for further use
// inside callback functions
var self = this;
var result = new Promise(function(resolve) {
// here `this` is completely irrelevant;
// we need to use `self`
resolve(self.callApi());
});
result.then(function(resp) {
self.notificationHandler(resp);
});
}
Check here for details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

Resources