How can I run a future before build in flutter? - flutter

I am not able to run getMapCurrencies before the build, and I need values in listCurrencies before the view. I can not put the future builder in the build because I dont want to bring listCurrencies many times, just once.
Please help
getMapCurrencies() {
currencies.getCurrenciesCheck().then((val) {
listCurrencies = val;
});
}
class _CurrencyWidgetState extends State<CurrencyWidget> {
#override
void initState() {
// TODO: implement initState
getMapCurrencies();
super.initState();
}

What do you mean by "I dont want to bring listCurrencies many times, just once"
FutureBuilder is one way you can do this. It will render the widget once listCurrencies is populated.
Another way is to use a ternary operator
listCurrencies != null ? (widget using listcurrencies) : (a progress indicator)
Edit:
Also you should set listCurrencies using
setState((){
listCurrencies = val;
})

Related

Dart Widget created based on a list always uses initState of other Widget in List

The children of my column are created with the data of a List of Maps. `
children: [for (var alarm in alarmDataList) AlarmWidget(alarmData: alarm)],
`I do some changes to my alarms on another Screen. Before that, I delete the according alarmData.
To do that, I have a deleteAlarmDataList function which I call to delete an element of the List. To update my Screen, I call Setstate.`
void deleteAlarmDataList (Map alarm) {
alarmDataList.removeWhere((element) => element.hashCode == alarm.hashCode);
setState(() { alarmDataList; });
}
`Afterwards I call my addAlarmDataList function, which adds a Map to the List alarmData and sorts the Data. Afterwards the alarmDataList gets updated.`
void addAlarmDataList (Map alarm) {
if(alarm['time'] != 'noAdd') setState(() alarmDataList.add(alarm);});
setState(() {alarmDataList.sort((a, b) => a['time'].compareTo(b['time']));});
}
`My problem is, that I have a function which gets called in the initState of the class AlarmWidget which needs to be executed so all information is shown correctly. Unfortunately, in the process of the addAlarmDataList function, the initState of the last index of the alarmDataList is called, instead of the one I added. Also the initState is called after the whole addAlarmDataList function and not after the if clause.
I want the initState of the Widget with the latest added AlarmData to be called. I have tried to insert the insert the new Map at index 0, but this didn't help.
if(alarm['time'] != 'noAdd') setState(() {alarmDataList.insert(0, alarm);});
im not sure this will solve all your issue. let me help to bring you on track.
when you call setState, the build method will be re-executed.
#override
Widget build(BuildContext context) {
....
}
thats why, everytime you call the setState all widget inside the build method will be executed.
and thats caused the last index of the alarmDataList is called on your widget.

Flutter Provider - Call function on value change without calling build()

I am wondering if it is possible to watch for a value change inside an initState which then simply calls a function?
I basically need to start and stop a timer given the status of a class i am observing with Provider (listen: true) and was hoping there was some callback functionality that i could trigger instead of build() being called each time?
For example something like..
void initState() {
super.initState();
Provider.of<MyService>(context, listen: true).serviceRunning => {
//do stuff (start/stop my local timer)
if(serviceRunning) {
serviceRunning()
} else {
serviceStopped()
}
}
}
void serviceRunning() {
//start local timer and other bits
}
void serviceStopped() {
//stop local timer and other bits
}
Widget build(BuildContext context) {
..
}
I don't recall Provider being able to do this, so would appreciate any suggestions on how to achieve this. As mentioned above, i am just trying to save having build() get called unnecessarily.
Not a provider user here (bloc fan) but you should be able to do what you want with a ValueNotifier exposed by your service. And in your initState you would add a listener to the notifier.
And I believe you can avoid build call by using context.select<T, R>(R cb(T value)), which allows a widget to listen to only a small part of T.
Extract of the provider doc:
Widget build(BuildContext context) {
final name = context.select((Person p) => p.name);
return Text(name);
}
But I'm not sure that this is necessary.
If you find a cleaner solution please share it, it's always nice learning what works in other part of the flutter community.

changing variables inside listview builder

i want to change variable values when the widget is loading the data from the web,
just want to do something like this:
_playid = _notes[1].id;
title = _notes[1].title;
but wherever I put it, i get an error,
I tried to put it in a set state inside listview builder, but no luck since I don't want it with onPress or on tap methods
could someone help, please?
i just found out,
simply we have to use setstate in fetch inside initstate
void initState() {
title = " ";
fetchNotes().then((value) {
setState(() {
_notes.addAll(value);
_playid = _notes[0].numb;
});
});
}

Controller's length property does not match the number of tabs present in TabBar's tabs property

I am implementing an TabBar but getting the error, as state above. I know the reason this is happening, but can't figure how to fix this.
I have an async function designed to pull data from Firebase which populates a list. The function is described below. The data pulled by this function is used to pass the length to the TabController.
Function to call data from Firebase:
Future functionName async {
await function actions...
List example = ['item1', 'item2', 'item3', 'item4'];
}
This function is used in a Future Builder, which returns a widget to display, as soon as the function execution is complete.
The future of the Future Builder is initialised in the initState() of the class. The init() state looks like:
#override
void initState() {
super.initState();
_future = functionName();
tabController = TabController(length: example.length, vsync: this, initialIndex: 0);
tabController.addListener(_setActiveTabIndex);
}
Now, I get the error, as stated above. Which is obvious, why!
As the function is an async function and is built in a Future Builder, initially the list 'example' is empty. And the TabController gets a length of 0. But as this list gets populated, the length increases, but the length of the TabController does not change.
I have tried using :
#override
void initState() {
super.initState();
_future = functionName();
setState(() {
tabController = TabController(length : example. length, vsync : this, initialIndex : 0)
}
)
But this doesn't work either.
It's annoying to know the issue, but not being able to fix it. Any help on this will be highly appreciated.
You already know the reason of the problem.
The hole idea it's kind of backwards.
You are trying to build the TabBar, before you know how many tabs you need.
You can
Execute your FutureBuilder and then build the TabBar with the data received.
Or you can
Get the data before you go to that screen, so have the data already.
I hope this put you on the right track

Flutter, using a bloc in a bloc

I have two BLoCs.
EstateBloc
EstateTryBloc
My Application basically gets estates from an API and displays them in a similar fashion
Now I wanted to add a sort functionality, but I could only access the List of Estates via a specific state.
if(currentState is PostLoadedState){{
print(currentState.estates);
}
I wanted to make the List of estates available for whichever bloc, that needed that list.
What I did was, I created the EstateTryBloc, which basically contains the List of estates as a state.
class EstateTryBloc extends Bloc<EstateTryEvent, List<Estate>> {
#override
List<Estate> get initialState => [];
#override
Stream<List<Estate>> mapEventToState(
EstateTryEvent event,
) async* {
final currentState = state;
if(event is AddToEstateList){
final estates = await FetchFromEitherSource(currentState.length, 20)
.getDataFromEitherSource();
yield currentState + estates;
}
}
}
As I print the state inside the bloc I get the List of estates but I dont know how I would use that List in a different bloc.
print(EstateTryBloc().state);
simply shows the initialState.
I am open for every kind of answer, feel free to tell me if a different approach would be better.
When you do print(EstateTryBloc().state); you are creating a new instance of EstateTryBloc() that's why you always see the initialState instead of the current state.
For that to work, you must access the reference for the instance that you want to get the states of. Something like:
final EstateTryBloc bloc = EstateTryBloc();
// Use the bloc wherever you want
print(bloc.state);
Right now the recommended way to share data between blocs is to inject one bloc into another and listen for state changes. So in your case it would be something like this:
class EstateTryBloc extends Bloc<EstateTryEvent, List<Estate>> {
final StreamSubscription _subscription;
EstateTryBloc(EstateBloc estateBloc) {
_subscription = estateBloc.listen((PostState state) {
if (state is PostLoadedState) {
print(state.estates);
}
});
}
#override
Future<Function> close() {
_subscription.cancel();
return super.close();
}
}
To be honest I overcomplicated things a little bit and did not recognize the real problem.
It was that I accidently created a new instance of EstateBloc() whenever I pressed on the sort button.
Anyways, thanks for your contribution guys!