I want to populate my DropdownSearch with fetching data from local database. Plese help me.
Future<dynamic> getList() async {
final db = await getDatabase();
final res = await db.rawQuery("SELECT * FROM tb_point_of_Sale");
List<dynamic> list =
res.isNotEmpty ? res.map((c) => PointOfSale.fromJson(c)).toList() : [];
}
body: Column(
children: [
DropdownSearch<String>(
mode: Mode.MENU,
items: PointOfSaleDao.db.getList(),
showSearchBox: true,
label: "Menu mode",
hint: "point of sale in menu mode",
onChanged: (value) {}
),
],
),
As getList returns a Future, use a FutureBuilder to draw the widget for each state the Future can be, whether it's still loading or finished fetching the data. The FutureBuilder will provide you with an AsyncSnapshot. After the Future has been resolved, you should be able to access the loaded items by calling .data on the AsyncSnapshot.
FutureBuilder(
future: getList(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
snapshot.data // access the loaded list
} else if (snapshot.hasError) {
snapshot.error // access the error message
} else {
// the future is still resolving
}
}
)
In case you are using the dropdown search package, there seems to be a field for that named asyncItems on it you might want to look into.
Related
I don't quite understand how you can update future in FutureBuilder by timer. I tried to create a timer and give it to the future, but it didn't work out and there was an error: type '_Timer' is not a subtype of the 'Future?'
my handler with a request:
Future<ObjectStateInfoModel> read(int id) async {
TransportResponse response = await transport.request(
'get',
RequestConfig(path: path + '($id)'),
TransportConfig(
headers: {},
));
ObjectStateInfoModel objectState = ObjectStateInfoModel.fromJson(response.data);
return objectState;
}
my FutureBuilder:
return FutureBuilder<ObjectStateInfoModel>(
future: logexpertClient.objectsState.read(object.id),
builder: (context, snapshot) {
if (snapshot.hasData) {
final data = snapshot.data!;
on the advice of one of the commentators i converted FutureBuilder to StreamBuilder and created such a stream and then everything works correctly:
stream = Stream.periodic(const Duration(seconds: 5)).asyncMap((_) async {
return logexpertClient.objectsState.read(object.id);
});
Use refreshable_widget, which is built specifically for this.
https://pub.dev/packages/refreshable_widget
Flexible(
child: RefreshableWidget<num>(
initialValue: challenge.userParticipation!.donePercent,
refreshCall: () async {
final challenge =
await cadoo.getChallengeDetail(
id: widget.challengeId,
);
return challenge.userParticipation!.donePercent;
},
builder: (context, value) {
return DonePercentWidget(
percent: value,
);
},
),
),
Pass a refresh call and how often you want to refresh, widget will build whatever on builder method.
I am using cubit for state management in my app. I have a variable in the state called prices which I want to access:
Future<void> fetchMonthlyTotals(String userId) async {
//var userId = await getUserId();
var prices =
await myDB().getPrices(userId);
print(prices .toString());
// ignore: unnecessary_null_comparison
if (prices != null && prices .isNotEmpty) {
emit(MonthlyTotalsState(monthlyTotals: prices ));
} else {
debugPrint("prices is empty");
}
}
This is the class where I want to access prices variable:
void getExpenses() async {
var prices = //get price from cubit
print(prices);
}
Both the codes are in different classes and are present in the same package
How do I access the price variable?
Kindly comment if more information is needed.
You can use like this aswell
BlocBuilder<Cubit, CubitState>(
buildWhen: (previous, current) => current is MonthlyTotalsState
builder: (context, state) {
if(state is MonthlyTotalsState){
return Center(
child: Text('Monthly TotalPrices:${state.monthlyTotals}'),
);
}
return const SizedBox();
},
),
If you need to use this value inside the UI you should use a BlocBuilder.
It will update your UI whenever the state changes.
If you however want to do something like showing a dialog or navigating in response to a state change you should use a BlocListener. If you want to do a combination of both of the mentioned use-cases you can use a BlocConsumer
BlocBuilder<ReportinCubit, MonthlyTotalsState>(
builder: (_, monthlyTotalState) {
return Center(
child: Text('Monthly Total Prices: ${monthlyTotalState.prices}'),
);
},
),
If you need to use this value inside the UI you should use a CubitBuilder.
It will update your UI whenever the state changes.
CubitBuilder<ReportinCubit, MonthlyTotalsState>(
builder: (_, monthlyTotalState) {
return Center(
child: Text('Monthly Total Prices: ${monthlyTotalState.prices}'),
);
},
),
i'm currently working on a app which basically works like a database. I want it to fetch data from my sqflite database and use it as text. For some reason I only get "Index of Object" instead of the correct value as text. This is my code in database_helper.dart:
Future<Obj> getName(int id) async {
final db = await database;
var res = await db.query(table, columns: [objName], where: "objId= ?", whereArgs: [id]);
await print(res); //returns right value
return await res.isNotEmpty ? Fish.fromMap(res.first) : Null ;
}
}
and this is my FutureBuilder
FutureBuilder(
future: dbHelper.getName(1),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListTile(
leading: Icon(Icons.message),
title: Text('${snapshot.data}'),
subtitle: Text(""),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NextPage()),
);
}
);
}
return Container();
},
),
I feel like I tried everything. Printing res directly from database_helper.dart gives the right result.
I'd love some tipps! Thanks in advance!
FutureBuilder is working fine and is returning data.You have one Fish object returned from your getName future.
snapshot.data has returned one Fish object.To show any property you can use snapshot.data.propertyName of Fish Model.
My requirement is to make that StreamBuilder connection state to waiting.
I'm using publish subject, whenever I want to load data in stream builder I'm just adding data to the sink by calling postStudentsToAssign() method, here this method making an API call which takes some time, in that time I to want make that streamBuilder connection state to waiting
Stream Builder:
StreamBuilder(
stream: studentsBloc.studentsToAssign,
// initialData: [],
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
// While waiting for the data to load, show a loading spinner.
return getLoader();
default:
if (snapshot.hasError)
return Center(child: Text('Error: ${snapshot.error}'));
else
return _getDrawer(snapshot.data);
}
}),
Initializing Observable:
final _assignStudentSetter = PublishSubject<dynamic>();
Observable<List<AssignMilestoneModel>> get studentsToAssign =>
_studentsToAssignFetcher.stream;
Method that add's data to Stream:
postStudentsToAssign(int studyingClass, String milestoneId, String subject,
List studentList) async {
var response = await provider.postAssignedStudents(
studyingClass, milestoneId, subject, studentList);
_assignStudentSetter.sink.add(response);
}
You can send null to the stream, so the snapshot.connectionState changes to active. I don't know why and whether it's official solution, but it works (at least now). I found this accidentally.
I would like the Flutter team to explain how to set snapshot's connectionState. It's not clear from StreamBuilder documentation. It seems you should replace the stream with a new one to have snapshot in waiting state. But it's agains the logic you want to implement.
I checked StreamBuilder source to find out that the AsyncSnapshot.connectionState starts as waiting (after stream is connected), after receiving data changes to active. snapshot.hasData returns true if snapshot.data != null. That's how following code works.
class SearchScreen extends StatelessWidget {
final StreamController<SearchResult> _searchStreamController = StreamController<SearchResult>();
final SearchService _service = SearchService();
void _doSearch(String text) async {
if (text?.isNotEmpty ?? false) {
_searchStreamController.add(null);
_searchService.search(text)
.then((SearchResult result) => _searchStreamController.add(result))
.catchError((e) => _searchStreamController.addError(e));
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
SearchBar(
onChanged: (text) => _doSearch(text),
),
StreamBuilder<SearchResult>(
stream: _searchStreamController.stream,
builder: (BuildContext context, AsyncSnapshot<SearchResult> snapshot) {
Widget widget;
if (snapshot.hasData) {
widget = Expanded(
// show search result
);
}
else if (snapshot.hasError) {
widget = Expanded(
// show error
);
}
else if(snapshot.connectionState == ConnectionState.active){
widget = Expanded(
// show loading
);
}
else {
// empty
widget = Container();
}
return widget;
},
),
]),
);
}
}
I am new to Flutter and facing an issue with StreamBuilder & ListView.builder.
I am making a network call on click of a button(Apply Button) available in the list of the card, based on that other buttons are displayed.
the issue I am facing is that widgets are not updated after successful network call but, when I refresh the page I am getting updated result.
What I am doing wrong?
I am not Using any State into this. Do I need to use it?
Widget Code
StreamBuilder(
initialData: [],
stream: dataBoc.ListData,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemBuilder: (BuildContext context, index) {
return InkWell(
key: Key(snapshot.data[index]["lid"]),
child: DataCard(
DataModel(snapshot.data[index]),
),
onTap: () {
Navigator.pushNamed(context, "/detailPage",
arguments: snapshot.data[index]["id"]);
},
);
},
itemCount: snapshot.data.length,
);
}
},
),
Bloc Code
//Here is how I am adding data to the stream
if (res.statusCode == 200) {
var data = json.decode(res.body);
if (data['status'] == true) {
// listDataStream.sink.add(data['result']);
listDataStream.add(data['result']);
} else {
listDataStream.sink.addError("Failed to Load");
}
}
Expected result: When I make Network call and if it succeeds then based on network result other buttons must be displayed on the appropriate card.
I have fixed this issue. The issue was my widget tree was not well structured and it was breaking the Widget build process.