parsing JSON file in flutter - json

I am parsing this type of JSON file in flutter but I am getting error.
initially, I am able to print the whole data in the console but when I want only the name it gives me an error.
bellow in the image for JSON file.
this the code that I wrote for parsing which gives me 1st value of name as "Abul-Abbas" then it throws an error.
import 'package:flutter/material.dart';
import 'package:flutter_appnew/Constants.dart';
import 'package:flutter_appnew/network.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
const URL ='https://xxxx-api.someapp.com/xxx';
class TabData extends StatefulWidget {
#override
_TabDataState createState() => _TabDataState();
}
class _TabDataState extends State<TabData> {
List image = [];
List Name = [];
#override
void initState() {
super.initState();
this.fetchUser();
}
fetchUser() async{
var response = await http.get(URL);
print(response.statusCode);
if(response.statusCode == 200){
var items = json.decode(response.body)[0]['name'];
print(items);
setState(() {
Name = items;
});
}
else{
setState(() {
Name = [];
});
}
}
#override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: Name.length,
itemBuilder: (BuildContext context, int index){
return getCard(context, index);
},
separatorBuilder: (context, index) => Divider(thickness: 2,),
);
}
Widget getCard(BuildContext context, int index){
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
title: Row(
children: [
Container(
height: 60,
width: 60,
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(30),
image: DecorationImage(
image: NetworkImage('${image[index]}'),
fit: BoxFit.cover,
),
),
),
SizedBox(width: 20,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('${Name[index]}', style: kListTileTextNameStyle,),
],
),
],
),
),
),
);
}
}
and the same is happening with the image I am not able to show it.
please help this is my first time with JSON file parsing.

I can advice you to try to avoid the dynamic type. Your
var items = json.decode(response.body)[0]['name'];
assigns the items to be the type String and the value is "Abul-Abbas". After that you assign Name which is a List to items which is of type String.
What you actually want to do is to add all names to the list (I guess).
So you should do:
response.body.forEach((element) {
Name.add(element["name"]);
});
I also recommend Renaming Name to names.
If you just wanted the first value of your response, then Name should be of type String.

Related

API give data NULL in first Load

I get the data from API and when API calls on the first load of the screen so API gets the data but in response, the data shows the null value, and when I click on hot reload it response shows data from API.
I don't know what happens with API or response.
Please someone help me to understand what happened with the response I also used await but nothing happens.
Here is my code:-
import 'package:flutter/material.dart';
import 'package:mindmatch/utils/widget_functions.dart';
import 'package:mindmatch/screens/Favorites.dart';
import 'package:mindmatch/screens/Editprofile.dart';
import 'package:getwidget/getwidget.dart';
import 'package:mindmatch/screens/Sidebar.dart';
import 'package:mindmatch/screens/Footer.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:mindmatch/utils/Auth.dart';
class Profile extends StatefulWidget {
var usrid;
Profile({Key? key, #required this.usrid}) : super(key: key);
#override
_Profile createState() => _Profile();
}
class _Profile extends State<Profile>{
//SingingCharacter? _character = SingingCharacter.male;
var url;
var data;
final body = null;
#override
Widget build(BuildContext context){
var UsrID = widget.usrid;
final Size size = MediaQuery.of(context).size;
final ThemeData themeData = Theme.of(context);
final double padding = 25;
final sidePadding = EdgeInsets.symmetric(horizontal: padding);
var url = Uri.https('www.******.net', '/mm_api/index.php',{'act':'profile','UsrID': UsrID});
print(url);
// print(getData());
Future getData() async{
final res = await http.get(
url,
headers: {'Content-Type': 'application/json'},
);
//var res = await http.get(Uri.parse('www.*******.net/mm_api/index.php?act=profile&UsrID=${UsrID}'));
print(res);
//data = json.decode(res.body);
data = jsonDecode(res.body);
print(data);
//setState(() {});
//print(res.body);
}
#override
void initState() async{
super.initState();
getData();
// print (await getData());
}
print(data);
//print(getData());
//return SafeArea(
return Scaffold(
appBar: AppBar(
titleSpacing: 3,
backgroundColor: Colors.white,
elevation: 0,
title: Text('My Profile', style: TextStyle(color: Colors.black, fontSize: 15,),),
leading: Builder(
builder: (BuildContext context) {
return Padding(padding: EdgeInsets.fromLTRB(15, 0, 0, 0),
child: IconButton(
icon: SvgPicture.asset(
width: 30,
'assets/images/Menu.svg',
height: 30,
),
onPressed: () { Scaffold.of(context).openDrawer(); },
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
),
);
},
),
actions: <Widget>[
Padding(
padding: sidePadding,
child: Row(
children: [
//Icon(Icons.search, color: Colors.black,),
SvgPicture.asset(
width: 30,
'assets/images/search.svg',
height: 30,
),
],
)
)
],
),
backgroundColor: Color(0xff8f9df2),
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
//colors: const [Color.fromRGBO(132,105,211,1), Color.fromRGBO(93,181,233,1), Color.fromRGBO(86,129,233,1)],
colors: [Colors.white, Colors.white]
),
),
width: size.width,
height: size.height,
child: Stack(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//addVerticalSpace(30),
data != null?Expanded(
child: Padding(
padding: sidePadding,
child: ListView(
physics: BouncingScrollPhysics(),
children: [
Text('${data[0]['name']}')
],
),
)
): const Center(
child: CircularProgressIndicator(),
)
],
),
],
)
),
drawer: Sidebar(),
persistentFooterButtons: [
Footer(usrid:UsrID),
],
);
//);
}
}
When first load screen it shows me a null value:- Here I Print data form response but it shows me a null value
And when I hot reload the screen it shows me the response value:- It shows the value and I comment any print value or hot reload the screen
Data from API:-
[{"id":"1","name":"anni","fulname":"anni ann","mobile":"+15214639870","email":"anni#gmail.com","about":"sdhbsdbcshcbsdhcbsbchsdb\ncbhbchsc","lookfor":"Relationship, Networking","education":"gcnd,2018","work":"dhfjsk,fjskk","politics":"Liberal, Apolitical","religion":"Protestant, Anglican, Hindu","children":"Have + don't want more, Have and want more","interests":"Treking, Sports, Cooking","distance":" 17 ","age":" 20, 60 "}]
when I test API on the browser it shows correct data but does not show in response
WHY?
Please help me to understand this.
I don't know whats going on with the response
It also looks like you are calling initState in your build method. You have to move it out of build method as it is a separate override method.
You have to call setstate after catching data from api
add this line in your getdata() at the end setstate()
setstate() is used to hot reload programatically so in other words when your app update it's state or any information which is used by your app you have to call setstate() function for reflate on your app's ui.
setstate() function call build method one time again and draw whole tree again.
if you have not use setstate then i suggest some code below do this.
final res = await http.get(
url,
headers: {'Content-Type': 'application/json'},
);
//var res = await http.get(Uri.parse('www.*******.net/mm_api/index.php?act=profile&UsrID=${UsrID}'));
print(res);
//data = json.decode(res.body);
dynamic data = jsonDecode(res.body);
print(data);
return data;
//setState(() {});
//print(res.body);
}
//then edit your future builder
FutureBuilder(builder: (context, snapshot) {
if(snapshot.connectionState==ConnectionState.waiting){
//return loader
}else {
if(snapshot.hasData==true){
//update your ui
}else{
//data is null
}
}
}```

How do I create function to pass Json data in Flutter?

How do I create a function to call JSON data on a specific page? The value of the JSON data will be used to be put in the TextField.
I have created the model class and the API for the User data. I want to use the id and the code.
user.dart
import 'dart:convert';
List<User> userFromJson(String str) => List<User>.from(json.decode(str).map((x) => User.fromJson(x)));
String userToJson(List<User> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class User {
User({
....
user-api.dart
import '../model/user.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
Future<List<User>> fetchUser() async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
var loginID = sharedPreferences.getString('user');
var url = Uri.parse("https:wahatever-abc/user.php?LoginID=$loginID");
final response = await http.get(url);
return userFromJson(response.body);
}
I want to create a function to call the JSON data in a new page call new_user.dart. The data in the function will be used in the Textfield form. I have no idea on how to call it.
new_user.dart
import 'model/user.dart';
import 'api/user-api.dart';
import 'package:http/http.dart' as http;
#override
void initState() {
fetchUserA();
super.initState();
_myActivity = '';
_myActivityResult = '';
}
void fetchUserA() async {
....
}
How do I create and pass the value inside the fetchUser?
What I want to achieve is how do I call the value from the JSON and declare it in the fetchUserA function by using the 'fetchUser()' in the 'user-api.dart' With the called value in the fetchUserA i will use the data to insert it in the Textfield form which i will create it later.
example of what i want to try
This is what i tried before but its not working. So I wanted to try other way. What I mean by other way is try to do like this this example
Widget build(BuildContext context){
return Form(
key: _formKey,
autovalidateMode: AutovalidateMode.always,
child: FutureBuilder(
future: fetchUser(),
builder: (context, snapshot){
return ListView.builder(
itemCount: snapshot.data.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, index)
{
User user = snapshot.data[index];
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
decoration : InputDecoration(labelText: "${user.id}"),
controller: id,
),
),
),

The method '[]' was called on null. Receiver: null T while accessing key:value pair in json

I am working on a mobile app related to vehicles. I have to create a form that should have several fields to be filled about a vehicle's info (like regNum, brand, model,type...).
In order to fetch the data for the dropdown button field I have to make http request(for type,brand,model).
I want whenever I change the vehicle brand in its corresponding dropdown, the vehicle model dropdown field to be updated only with models corresponding to the selected brand.
Here is my code:
#VehicleForm
class VehicleForm extends StatefulWidget {
final Future<VehicleTypes> types;
final Future<VehicleBrands> brands;
final Future<VehicleModels> models;
VehicleForm(this.types, this.brands, this.models);
#override
VehicleFormState createState() => VehicleFormState(types,brands,models);
}
class VehicleFormState extends State<VehicleForm>{
final Future<VehicleTypes> types;
final Future<VehicleBrands> brands;
final Future<VehicleModels> models;
String brandName;
VehicleFormState(this.types, this.brands, this.models);
void handleBrandChanged(String brand){
setState(() {
print(brand);
brandName=brand;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Vehicle')
),
body: Container(
child: Column(
children: [
Container(
margin: EdgeInsets.only(
top:20,
),
alignment: Alignment.center,
child:Text('General Info',
style: TextStyle(
fontSize: 22,
color:Colors.blue,
),
),
),
Container(
child: Column(
children: [
Container(
child: TextFormField(
decoration: const InputDecoration(
hintText: 'Registration number'
),
),
margin: EdgeInsets.all(10),
),
Container(
child: TextFormField(
decoration: const InputDecoration(
hintText: 'Vehicle km'
),
),
margin: EdgeInsets.all(10),
),
Container(
width:200,
child: VehicleTypeMenu(types),
),
Container(
width:200,
child: VehicleBrandMenu(brands,brandName,handleBrandChanged),
),
Container(
width:250,
child: brandName==null ? TextFormField(
decoration: const InputDecoration(
hintText: 'Vehicle Model'
),
): VehicleModelMenu(models,brandName),
),
VehicleYearDropdown(),
VehicleMonthDropdown(),
],
),
)
],
)
)
);
}
//VehicleBrand
class VehicleBrandMenu extends StatelessWidget{
final Future<VehicleBrands> brands;
final String brandName;
final ValueChanged<String> onChanged;
VehicleBrandMenu(this.brands,this.brandName,this.onChanged);
void handleBrandChanged(String brandName){
onChanged(brandName);
}
#override
Widget build(BuildContext context) {
return FutureBuilder<VehicleBrands>(
future: brands,
builder: (context,snapshot){
if(snapshot.hasData){
List<String> vehicleBrands = List<String>();
for(int i=snapshot.data.brands.length-1;i>=0;i--){
vehicleBrands.add(snapshot.data.brands[i]['name'].toString());
}
return DropdownButton<String>(
hint: Text("Select Vehicle Brand"),
value:brandName,
onChanged: handleBrandChanged,
items: vehicleBrands.map((String vehicleBrand){
return DropdownMenuItem(
value:vehicleBrand,
child: Row(
children: [
Text('$vehicleBrand')
],
),
);
}).toList(),
);
} else if(snapshot.hasError){
return Text('${snapshot.error}');
} else{
return TextFormField(
decoration: const InputDecoration(
hintText: 'Vehicle Model'
),
);
}
}
);
}
}
//VehicleModel(the problem occurs here)!
class VehicleModelMenu extends StatefulWidget{
final Future<VehicleModels> models;
final String brandName;
VehicleModelMenu(this.models,this.brandName);
#override
VehicleModelMenuState createState() => VehicleModelMenuState(models,brandName);
}
class VehicleModelMenuState extends State<VehicleModelMenu>{
final Future<VehicleModels> models;
final String brandName;
var firstItem;
VehicleModelMenuState(this.models,this.brandName);
#override
Widget build(BuildContext context) {
return FutureBuilder<VehicleModels>(
future: models,
builder: (context,snapshot){
if(snapshot.hasData){
print(brandName);
List<String> vehicleModels = List<String>();
for(int i=snapshot.data.models.length-1;i>=0;i--){ //The problem occurs in this loop
if(snapshot.data.models[i]['vehicleBrand']['name']==brandName){ //I check for equal brand
vehicleModels.add(snapshot.data.models[i]['name']); //I add only the needed models
}
}
return DropdownButton<String>(
hint: Text("Select Vehicle Model"),
value: firstItem,
onChanged: (String model) {
setState(() {
firstItem = model;
});
},
items: vehicleModels.map((String vehicleModel) {
return DropdownMenuItem(
value: vehicleModel,
child: Row(
children: [
Text('$vehicleModel')
],
),
);
}).toList(),
);
} else if(snapshot.hasError){
return Text('${snapshot.error}');
} else {
return CircularProgressIndicator();
}
}
);
}
}
Here is the data I want to fetch: I compare the ['vehicleBrand']['name']->brand property and add ['name']->model
enter image description here
Here is the actual error:
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building FutureBuilder<VehicleModels>(dirty, state: _FutureBuilderState<VehicleModels>#5813d):
The method '[]' was called on null.
Receiver: null
Tried calling: []("name")
The relevant error-causing widget was:
FutureBuilder<VehicleModels> file:///D:/Android%20Apps/login_form/lib/vehicleFormElements/vehicleModel.dart:23:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 VehicleModelMenuState.build.<anonymous closure> (package:test_flutter_app/vehicleFormElements/vehicleModel.dart:30:59)
#2 _FutureBuilderState.build (package:flutter/src/widgets/async.dart:751:55)
#3 StatefulElement.build (package:flutter/src/widgets/framework.dart:4744:28)
#4 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4627:15)
Here is the deserialisation to object
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
class VehicleModels {
final List<dynamic> models;
VehicleModels({this.models});
factory VehicleModels.fromJson(Map<String,dynamic> json){
return VehicleModels(
models: json['data']['results'],
);
}
}
Future<VehicleModels> getVehicleModels(String cookie)async{
final http.Response response = await http.get(
'https://gara6.bg/auto-api/vehicleModels?pageSize=2147483647',
headers: <String, String>{
'Content-Type': 'application/json',
'cookie':cookie,
},
);
if(response.statusCode==200){
return VehicleModels.fromJson(jsonDecode(utf8.decode(response.bodyBytes)));
}
else{
throw Exception('Failed to retrieve vehicle models');
}
}
If any entry in your JSON is missing vehicleBrand you will get that null error.
Since you're accessing nested JSON data (i.e. Map class) directly, you have to check each nested level actually has data or else you can get a null error trying to access a value when the object is null.
So this:
if (snapshot.data.models[i]['vehicleBrand']['name']==brandName) {
// do something
}
should be something like this:
if (snapshot.data.models[i] != null && snapshot.data.models[i]['vehicleBrand'] != null && snapshot.data.models[i]['vehicleBrand']['name'] == brandName) {
// do something
}
In general, directly accessing JSON data like this is unsafe, repetitive and verbose. It would probably be better to convert your JSON data into objects (i.e. deserialize) where you can get the benefits of Type-safety (properties are the type you're expecting) & can create methods/getters that produce safe/sane values so you don't get null errors when data isn't perfect.
Check out the Flutter article on serialization for more info.

How to deal with complex API responses for making cards in Flutter?

I am very new to Flutter and now developing an app that lists restaurants.
I have an API endpoint that returns JSON data. Here it is: https://node.coredes.in/restaurants.
I have already done the layouts. But I don't know how to deal with JSON data. I already tried to do this from examples I got from net.
I want to know how can I use these fields - doc.name, doc.image_gallery[0], doc.location.locality, doc.friday.closing_at.hour, doc.friday.closing_at.minute, to make a list of cards?
Could anyone please help me out with a sample code?
Here is a sample code below, shows how to get the name of restaurants in your JSON file:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
void main() {
runApp(new MaterialApp(
home: new HomePage(),
));
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String url = "https://node.coredes.in/restaurants/";
List data;
/*onCreate*/
#override
void initState() {
// TODO: implement initState
super.initState();
getJSONData(); //method
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: Text("my JSON app")),
body: new ListView.builder(
// itemCount: 1,
//itemCount: data==null ? 0 :data.length ,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
return new Container(
child: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Card(
child: new Container(
child: new Text(data[index]['name'] ?? ''),
padding: EdgeInsets.all(20),
),
)
],
),
),
);
},
),
);
}
/*method*/ //RT is Future<String>
Future<String> getJSONData() async {
var response = await http
.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
print(response.body);
debugPrint(response.body);
setState(() {
var convertDataToJson = json.decode(response.body);
data = convertDataToJson['doc'];
});
return "Success";
}
}
And you can play with data[index]['name']. For example if you want the city you can do something like that data[index]['location']['city'].
So the class model you said, is in order to make your code easy to understand and fast to be reused. Your JSON file have a complex embedded data on it, and it's a little difficult to access this data. So using a class model will be very helpful to get easily, whatever the value you want from it. Let me show you that with a concret example, to know when a restaurant will open and close, you need to go along with this hierarchy doc => opening_times => Sunday => opening_at and the same for the closing time. So let's translate it to our flutter code, if we want to get just the hour value, it will be like data[index]['opening_time']['Sunday']['opening_at']['hour'], and the same for minute value, same for all the rest. In this hierarchy we didn't took so long to arrive to the end, but you're free to imagine in a very big hierarchy, how it will be the situation. Let's return to our case, now let's take the same example and try to use, like you said, a class model instead of a hard coded JSON attributs. Let's write a model class for Restaurant.
class Restaurant {
String name;
String city;
String day;
bool isOpen;
int hourOpen;
int minuteOpen;
// ..
// ..
// The rest of your wanted attributs
Restaurant(
{this.name,
this.city,
this.day,
this.isOpen,
this.hourOpen,
this.minuteOpen});
}
After that, we will write a method, its main goal is to fill our restaurants variable.
Future<String> getRestaurants() async {
var response = await http
.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
var convertDataToJson = json.decode(response.body);
data = convertDataToJson['doc'];
List tempRestaurants = new List();
data.forEach((restaurant) => {
tempRestaurants.add(new Restaurant(
name: restaurant['name'],
city: restaurant['location']['city'],
day: 'Sunday',
isOpen: restaurant['opening_times']['Sunday']['is_open_today'],
hourOpen: restaurant['opening_times']['Sunday']['opening_at']
['hour'],
minuteOpen: restaurant['opening_times']['Sunday']['opening_at']
['minute'])),
});
setState(() {
this.restaurants = tempRestaurants;
});
}
Here is how we get data after writing the model.
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: Text("my JSON app")),
body: new ListView.builder(
itemCount: restaurants == null ? 0 : restaurants.length,
itemBuilder: (BuildContext context, int index) {
return new Container(
child: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Card(
child: new Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Name: ${restaurants[index].name}"),
Text("City: ${restaurants[index].city}"),
Text("Day: ${restaurants[index].day}"),
Text("IsOpen: ${restaurants[index].isOpen}"),
Text(
"Time: ${restaurants[index].hourOpen}:${restaurants[index].minuteOpen}"),
]),
padding: EdgeInsets.all(20),
),
)
],
),
),
);
},
),
);
}
PS: in this example, I just took Sunday value in every restaurant instance, so that I can show you how easily the access to data has become. But you can create a class model for it, let's say RestaurantDay, and have attributs like dayName, hourOpen, minuteOpen... And after that, you can link it with the logic where we get data.
Try this:
class DemoClass {
String name;
int Id;
DemoClass(this.name, this.Id);
static DemoClass fromJson(Map<String, dynamic> json) {
return DemoClass(json['name'] as String, json['Id'] as int);
}
Map<String, dynamic> toJson(DemoClass instance) =>
<String, dynamic>{
'name': instance.name,
'Id': instance.trackerId
};
static List<DemoClass> fromJsonListStr(String jsonStr){
var list = jsonDecode(jsonStr) as List;
List<DemoClass> myThing = list.map((e) => DemoClass.fromJson(e)).toList();
return myThing;
}
}
Use this to get a list of objects:
var resp = await http.get('http://apicall.com/array',
headers: {"Content-Type": "application/json"});
var ret = DemoClass.fromJsonListStr(resp.body);
return ret;
Use this to get a single object:
var resp = await http.get('http://apicall.com/array',
headers: {"Content-Type": "application/json"});
var data = jsonDecode(resp.body);
var obj = DemoClass.fromJson(data);

Flutter JSON duplicate index

I have a list of users that I am reading from JSON.
This is the JSON file:
{
"Dependents": [
{
"Name": "Kim",
"Relationship": "Parent"
},
{
"Name": "Tim",
"Relationship": "Spouse"
}
]
}
This is the model class:
new_fifth_model.dart
class NewFifthModel {
String name;
String relationship;
NewFifthModel(this.name, this.relationship);
}
And this is the class to bring out the users in a list.
NewFifth.dart
import 'package:flutter/material.dart';
import 'package:emas_app/model/new_fifth_model.dart';
import 'dart:convert';
import 'dart:async' show Future;
import 'package:http/http.dart' as http;
final String url = "http://crm.emastpa.com.my/MemberInfo.json";
final int page = 5;
//Future to get list of dependent names
Future<List<NewFifthModel>> fetchUserInfo() async{
var response = await http.get(url, headers: {"Accept": "application/json"});
List data = json.decode(response.body)["Dependents"];
var fifthmodel = <NewFifthModel>[];
data.forEach((f) => fifthmodel.add(new NewFifthModel(f["Name"], f["Relationship"])));
print(fifthmodel);
return fifthmodel;
}
class NewFifth extends StatefulWidget {
#override
_FifthState createState() => _FifthState();
}
class _FifthState extends State<NewFifth> {
List<NewFifthModel> fifthList;
#override
void initState() {
super.initState();
if (fifthList == null) {
fetchUserInfo().then((data) {
this.setState(() {
fifthList = data;
});
});
}
}
#override
Widget build(BuildContext context) {
//body widget
Widget _createBody() {
if(fifthList == null){
return new Center(
child: new CircularProgressIndicator(),
);
}
else{
return new ListView.builder(
shrinkWrap: true,
itemCount: fifthList.length,
itemBuilder: (context, index){
return new Column(
children: fifthList.map((f){
return new Card(
child: new ListTile(
title: new Text(f.name),
subtitle: new Text(f.relationship),
trailing: new Text(index.toString()),
onTap: (){
makeDialog(index.toString());
},
),
);
}).toList(),
);
});
}
}
return new Scaffold(
body: _createBody(),
);
}
}
This is the output on the screen.
The problem I am having (as you can see in the picture) is that the index number I put in the trailing part of the ListTile is duplicating and I really need the index number in order to proceed.
How do I rectify this problem?
Any help is very much appreciated.
you are creating 2 list here, you are recreating a Column with the entire list inside the item build, the ListView.builder is already taking care of iterating on your list using the itemCount.
itemBuilder: (context, index) {
final f = fifthList[index];
return Card(
child: new ListTile(
title: new Text(f.name),
subtitle: new Text(f.relationship),
trailing: new Text(index.toString()),
onTap: (){
makeDialog(index.toString());
},
),
);
}
Looks like you have only 2 items in the JSON object but you are showing 4.
I think you meant to only show 2? If so, in your itemBuilder function, you should do this:
return new ListView.builder(
shrinkWrap: true,
itemCount: fifthList.length,
itemBuilder: (context, index) {
var f = fifthList[index];
return new Card(
child: new ListTile(
title: new Text(f.name),
subtitle: new Text(f.relationship),
trailing: new Text(index.toString()),
onTap: () {
makeDialog(index.toString());
},
),
);
});
You were using .map() which looped through the list again on each item. You had 2 items, so you ended up with 4. If you had 3, it would show 6 items, and so on.