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

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

Related

LateInitializationError: Field '_splitScreenMode' has not been initialized flutter

I'm facing this "LateInitializationError: Field '_splitScreenMode' has not been initialized." error, when I run the flutter app. can you help me?
When working with the late keyword. You must initialize it before using it. Most of the time, you initialized it within the initState. Take a look at how I did it below:
late bool _splitScreenMode; // I used bool type for this example
// setting/initializing the _splitScreenMode
#override
void initState() {
_splitScreenMode = true;
super.initState();
}
For more help with any questions, leave a comment below.

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 - Reuse same custom widget class for instances appear not at same time

In shorter word, my question is how to call child's initState() again on parent's setState().
I need to reuse a widget class for multiple instances. I need the widgets to appear in turn like below where I can use setState() to switch between them.
bool showthefirstone = true;
#override
Widget build(BuildContext context) {
...
TheWidget it = showthefirstone ? TheWidget(...) : TheWidget(..);
...
}
The later one's initState() is not called. No problem showing them both together along at the same time. The issue only occurs upon setState().
For those who don't understand, this trigger the change
setState((){showthefirstone = !showthefirstone})
It's the same answer with different question. My question is more generic. At least works for my case.
https://stackoverflow.com/a/70789848/1297048

Api data null whe nthe pages load even i use initState

im using post method to get api data/response.body in initState and i get all the response/data then i put it in my variables surveyData, but when i load the pages with widget looped by the response.body length it goes error and say response.body.length is null but when i save the text editor/ hot reload, all the data entered and it's not null anymore and the widget appear.
fyi: the http.post method is my own function not from import 'package:http/http.dart' as http; so don't mind it
Variables that contain the response
dynamic surveyData;
initState Code
#override
void initState() {
super.initState();
// GET PAGES
surveyPages = widget.surveyPages;
// GET FORM DETAIL
http.post(
'survey-pre-mitsu/form-detail',
body: {
"survey_form_header_id": 1,
},
).then(
(res) {
surveyData = res['data'];
},
);
}
Widget that looped by surveyData.length
for (var i = 0; i < surveyData.length; i++)
AdditionalForm(questionLabel: surveyData[i]['label'],
questionType: surveyData[i]['type'],),
This is what the error
And this is what it looks like when i do hot reload
First, I suggest you to use future builder to resolve this problem.
First, I suggest performing post(even though its your own code) as a asynchronous operation, hence not inside initState(). Preferably write the logic in a separate class/file with packages like a provider package. Try this first and then post the error after that.
You need to add Some delay , In this Delay you can show a loading icon . for delay you can use :
Future.delayed(const Duration(milliseconds: 500), () {
// Here you can write your code
setState(() {
// Here you can write your code for open new view
});
});
This will solve your problem

How can I run a future before build in 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;
})