Flutter Complex Parsing Json Undefined getter "List<Type>' - flutter

I am trying to parse a complex json file into my application I am getting an error: The getter 'name' isn't defined for the type 'List'. I can't get the name of the route at my List of routes, but can get everything else.
I don't understand where this is happening and how to fix it.
My code:
void openBottomSheet() {
showModalBottomSheet(
context: context,
builder: (context) {
return FutureBuilder<DriverDataModel>(
future: mongoApi.getMongoData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final driver = snapshot.data;
return Container(
child: ListView.builder(
itemCount: driver.data.routes.length,
itemBuilder: (BuildContext context, snapshot) {
return ListTile(
title: Text('${driver.data.routes.name}'),
leading: Icon(Icons.directions),
onTap: () {
drawPolyLine.cleanPolyline();
getCurrentLocation();
routesCoordinates.isInCourse(driver.data.routes);
Navigator.pop(context);
},
);
},
),
);
}
return Container();
},
);
});
Json reponse:
{
"success": true,
"data": {
"_id": "600773ac1bde5d10e89511d1",
"name": "Joselito",
"truck": "5f640232ab8f032d18ce0137",
"phone": "*************",
"routes": [
{
"name": "Tere city",
"week": [
{
"short_name": "mon"
}
],
"coordinates": [
{
"lat": -22.446938,
"lng": -42.982084
},
{
"lat": -22.434384,
"lng": -42.978511
}
]
}
],
"createdAt": "2021-01-20T00:05:00.717Z",
"updatedAt": "2021-01-20T00:05:00.717Z",
"__v": 0
}
I used https://app.quicktype.io/ to create my model and successfully parsed. How ever, when I tried to print the name of my route inside of my routes's list a get that getter error.

#fartem almost answered right except you need to dynamically access your items by index (not just the first item). In your code on the line where you use the function itemBuilder in ListView.builder, instead of
itemBuilder: (BuildContext context, snapshot) {
I would suggest using
itemBuilder: (BuildContext context, i) {
since the second parameter is an INDEX. Thus, to be able to get the name for each of the items in the list you would have to use that index:
title: Text('${driver.data.routes[i].name}'),
and so on.

Routes is an array, you can try to calling it by driver.data.routes[0].name

Related

Flutter Navigation using a switchcase

I am building a listview of 20 list in them and once this list view is build i want to have different pages for each of the list tile and i also want a way to navigate to each of these page seperately.
i am thinking of using the switch case and use the index oof the list for the condition which will decide based on the clicked index to navigate.
final List<Map<String, dynamic>> _av_all_listtiles = [
{
"id": 1,
"name": "label 1",
},
{
"id": 2,
"name": "label 2",
},
{
"id": 3,
"name": "label 3",
},
ListView.builder(
itemCount: _av_searched_listiles.length,
itemBuilder: (context, index) =>
child: Card(
borderOnForeground: true,
elevation: 8,
child: Container(
height: 44.h,
child: ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
// here i want some kind of function or conditioon based on which it will navigate
deposit_screen()),
);
},
),
),
),
),
),
I tried to make function but it didnt work
You can use switch case for navigation like this :
ListView.builder(
itemCount: _av_all_listtiles.length,
itemBuilder: (context, index) => Card(
borderOnForeground: true,
elevation: 8,
child: Container(
height: 44.h,
child: ListTile(
onTap: () {
var screen = deposit_screen();
switch (index) {
case 0:
screen= deposit_screen();
break;
case 1:
screen= deposit_screen1();
break;
case 2:
screen= deposit_screen2();
break;
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => screen
),
);
},
),
),
),
)
This is not too difficult to implement. There are few things to consider to fix your code.
Usage of arrow function
When you use arrow function it means you are calling and returning the value in a single line of code. If you need to write some logic inside function first change arrow function to normal function body.
You need to change this
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
deposit_screen()),
);
to
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
})
);
Now you can put your code inside this function. But for this builder to execute and navigate to a specific page, you need to return the page from here.
For example, using the default counter code, I am trying to move to Page1 if value is even & Page2 if value is odd.
You need to put your code like this.
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return (_counter %2==0 ? Page1() : Page2());
}),
);
Now the router will get the page name correctly as you are returning it from builder.

reading data from firebase firestore collection at stream builder

I got trouble with firebase fireStore.
There is a stream builder reading data from items collection.
Inside items collection there is some fields and another collections.
I haven't any problem with fields, the problem is with collection.
how to access those collections inside stream builder?
StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: CallApi().finalReference(reference: widget.finalReference),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(child: Text('snapshot Error:${snapshot.error}'));
}
if (snapshot.hasData) {
var snapData = snapshot.data!.docs;
if (kDebugMode) {
print(snapData.length);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: ListView.builder(
itemCount: snapData.length,
itemBuilder: (BuildContext context, int index) {
return ListItem(
mTitle: snapData[index].get('title') ?? '',
mSubTitle: snapData[index].get('address') ?? 'empty',
mPrice: snapData[index].get('price') ?? '',
mImageUrl: snapData[index].get('gallery')[0],
mOnTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsPage(
adsTitle: snapData[index].get('title'),
adsSubTitle: snapData[index].get('subTitle'),
gallery: snapData[index].get('gallery'),
specFTitle: snapData[index].get('gallery'),
),
),
);
},
);
},
),
),
],
);
}
return const Center(child: CircularProgressIndicator());
},
),
here is firebase
Reading data from Firestore is a shallow operation. When you read a document, its subcollection are not automatically read.
So if you want to get the data from the subcollections of the current document, you will have to start a new read operation for that. If you want to show that data in the UI, you can use a new, nested StreamBuilder or FutureBuilder for that.

Getting this RangeError (index): Invalid value: Valid value range is empty: 1 while trying to populate json data to ListView.builder

I have an API and what I am trying to do is to display the 'CourseTitle' from the JSON into the ExpansionTile title and the corresponding 'Title', 'EndDate', 'QuizStatus' in the children of ExpansionTile.
If data is not available for corresponding 'Title', 'EndDate', 'QuizStatus' etc., only 'CourseTitle' should be added to the ExpansionTile title, and children should be empty.
The first tile is built as expected but the remaining screen shows a red screen with RangeError (index): Invalid value: Valid value range is empty: 1.
I'm aware that this is because of empty data from JSON but couldn't solve the issue.
Here's JSON response:
{
"QuizzesData": [
{
"request_status": "Successful",
"CourseCode": "ABC101",
"CourseTitle": "ABC Course",
"UnReadStatus": [],
"Quizzes": [
{
"QuizID": "542",
"Title": "Test Quiz 01",
"StartDate": "Oct 20, 2022 12:00 AM",
"EndDate": "Oct 31, 2022 11:59 PM",
"IsDeclared": "False",
"Questions": "5",
"TotalMarks": "5",
"MarksObtained": "1",
"MarksObtainedTOCheckQuizResult": "1",
"QuizIsDeclared": "Un-Declared",
"StudentSubmitStatus": "true",
"IsRead": "1",
"QuizStatus": "Attempted"
}
]
},
{
"CourseCode": "DEF101",
"CourseTitle": "DEF Course",
"UnReadStatus": [],
"Quizzes": []
},
{
"CourseCode": "GHI101",
"CourseTitle": "GHI Course",
"UnReadStatus": [],
"Quizzes": []
},
{
"CourseCode": "JKL101",
"CourseTitle": "JKL Course",
"UnReadStatus": [],
"Quizzes": []
},
]
}
Here's the API data:
var listofdata ;
Future quizListingApi() async {
final response = await http.get(Uri.parse('json url'));
if(response.statusCode == 200){
listofdata = jsonDecode(response.body.toString());
}
else{
print(response.statusCode);
}
and the build method:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(child: FutureBuilder(
future: quizListingApi(),
builder: (context, AsyncSnapshot snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Text('Loading');
}
else{
return ListView.builder(
itemCount: listofdata['QuizzesData'].length,
itemBuilder: (context, index){
return Card(
child: Column(
children: [
ExpansionTile(
title: Text(listofdata['QuizzesData'][index]['CourseTitle']),
children: [
Text(listofdata['QuizzesData'][index]['Quizzes'][index]['Title']),
Text(listofdata['QuizzesData'][index]['Quizzes'][index]['EndDate']),
Text(listofdata['QuizzesData'][index]['Quizzes'][index]['QuizStatus']),
],
),
],
),
);
}
);
}
},
))
],
),
);
}
I also tried answers from other similar threads but couldn't find the solution for this specific type of problem.
Your Quizzes's index are not same as your listofdata, so you need and other for loop for your Quizzes's items:
ExpansionTile(
title: Text(listofdata['QuizzesData'][index]['CourseTitle']),
children: List<Widget>.generate(listofdata['QuizzesData'][index]['Quizzes'].length, (i) => Column(
children: [
Text(listofdata['QuizzesData'][index]['Quizzes'][i]
['Title']),
Text(listofdata['QuizzesData'][index]['Quizzes'][i]
['EndDate']),
Text(listofdata['QuizzesData'][index]['Quizzes'][i]
['QuizStatus']),
],
),),
),

Getting Error on implementing Dismissible on flutter list

I am trying to implement Dismissible to swipe and remove the item from the list in flutter, but I am getting the below error on implementation of the same
type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of
type 'String'
at this line of the code key: Key(item)
How should I resolve it ?
ListView.separated(
separatorBuilder: (context, index){
return Divider();
},
controller: _scrollController,
itemCount: noteItems,
shrinkWrap: true,
itemBuilder: (context, index) {
final item = firstdata[index];
return
Dismissible(
direction: DismissDirection.endToStart,
key: Key(item),
onDismissed: (direction) {
setState(() {
firstdata.removeAt(index);
});
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text("$item dismissed")));
},
background: Container(color: Colors.red)
,
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0, 7.0, 8.0, 0.0),
child: Column(
children: <Widget>[
ListTile(
leading:ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset('images/appstore.png', width: 50, height: 50)
) ,
title:
Row(children: [
Flexible(
child: firstdata[index]['id']!= null?AutoSizeText(
firstdata[index]['id'],
maxLines: 2,
style: TextStyle(fontWeight: FontWeight.bold),) :Text(''),
),
],),
),
],
),
),
);
},
),
The JSON data structure for the list view is here below
{
"error": "false",
"notification": [
{
"rn": "1",
"id": "224",
"company_details": {
"code": "2",
}
},
{
"rn": "2",
"id": "219",
"company_details": {
"code": "3",
}
},
{
"rn": "3",
"id": "213",
"company_details": {
"code": "3",
}
},
{
"rn": "4",
"id": "209",
"company_details": {
"code": "4",
}
},
{
"rn": "5",
"id": "204",
"company_details": {
"code": "3",
}
},
{
"rn": "6",
"id": "199",
"company_details": {
"code": "3",
}
},
{
"rn": "7",
"id": "193",
"company_details": {
"code": "3",
}
}
],
}
How should I implement the same and get it resolved?
As stated in the other answer, the Key function expects a string to create a key based on that. If you can identify an item based on one of its parameters (for example id), then you could use item.id and it would be fine.
However, to make sure it will be truly unique key for any combination of parameters (in your case id, rn and company_details) you can use ObjectKey:
Replace the following line:
key: Key(item)
With the following:
key:ObjectKey(item)
This way Flutter can identify your item's parameters and create a key based on the combination of them.
Other options include ValueKey and UniqueKey.
type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
means that it crashed because it was expecting a String and flutter did not find one.
This means that:
key: Key(item)
Key(item)-> Is not a String. I donĀ“t know how are you creating Key/where is it.
My best guess is to try to find some method like...:
`key: Key(item).aMethodthatgivesaString()`
`key: Key(item).toString()`
Let me know if this was useful.

Can't change the status of checkbox in GridView Flutter with Mobx

I want to add a checkbox for GirdView in Flutter. The data was fetched from API request include attribute selected default is false. When I click on the checkbox of each Item it will change value is True and update on UI and I use Mobx to observe these change actions. When I debugging the values were changed but UI didn't update, I really don't know the reason. I added 2 pictures for UI and Mobx model below.
API:
{
"name": "HuynhDuy Phuc",
"birthday": "None",
"phone": "N/A",
"isSelected": false
},
{
"name": "Doan Phuc",
"birthday": "None",
"phone": "N/A",
"isSelected": false
},
{
"name": "Phuc Vu",
"birthday": "None",
"phone": "N/A",
"isSelected": false
},
final _userApiPresenter = Provider.of<UserApiPresenter>(context);
_userApiPresenter.fetchUsersList();
Observer(
name: 'ListHomePage',
builder: (BuildContext context) {
return (_userApiPresenter.userAPI != null)
? AnimationLimiter(
child: GridView.builder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(12),
addAutomaticKeepAlives: true,
//Determine the number of cells per row
gridDelegate:
new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemCount:
_userApiPresenter.userAPI.users.length,
itemBuilder: (context, index) {
User user =
_userApiPresenter.getUser(index: index);
return AnimationConfiguration.staggeredGrid(
position: index,
duration:
const Duration(milliseconds: 375),
columnCount: 2,
child: Container(
child: ScaleAnimation(
child: GestureDetector(
child: Stack(
children: <Widget>[
UserItem(
name: user.name,
type: user.name,
phone: user.phone,
birthday: user.birthday,
isSelected: user.selected,
),
Align(
alignment: Alignment.topRight,
child: Checkbox(
value: user.selected,
onChanged: (_) {
if(user.selected){
_userApiPresenter.changeStatusCheckBox(index: index);
} else{
_userApiPresenter.changeStatusCheckBox(index: index);
}
},
),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder:
(BuildContext context) =>
UserDetailPage(
index: index,
name: user.name,
),
),
);
},
),
),
),
);
},
),
)
: Center(
child: CircularProgressIndicator(),
);
},
)
UI
Mobx model
Observable information about users array and the user model itself is missing, but what you need to do(if already not) is:
Make the array of users observable as well - this way any addition, deletion, etc will results in update of the number of user boxes in the UI
Make property selected of User observable also - this way when certain user 'selected' state is effected, the UI will render the change
And something off topic:
You don't need #action attribute on getUser method, because this method is not updating any observable data
If this answer does not solve your problem, please provide implementation of userApi and User :)
You just missing one thing.
mobX does not update UI unless you tell it main variable changed..
To do so, just add the following line of code to your changeStatusCheckBox()
_userAPI = _userAPI;