Since you can only return widgets in FutureBuilder I was wondering if there is a way to extract data from those widgets to modify it?
For example, is there a way to get to the "snapshot.data.value" here?
if (snapshot.hasData) {
return Text("${snapshot.data.value}");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
Here is my parent widget from which im trying to get snapshot.data.value:
Container(
child: FirstWidget(),
),
Container(
child: SecondWidget(),
),
Here is my child widget that returns following FutureBuilder:
#override
Widget build(BuildContext context) {
return FutureBuilder<Api>(
future: _apivalue,
builder: (context, snapshot) {
if (snapshot.hasData) {
Test(er: snapshot.data.er);
return Text("${snapshot.data.value}");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Text('');
},
);
}
}
Question is not clear but what i understand from your question is that you want to use the FutureBuilder data out side the widget. You can do that by storing the data inside a variable
var data; // Defined inside the state of widget as a local variable
if (snapshot.hasData) {
data = snapshot.data;
return Text("${snapshot.data.value}");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
Related
I have this error in my code before the { (builde:(context,snapshot)
buildSearchresult() {
return FutureBuilder(
future: searchresultfuture,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgress();
}
});
}
The builder must always return a widget. However, in your code, if the condition !snapshot.hasData is not satisfied, the builder returns null. So you should return a widget outside this condition:
buildSearchresult() {
return FutureBuilder(
future: searchresultfuture,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgress();
}
return Container(); // The widget containing your data
});
}
Possible duplicate.
You are returning widget only when you don't have data.
you need to return widget on every possible case, like
error
on data
no data
waiting
You can also simplify by returning default widget others state.
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
/// return your widget while loadling
} else if (snapshot.hasError) {
/// return your widget based on error
} else if (snapshot.hasData) {
/// return your widget while have data
} else if (!snapshot.hasData) {
/// return your widget while there is no data
} else {
/// return widget
}
},
You forgot return from your FutureBuilder().
The return you have is just for your if statement not FutureBuilder().
Use:
buildSearchresult() {
return FutureBuilder(
future: searchresultfuture,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgress();
}
return ... // add this to return something.
});
}
See a similar question here for more info.
I have a stream from Bluetooth and I want to extract the data and send it to another widget but I am having a problem with the return of the widget. this is my code.
StreamBuilder<List<int>>(
stream: stream,
builder: (BuildContext context, AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState == ConnectionState.active) {
// geting data from bluetooth
var currentValue = _dataParser(snapshot.data);
if (currentValue != "nan") {
return temperature = double.parse('${currentValue}');
}
}
});
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
Text('Temperature:'),
Text('20'), // I want temperature here
],
);
}
I want to pass temperature to be written instead of 20 in the Text widget.
what shall I put after return?
Empty SizedBox widget is just fine in that case.
There is nil package also, if you okay with using some extras
here.
Showing some loading state also is a good option
I just started writing with Flutter.I am constantly getting this error. What should i do? Here is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<WeatherInfo>(
future: futureWeather,
builder: (context, snapshot) {
if (snapshot.hasData) {
} else if (snapshot.hasError) {
return Center(
child: Text("${snapshot.error}"),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<WeatherInfo>(
future: futureWeather,
builder: (context, snapshot) {
if (snapshot.hasData) {
} else if (snapshot.hasError) {
return Center(
child: Text("${snapshot.error}"),
);
}
return const Center(child: CircularProgressIndicator());
}));
}
Inside the FutureBuilder you covered the case in which you have the data or you have an error, but not when you are expecting for the future to complete(And don't have neither the data or an error).
I just added a Circular progress indicator to be shown while no data or no error are returned from the Future, that should prevent the FutureBuilder from returning null. And when the snapshot state changes the data or error would be shown.
I think you should try and wrap the future builder in a container
I am using Futurebuilder in flutter and having issue while closing the showDialog
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size( 50.0),
body: FutureBuilder(
future: widget.getAutoCompleteData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
Navigator.of(context).pop();
} else if (snapshot.hasError) {
} else {
LoadingDialog.showLoadingDialog(context, _scaffoldKey);
}
return Center(
child: Container(child: Text("sds"),),
);
}));
}
Getting below error when screen loads
package:flutter/src/widgets/navigator.dart': Failed assertion: line 5013 pos 12: '!_debugLocked': is not true
Change this
FutureBuilder(
future: widget.getAutoCompleteData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
Navigator.of(context).pop();
} else if (snapshot.hasError) { //here this is empty
} else {//remove else statement
LoadingDialog.showLoadingDialog(context, _scaffoldKey);
}
return Center(
child: Container(child: Text("sds"),),
);
})
To This
FutureBuilder<List<Post>>(
future: _dataFetcher.getPosts(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return LoadingDialog.showLoadingDialog(context, _scaffoldKey);
}
return Center(child: Text('${snapshot.data![0].title}'));
},
)
It may be caused by the re-entrant of the Navigator (you can check the answer here: Error thrown on navigator pop until : “!_debugLocked': is not true.”
)
Or, maybe you don't want to use FutureBuilder. The FutureBuilder is meant to stay in the same widget/page and show different screens when future data is not ready. If you want to push a loading dialog and close it when data is ready, you can just simply use a Future function
Future pressTheButton(context) async {
LoadingDialog.showLoadingDialog(context, _scaffoldKey); // showDialog here
final data = await getAutoCompleteData(); // await the data
Navigator.of(context).pop(); // pop the loading dialog
// return your data or error
// or rebuild the current widget with the data
}
I have a stream builder for loading a list of video posts. Whenever an error occurs, I add an error to the sink and the StreamBuilder displays an error message with a "Try Again" button. My issue is that when I press the button, Nothing (visually) happens but I want to replace the error message with a spinningLoader while it's retrying.
How would I achieve this?
I was thinking of adding a boolean to the sink and check if snapshot.data is bool and return the spinningLoader if it is, but this seems counter-intuitive.
#override
Widget build(BuildContext context) {
return SafeArea(
child: Container(
color: backgroundColor,
child: StreamBuilder(
stream: _streamController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return buildRelatedList(snapshot.data);
} else if (snapshot.hasError) {
return retryButton();
} else {
return _spinningLoader;
}
},
),
),
);
}
_fetchVideos() async {
List videos = await RelatedVideos.fetchVideos(
id: widget.id);
if (videos.isEmpty) {
_streamController.sink.addError('error loading');
} else {
_streamController.sink.add(videos);
}
}
You can use ConnectionState:
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.none: return Text('Select lot');
case ConnectionState.waiting: return Text('Awaiting bids...');
case ConnectionState.active: return Text('\$${snapshot.data}');
case ConnectionState.done: return Text('\$${snapshot.data} (closed)');
}
return null; // unreachable
},
)
That will return the state of connection to an asynchronous computation. Also you can change the Text widget to another widget, for example you can use CircularProgressIndicator();
https://api.flutter.dev/flutter/widgets/ConnectionState-class.html
https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html
https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html