I am beginner in flutter ,I used an API of soccer to get some information of player transferts ,so I have created a model class that contains only the information that I need to ,but when I executed, I had this error:
E/flutter ( 5073): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
E/flutter ( 5073): #0 new Transferts.fromJson (package:tl_fantasy/models/transfert_json.dart:12:26)
E/flutter ( 5073): #1 _PlayerDetailsState.getTeams.<anonymous closure>.<anonymous closure> (package:tl_fantasy/players/player_details.dart:45:45)
So I changed my model class
if i put this in the model class it works when i put it for example json['transfers'][0]['date'], but the problem is it gives me only the first result , what i need is all results, how to replace[0] by a kind of index or something? how to take all elements?
Here the json that i am trying to access:
{
"response": [
{
"player": {
"id": 35845,
"name": "Hernán Darío Burbano"
},
"update": "2020-02-06T00:08:15+00:00",
"transfers": [
{
"date": "2019-07-15",
"type": "Free",
"teams": {
"in": {
"id": 2283,
"name": "Atlas",
"logo": "https://media.api-sports.io/football/teams/2283.png"
}
}
},
{
"date": "2019-01-01",
"type": "N/A",
"teams": {
"in": {
"id": 1937,
"name": "Atletico Atlas",
"logo": "https://media.api-sports.io/football/teams/1937.png"
}
}
}
]
}
]
}
Here my model class tranfert_json:
class Response {
Player player;
String update;
List<Transfers> transfers;
Response({this.player, this.update, this.transfers});
Response.fromJson(Map<String, dynamic> json) {
player = json['player'] != null ? new Player.fromJson(json['player']) : null;
update = json['update'];
if (json['transfers'] != null) {
transfers = new List<Transfers>();
json['transfers'].forEach((v) { transfers.add(new Transfers.fromJson(v)); });
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.player != null) {
data['player'] = this.player.toJson();
}
data['update'] = this.update;
if (this.transfers != null) {
data['transfers'] = this.transfers.map((v) => v.toJson()).toList();
}
return data;
}
}
class Player {
int id;
String name;
Player({this.id, this.name});
Player.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}
class Transfers {
String date;
String type;
Teams teams;
Transfers({this.date, this.type, this.teams});
Transfers.fromJson(Map<String, dynamic> json) {
date = json['date'];
type = json['type'];
teams = json['teams'] != null ? new Teams.fromJson(json['teams']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['date'] = this.date;
data['type'] = this.type;
if (this.teams != null) {
data['teams'] = this.teams.toJson();
}
return data;
}
}
class Teams {
In teamIn;
Teams({this.teamIn});
Teams.fromJson(Map<String, dynamic> json) {
teamIn = json['in'] != null ? new In.fromJson(json['in']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.teamIn != null) {
data['in'] = this.teamIn.toJson();
}
return data;
}
}
class In {
int id;
String name;
String logo;
In({this.id, this.name, this.logo});
In.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
logo = json['logo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['logo'] = this.logo;
return data;
}
}
Here my player_details class:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:tl_fantasy/models/transfert_json.dart';
class PlayerDetails extends StatefulWidget {
int id;
String name;
String lastname;
String image;
String club;
String position;
String nationality;
String age;
int matches;
String goals;
String assists;
String saves;
PlayerDetails({this.id,this.name, this.lastname,this.image, this.club, this.position,
this.nationality, this.age, this.matches, this.goals, this.assists, this.saves});
#override
_PlayerDetailsState createState() => _PlayerDetailsState();
}
class _PlayerDetailsState extends State<PlayerDetails> {
List<Response> teams = [];
Future<void> getTeams(int id) async {
http.Response response = await http.get(
'https://v3.football.api-sports.io/transfers?player=$id',
headers: {'x-rapidapi-key': 'c52370f8295e1525b7f7ba38655e243f',
'x-rapidapi-host':'v3.football.api-sports.io'});
String body = response.body;
var data = jsonDecode(body);
List<dynamic> clubList = data['response'];
setState(() {
teams = clubList
.map((dynamic item) => Response.fromJson(item))
.toList();
});
}
#override
void initState() {
super.initState();
getTeams(widget.id);
}
#override
Widget build(BuildContext context) {
if(widget.matches == null ){
widget.matches == 0;
}
if(widget.goals == null ){
widget.goals == "0";
}
if(widget.assists == null ){
widget.assists == "0";
}
if(widget.saves == null ){
widget.saves == "0";
}
List<Stats> stats = [
Stats("Matches", widget.matches.toString() ),
Stats("Goals", widget.goals ),
Stats("Assists", widget.assists ),
Stats("Saves", widget.saves ),
];
return Scaffold(
appBar: AppBar(
title: Text("Player Details"),
backgroundColor: Colors.blue[300],
elevation: 0.0,
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Colors.purple, Colors.blue])
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.purple, Colors.black38])),
child: ListView(
children: [
SizedBox(
height: 20,
),
Container(
margin: EdgeInsets.fromLTRB(8.0,0,8.0,0),
width: double.infinity,
child: Card(
elevation: 4.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child:
Row(
children: <Widget>[
Container(
height: 60,
width: 60,
child:
Image.network(this.widget.image,
),
),
const SizedBox(width:10.0),
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget> [
Text(widget.name, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0,
)),
Text(widget.lastname, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0,
)),
const SizedBox(height: 5.0, ),
Text(widget.club, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0,
)),
const SizedBox(height: 5.0, ),
Text("Role : "+widget.position, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0, color: Colors.grey[600],
)),
const SizedBox(height: 5.0, ),
Text("Age : "+widget.age, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0, color: Colors.grey[600],
)),
const SizedBox(height: 5.0, ),
Text("Nationality : "+widget.nationality, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0, color: Colors.grey[600],
)),
],
),
],
),
),
),
),
Container(
margin: EdgeInsets.fromLTRB(10, 15, 0, 0),
child: Text(
"Season Stats",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w900, color: Colors.white),
),
),
SizedBox(
height: 10,
),
Container(
padding: EdgeInsets.all(12.0),
child: GridView.builder(
shrinkWrap: true,
itemCount: stats.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0
),
itemBuilder: (BuildContext context, int index){
return Card(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.fromLTRB(0, 5, 0, 0),
child: Text(stats[index].result,style: TextStyle(fontSize: 20.0)),
),
Container(
alignment: Alignment.bottomCenter,
child: Text(stats[index].title,style: TextStyle(fontSize: 25.0)),),
]
),
),
);
},
)
),
SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.fromLTRB(10, 0, 0, 10),
child: Text(
"Teams",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w900, color: Colors.white),
),
),
SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.fromLTRB(5, 0, 5, 0),
child: ListView.builder(
shrinkWrap: true,
physics : NeverScrollableScrollPhysics(),
itemBuilder: (context, index){
return Card(
elevation: 4.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child:
Row(
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage(teams[index].transfers[index].teams.teamIn.logo),
),
const SizedBox(width:10.0),
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget> [
Text(teams[index].transfers[index].teams.teamIn.name, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0,
)),
const SizedBox(height: 5.0, ),
Text("joined : "+teams[index].transfers[index].date, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0, color: Colors.grey[600],
)),
],
),
],
),
),
);
},
itemCount: teams.length,
),
),
SizedBox(
height: 70,
),
],
),
)
),
);
}
}
class Stats{
String title;
String result;
Stats(this.title,this.result);
}
class Team {
String name;
String image;
String date;
Team(this.name,this.image,this.date);
}
i am trying to find a way to get all results , not just the first index of my api json
Example of nested ListviewBuilder , don't forget to add shrinkWrap inside the listview
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
shrinkWrap: true,
itemCount: teams.length,
itemBuilder: (BuildContext context, int index) {
List<Transfers> transfers = teams[index].transfers;
return ListView.builder(
shrinkWrap: true,
itemCount: transfers.length,
itemBuilder: (BuildContext context, int index) {
return Text(transfers[index].teams.teamIn.name);
},
) ;
},
),
);
}
Related
when click the showModalBottomSheet it's show on the screen
Null Check operator used on a null value
can anyone help to figure out which is the code error? kindly refer full code as below, TQ!
class ProductContentFirst extends StatefulWidget {
final List _productContentList;
const ProductContentFirst(this._productContentList, {Key? key})
: super(key: key);
#override
State<ProductContentFirst> createState() => _ProductContentFirstState();
}
class _ProductContentFirstState extends State<ProductContentFirst> {
ProductContentItem? _productContent;
List _attr = [];
#override
void initState() {
super.initState();
_productContent = widget._productContentList[0];
this._attr = this._productContent!.attr!;
//print(this._attr);
}
List<Widget>? _getAttrItemWidget(attrItem) {
List<Widget> attrItemList = [];
attrItem.list.forEach((item) {
attrItemList.add(Container(
margin: EdgeInsets.all(5),
child: Chip(
label: Text("${item}"),
padding: EdgeInsets.all(10),
),
));
print (item);
});
}
List<Widget>? _getAttrWidget() {
List<Widget> attrList = [];
this._attr.forEach((attrItem) {
attrList.add(Wrap(
children: [
Container(
width: ScreenAdapter.width(80.0),
child: Padding(
padding: EdgeInsets.only(top: ScreenAdapter.height(30.0)),
child: Text(
"${attrItem.cate}",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
),
Container(
width: ScreenAdapter.width(600.0),
child: Wrap(
//children: [],
children: _getAttrItemWidget(attrItem)!,
),
)
],
));
print(attrItem.cate);
});
//return null;
}
_attrBottomSheet() {
showModalBottomSheet(
context: context,
builder: (context) {
return GestureDetector(
onTap: () {
false;
},
child: Stack(
children: [
Container(
padding: EdgeInsets.all(10),
child: ListView(
children: [
Column(
children: _getAttrWidget()!,
)
],
),
),
Positioned(
bottom: 0,
width: ScreenAdapter.width(750.0),
height: ScreenAdapter.height(100),
child: Row(
children: [
Expanded(
flex: 1,
child: Container(
child: JdButton(
color: Color.fromRGBO(253, 1, 0, 0.9),
text: "Add Cart",
cb: () {
print("Add Cart");
},
),
)),
Expanded(
flex: 1,
child: Container(
child: JdButton(
color: Color.fromRGBO(255, 165, 0, 0.9),
text: "Buy",
cb: () {
print("Buy");
},
),
)),
],
))
],
),
);
});
}
#override
Widget build(BuildContext context) {
String pic = Config.domain + this._productContent!.pic!;
pic = pic.replaceAll("\\", "/");
return Container(
padding: EdgeInsets.all(10.0),
child: ListView(
children: [
AspectRatio(
aspectRatio: 16 / 12,
child: Image.network(
"${pic}",
fit: BoxFit.cover,
),
),
Container(
padding: EdgeInsets.only(top: 7),
child: Text(
"${this._productContent!.title}",
style: TextStyle(
color: Colors.black87, fontSize: ScreenAdapter.size(36)),
),
),
Container(
padding: EdgeInsets.only(top: 7),
child: Text(
"${this._productContent!.subTitle}",
style: TextStyle(
color: Colors.black54, fontSize: ScreenAdapter.size(28)),
),
),
Container(
padding: EdgeInsets.only(top: 7),
child: Row(
children: [
Expanded(
flex: 1,
child: Row(
children: [
Text("Price: "),
Text(
"${this._productContent!.price}",
style: TextStyle(
color: Colors.red,
fontSize: ScreenAdapter.size(46)),
)
],
),
),
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text("Old Price: "),
Text(
"${this._productContent!.oldPrice}",
style: TextStyle(
color: Colors.black38,
fontSize: ScreenAdapter.size(32),
decoration: TextDecoration.lineThrough),
),
],
),
),
],
),
),
Container(
margin: EdgeInsets.only(top: 7),
height: ScreenAdapter.height(80.0),
child: InkWell(
onTap: () {
_attrBottomSheet();
},
child: Row(
children: [
Text(
"Select:",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text("115, Black, XL, 1 pcs")
],
),
),
),
Divider(),
Container(
height: ScreenAdapter.height(80.0),
child: Row(
children: [
Text(
"Delivery Fees:",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text("Free Delivery")
],
),
),
Divider(),
],
),
);
}
}
class ProductContentModel {
ProductContentItem? result;
ProductContentModel({this.result});
ProductContentModel.fromJson(Map<String, dynamic> json) {
result = json['result'] != null
? new ProductContentItem.fromJson(json['result'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.result != null) {
data['result'] = this.result!.toJson();
}
return data;
}
}
class ProductContentItem {
String? sId;
String? title;
String? cid;
Object? price;
String? oldPrice;
Object? isBest;
Object? isHot;
Object? isNew;
String? status;
String? pic;
String? content;
String? cname;
List<Attr>? attr;
String? subTitle;
Object? salecount;
ProductContentItem(
{this.sId,
this.title,
this.cid,
this.price,
this.oldPrice,
this.isBest,
this.isHot,
this.isNew,
this.status,
this.pic,
this.content,
this.cname,
this.attr,
this.subTitle,
this.salecount});
ProductContentItem.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
title = json['title'];
cid = json['cid'];
price = json['price'];
oldPrice = json['old_price'];
isBest = json['is_best'];
isHot = json['is_hot'];
isNew = json['is_new'];
status = json['status'];
pic = json['pic'];
content = json['content'];
cname = json['cname'];
if (json['attr'] != null) {
attr = <Attr>[];
json['attr'].forEach((v) {
attr!.add(new Attr.fromJson(v));
});
}
subTitle = json['sub_title'];
salecount = json['salecount'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['_id'] = this.sId;
data['title'] = this.title;
data['cid'] = this.cid;
data['price'] = this.price;
data['old_price'] = this.oldPrice;
data['is_best'] = this.isBest;
data['is_hot'] = this.isHot;
data['is_new'] = this.isNew;
data['status'] = this.status;
data['pic'] = this.pic;
data['content'] = this.content;
data['cname'] = this.cname;
if (this.attr != null) {
data['attr'] = this.attr!.map((v) => v.toJson()).toList();
}
data['sub_title'] = this.subTitle;
data['salecount'] = this.salecount;
return data;
}
}
class Attr {
String? cate;
List<String>? list;
Attr({this.cate, this.list});
Attr.fromJson(Map<String, dynamic> json) {
cate = json['cate'];
list = json['list'].cast<String>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['cate'] = this.cate;
data['list'] = this.list;
return data;
}
}
When the exception was thrown, this was the stack:
\#0 \_ProductContentFirstState.\_getAttrWidget.\<anonymous closure (package:flutter_jdshop/pages/ProductContent/ProductContentFirst.dart:64:54)
Don't use ! without checking null. While the snippet is large, follow these steps.
Check null, and then perform operation the place you've used !. It will be like if(result!=null)result.add(new FocusItemModel.fromJson(v));
the children can be children: _getAttrItemWidget(attrItem)??[]
You aren't returning widgets from _getAttrItemWidget and others. It will be
List<Widget> _getAttrItemWidget(attrItem) { // no need to return null
List<Widget> attrItemList = [];
attrItem.list.forEach((item) {
....
print (item);
});
return attrItemList;
}
In short Don't use ! without checking null. or provide default value on null case.
Find more about null-safety.
I am fairly new to using REST API to GET data and display in a Listview in Flutter. I have since been working on something like this, But i get Lost along the line. Hence I need Help with this.
My code Goes thus
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class TransactionDetails {
final String avatar;
final String name;
final String date;
final String amount;
TransactionDetails({required this.avatar, required this.name, required this.date, required this.amount});
factory TransactionDetails.fromJson(Map<String, dynamic> json) {
return TransactionDetails(
avatar: json['avatar'],
name: json['name'],
date: json['date'],
amount: json['amount']);
}
}
class BaseScreen extends StatelessWidget {
const BaseScreen({Key? key}) : super(key: key);
Future<TransactionDetails> fetchTransaction() async {
final response = await http
.get('https://brotherlike-navies.000webhostapp.com/people/people.php');
if (response.statusCode == 200) {
return TransactionDetails.fromJson(json.decode(response.body));
} else {
throw Exception('Request Failed.');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
height: 150,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
margin: const EdgeInsets.all(15),
width: 319,
height: 100,
color: Colors.green,
alignment: Alignment.center,
child: const Text(
'\$5200.00',
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
Container(
margin: const EdgeInsets.all(15),
width: 319,
height: 100,
color: Colors.green,
alignment: Alignment.center,
child: const Text(
'\$1200.00',
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
SizedBox(height: 24),
],
),
),
Padding(
padding: EdgeInsets.all(15),
child: Text(
"Recent Transactions",
style: TextStyle(
fontSize: 14, fontWeight: FontWeight.bold, color: Colors.green),
),
),
ListView() //Display the data here from the REST API
],
)));
}
}
How do I Display it on the Listview? Please I need help with this. Just for the sake of clarification as I am learning here with this.
Try below code:
Your TransactionDetails Class
class TransactionDetails {
String? avatar;
String? name;
String? date;
String? amount;
TransactionDetails({
this.avatar,
this.name,
this.date,
this.amount,
});
TransactionDetails.fromJson(Map<String, dynamic> json) {
avatar = json['avatar'];
name = json['name'];
date = json['date'];
amount = json['amount'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['avatar'] = avatar;
data['name'] = name;
data['date'] = date;
data['amount'] = amount;
return data;
}
}
API Call:
Future<List<TransactionDetails>> fetchAlbum() async {
final response = await http.get(Uri.parse(
'https://brotherlike-navies.000webhostapp.com/people/people.php'));
if (response.statusCode == 200) {
final List result = json.decode(response.body);
return result.map((e) => TransactionDetails.fromJson(e)).toList();
} else {
throw Exception('Failed to load data');
}
}
Your Widget:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
height: 150,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
margin: const EdgeInsets.all(15),
width: 319,
height: 100,
color: Colors.green,
alignment: Alignment.center,
child: const Text(
'\$5200.00',
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
Container(
margin: const EdgeInsets.all(15),
width: 319,
height: 100,
color: Colors.green,
alignment: Alignment.center,
child: const Text(
'\$1200.00',
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 24),
],
),
),
const Padding(
padding: EdgeInsets.all(15),
child: Text(
"Recent Transactions",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.green),
),
),
Center(
child: FutureBuilder<List<TransactionDetails>>(
future: fetchAlbum(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: Image.network(
snapshot.data![index].avatar.toString()),
),
title: Text(snapshot.data![index].name.toString()),
trailing:
Text(snapshot.data![index].amount.toString()),
subtitle: Text(snapshot.data![index].date.toString()),
);
},
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
),
],
),
Result Screen->
There are multiple ways you can achieve this.
Using FutureBuilder
Using StatefulWidget & setState
Currently, you are using a StatelessWidget (BaseScreen) so let's just go with FutureBuilder.
On hitting the url that you have given:
https://brotherlike-navies.000webhostapp.com/people/people.php
It gives the following response:
[{"avatar":"https:\/\/static.vecteezy.com\/system\/resources\/thumbnails\/002\/002\/403\/small\/man-with-beard-avatar-character-isolated-icon-free-vector.jpg","name":"Kayo Johnson","date":"09\/29\/2022","amount":"5000.00"},{"avatar":"https:\/\/static.vecteezy.com\/system\/resources\/thumbnails\/002\/002\/403\/small\/man-with-beard-avatar-character-isolated-icon-free-vector.jpg","name":"Kuta Joy","date":"09\/29\/2022","amount":"5000.00"},{"avatar":"https:\/\/static.vecteezy.com\/system\/resources\/thumbnails\/001\/993\/889\/small\/beautiful-latin-woman-avatar-character-icon-free-vector.jpg","name":"Timmi Phillips","date":"09\/28\/2022","amount":"3500.00"}]
It returns a list of transaction details objects. Hence, you should add another method in your model TransactionDetail which will return a list of TransactionDetails as follows:
class TransactionDetails {
final String avatar;
final String name;
final String date;
final String amount;
TransactionDetails(
{required this.avatar,
required this.name,
required this.date,
required this.amount});
factory TransactionDetails.fromJson(Map<String, dynamic> json) {
return TransactionDetails(
avatar: json['avatar'],
name: json['name'],
date: json['date'],
amount: json['amount']);
}
static List<TransactionDetails> fromJsonList(dynamic jsonList) {
final transactionDetailsList = <TransactionDetails>[];
if (jsonList == null) return transactionDetailsList;
if (jsonList is List<dynamic>) {
for (final json in jsonList) {
transactionDetailsList.add(
TransactionDetails.fromJson(json),
);
}
}
return transactionDetailsList;
}
}
Update your fetchTransaction method as follows:
Future<List<TransactionDetails>> fetchTransaction() async {
final response = await http
.get('https://brotherlike-navies.000webhostapp.com/people/people.php');
if (response.statusCode == 200) {
return TransactionDetails.fromJsonList(json.decode(response.body));
} else {
throw Exception('Request Failed.');
}
}
Just wrap your ListView widget with a FutureBuilder widget as follows:
FutureBuilder(
future: fetchTransaction(),
builder: (context, AsyncSnapshot<List<TransactionDetails>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) {
return const Center(child: Text('Something went wrong'));
}
return ListView.builder(
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data![index].name),
subtitle: Text(snapshot.data![index].amount),
);
});
}
return const CircularProgressIndicator();
},
),
Help me please, How can I get this data in single page. When I trying to fetch data from api I get this error :
type '(dynamic) => ProductDetailsModel' is not a subtype of type '(String, dynamic) => MapEntry<dynamic, dynamic>' of 'transform' - Flutter.
I need to just show data in single page. I am trying to get data with Future Builder not get.
This is my onTap:
onTap: () {singleProductDataC.getSingleProductData(
productId: item.id,
productSlug: item.slug,
);
.
This Is My Api :
{
"productdetails": {
"id": 1,
"proCategory": "1",
"proSubcategory": "1",
"proChildCategory": "1",
"proBrand": null,
"proShop": null,
"proName": "Nestle LACTOGEN 1 Infant Formula With Iron TIN",
"slug": "nestle-lactogen-1-infant-formula-with-iron-tin",
"proPurchaseprice": "550",
"proOldprice": "750",
"proNewprice": "630",
"proCode": null,
"proLimit": null,
"proDescription": "<ul><li> is a super quality online super shop that, at this moment has service in Dhaka city. ",
"proQuantity": "12",
"aditionalshipping": null,
"combo": null,
"offer": null,
"video": null,
"unit": "400 gm",
"deliveryarea": null,
"homedelivery": null,
"returnwarranty": null,
"codavailable": null,
"warranty": null,
"proLocation": "1",
"ratting": "12.1",
"status": "1",
"created_at": "2022-01-01T20:51:03.000000Z",
"updated_at": "2022-02-12T05:58:43.000000Z",
"reviews_count": "3",
"category": {
"id": 1,
"name": "Fruits & Vegetables",
"slug": "fruits--vegetables",
"image": "public/uploads/category/1642326298-fruits-and-vegetables.png",
"frontProduct": "1",
"level": null,
"status": "1",
"created_at": "2022-01-01T18:15:36.000000Z",
"updated_at": "2022-01-15T22:44:58.000000Z"
},
"brand": null
},
"images": [
{
"id": 6,
"product_id": "1",
"image": "public/uploads/product/1644645523-1644066476-0129980_khusboo-premium-olive-pickles-400-gm.jpeg",
"created_at": "2022-02-12T05:58:43.000000Z",
"updated_at": "2022-02-12T05:58:43.000000Z"
}
]
}
This Is My Controller
import 'package:Darucheeni/src/configs/appConfigs.dart';
import 'package:Darucheeni/src/pages/productPage/productDetailsPage.dart';
import 'package:dio/dio.dart';
import 'package:get/get.dart';
class ProductDetailsController extends GetxController {
final dio = Dio();
final singleProductsList = RxList<ProductDetailsModel>();
getSingleProductData({
String? productSlug,
int? productId,
}) async {
final res = await dio.get(
baseUrl + 'product-details/$productId/$productSlug',
);
final List<ProductDetailsModel> productDetaisData = res
.data['productdetails']
.map((json) => ProductDetailsModel.fromJson(json))
.toList()
.cast<ProductDetailsModel>();
print('------------------------------>');
print('Status Code : ${res.statusCode}');
print('Headers : ${res.headers}');
print('realUri : ${res.realUri}');
print('statusMessage : ${res.statusMessage}');
print('requestOptions : ${res.requestOptions}');
print(res.data['productdetails']);
print('------------------------------>');
await Get.to(ProductDetailsPage());
print(res.data);
if (res.statusCode == 200) {
print(productDetaisData);
singleProductsList.addAll((res.data as List)
.map((e) => ProductDetailsModel.fromJson(e))
.toList());
}
}
}
This Is My Details Page :
import 'package:Darucheeni/src/LottieAnimation/loadingLottie.dart';
import 'package:Darucheeni/src/controllers/mainController/baseController.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:Darucheeni/src/configs/appColors.dart';
import 'package:Darucheeni/src/widgets/textWidget/kText.dart';
import '../../configs/appConfigs.dart';
import '../../configs/iconAndImages.dart';
import '../../widgets/QuantityWidget/quantityWidgets.dart';
import '../../widgets/button/customBackButton.dart';
class ProductDetailsPage extends StatefulWidget with BaseController {
// final int? productId;
// final String? productSlug;
// ProductDetailsPage({
// this.productId,
// this.productSlug,
// });
#override
State<ProductDetailsPage> createState() => _ProductDetailsPageState();
}
class _ProductDetailsPageState extends State<ProductDetailsPage>
with BaseController {
bool isAddtoBag = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
leading: customBackButton(),
title: KText(
text: 'Product Details',
fontSize: 25,
color: black,
fontWeight: FontWeight.w500,
fontFamily: brushScriptFonts,
),
),
body: ListView(
children: [
// future builder give me some error
// FutureBuilder<Map<String, dynamic>>(
// future: singleProductDataC.getSingleProductData(),
// builder: ((context, snapshot) {
// print('-----------------------> ${snapshot.data}');
// if (!snapshot.hasData) {
// return LoadingLottie();
// }
// final products = snapshot.data!;
// print('-----------------------> $products');
// return Column(
// children: [
// Stack(
// children: [
// // Container(
// // color: white,
// // height: 250,
// // width: Get.width,
// // child: CachedNetworkImageWidget(
// // imageUrl: products!.imagesModel!.image.toString(),
// // ),
// // ),
// Positioned(
// top: 30,
// child: Image.asset(
// discountArrow,
// scale: 2,
// ),
// ),
// Positioned(
// top: 30,
// child: KText(
// text: ' -10%',
// color: white,
// fontSize: 16,
// fontWeight: FontWeight.bold,
// ),
// ),
// ],
// ),
// sizeH20,
// Padding(
// padding: paddingHori20,
// child: KText(
// text: products['proName'],
// fontSize: 25,
// color: black,
// maxLines: 100,
// fontFamily: segoeBoldFonts,
// ),
// ),
// sizeH20,
// sizeH20,
// Padding(
// padding: paddingHori20,
// child: Row(
// children: [
// KText(
// text: '৳ ',
// fontSize: 25,
// ),
// KText(
// text: products['proNewprice'],
// fontSize: 30,
// fontWeight: FontWeight.bold,
// ),
// sizeW20,
// KText(
// text: '৳ ${products['proOldprice']}',
// fontSize: 25,
// color: black54,
// decoration: TextDecoration.lineThrough,
// fontWeight: FontWeight.bold,
// ),
// Spacer(),
// KText(
// text: 'Unit : ',
// fontSize: 18,
// color: black,
// fontWeight: FontWeight.bold,
// ),
// KText(
// text: products['unit'],
// fontSize: 22,
// fontWeight: FontWeight.bold,
// ),
// ],
// ),
// ),
// sizeH20,
// sizeH20,
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: [
// isAddtoBag == false
// ? InkWell(
// onTap: () {
// setState(() {
// isAddtoBag = true;
// });
// },
// child: Padding(
// padding: EdgeInsets.symmetric(horizontal: 60),
// child: Container(
// alignment: Alignment.center,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(30),
// color: white,
// ),
// child: Padding(
// padding: EdgeInsets.all(4),
// child: Container(
// alignment: Alignment.center,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(30),
// color: orange,
// ),
// child: Padding(
// padding: EdgeInsets.symmetric(
// horizontal: 30,
// vertical: 7,
// ),
// child: KText(
// text: 'Add To Bag',
// fontSize: 27,
// fontWeight: FontWeight.bold,
// color: white,
// ),
// ),
// ),
// ),
// ),
// ),
// )
// : QuantityWidget(
// iconSize: 30,
// cirecleRadius: 20,
// iconRadius: 16,
// quantityCSize: 25,
// circleColor: backgroundColor,
// ),
// ],
// ),
// sizeH10,
// Padding(
// padding: EdgeInsets.symmetric(horizontal: 10),
// child: Divider(
// color: orange,
// height: 30,
// ),
// ),
// sizeH10,
// Padding(
// padding: paddingHori20,
// child: KText(
// text: products['proName'],
// color: Colors.black45,
// fontSize: 20,
// maxLines: 100,
// fontWeight: FontWeight.w500,
// ),
// ),
// ],
// );
// }),
// ),
ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: singleProductDataC.singleProductsList.length,
itemBuilder: (context, index) {
final products = singleProductDataC.singleProductsList[index].productdetails;
print(products);
return Column(
children: [
Stack(
children: [
// Container(
// color: white,
// height: 250,
// width: Get.width,
// child: CachedNetworkImageWidget(
// imageUrl: products!.imagesModel!.image.toString(),
// ),
// ),
Positioned(
top: 30,
child: Image.asset(
discountArrow,
scale: 2,
),
),
Positioned(
top: 30,
child: KText(
text: ' -10%',
color: white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
sizeH20,
Padding(
padding: paddingHori20,
child: KText(
text: products! .proName.toString(),
fontSize: 25,
color: black,
maxLines: 100,
fontFamily: segoeBoldFonts,
),
),
sizeH20,
sizeH20,
Padding(
padding: paddingHori20,
child: Row(
children: [
KText(
text: '৳ ',
fontSize: 25,
),
KText(
text: products.proNewprice.toString(),
fontSize: 30,
fontWeight: FontWeight.bold,
),
sizeW20,
KText(
text:
'৳ ${products .proOldprice.toString()}',
fontSize: 25,
color: black54,
decoration: TextDecoration.lineThrough,
fontWeight: FontWeight.bold,
),
Spacer(),
KText(
text: 'Unit : ',
fontSize: 18,
color: black,
fontWeight: FontWeight.bold,
),
KText(
text: products .unit.toString(),
fontSize: 22,
fontWeight: FontWeight.bold,
),
],
),
),
sizeH20,
sizeH20,
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
isAddtoBag == false
? InkWell(
onTap: () {
setState(() {
isAddtoBag = true;
});
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 60),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: white,
),
child: Padding(
padding: EdgeInsets.all(4),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(30),
color: orange,
),
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: 30,
vertical: 7,
),
child: KText(
text: 'Add To Bag',
fontSize: 27,
fontWeight: FontWeight.bold,
color: white,
),
),
),
),
),
),
)
: QuantityWidget(
iconSize: 30,
cirecleRadius: 20,
iconRadius: 16,
quantityCSize: 25,
circleColor: backgroundColor,
),
],
),
sizeH10,
Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Divider(
color: orange,
height: 30,
),
),
sizeH10,
Padding(
padding: paddingHori20,
child: KText(
text: products .proName.toString(),
color: Colors.black45,
fontSize: 20,
maxLines: 100,
fontWeight: FontWeight.w500,
),
),
],
);
}),
sizeH20,
TextButton(
onPressed: () => Get.back(),
child: KText(
text: 'close',
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
sizeH20,
],
),
);
}
}
This Is My Model Class:
// ignore_for_file: unused_field
class ProductDetailsModel {
Productdetails? productdetails;
List<Images>? images;
ProductDetailsModel({this.productdetails, this.images});
ProductDetailsModel.fromJson(Map<String, dynamic> json) {
productdetails = json['productdetails'] != null
? new Productdetails.fromJson(json['productdetails'])
: null;
if (json['images'] != String) {
images = <Images>[];
json['images'].forEach((v) {
images!.add(new Images.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.productdetails != null) {
data['productdetails'] = this.productdetails!.toJson();
}
if (this.images != null) {
data['images'] = this.images!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Productdetails {
int? id;
String? proCategory;
String? proSubcategory;
String? proChildCategory;
String? proBrand;
String? proShop;
String? proName;
String? slug;
String? proPurchaseprice;
String? proOldprice;
String? proNewprice;
String? proCode;
String? proLimit;
String? proDescription;
String? shortDescription;
String? proQuantity;
String? aditionalshipping;
String? combo;
String? offer;
String? video;
String? unit;
String? deliveryarea;
String? homedelivery;
String? returnwarranty;
String? codavailable;
String? warranty;
String? proLocation;
String? ratting;
String? status;
String? createdAt;
String? updatedAt;
String? reviewsCount;
Category? category;
String? brand;
Productdetails(
{this.id,
this.proCategory,
this.proSubcategory,
this.proChildCategory,
this.proBrand,
this.proShop,
this.proName,
this.slug,
this.proPurchaseprice,
this.proOldprice,
this.proNewprice,
this.proCode,
this.proLimit,
this.proDescription,
this.shortDescription,
this.proQuantity,
this.aditionalshipping,
this.combo,
this.offer,
this.video,
this.unit,
this.deliveryarea,
this.homedelivery,
this.returnwarranty,
this.codavailable,
this.warranty,
this.proLocation,
this.ratting,
this.status,
this.createdAt,
this.updatedAt,
this.reviewsCount,
this.category,
this.brand, });
Productdetails.fromJson(Map<String, dynamic> json) {
id = json['id'];
proCategory = json['proCategory'];
proSubcategory = json['proSubcategory'];
proChildCategory = json['proChildCategory'];
proBrand = json['proBrand'];
proShop = json['proShop'];
proName = json['proName'];
slug = json['slug'];
proPurchaseprice = json['proPurchaseprice'];
proOldprice = json['proOldprice'];
proNewprice = json['proNewprice'];
proCode = json['proCode'];
proLimit = json['proLimit'];
proDescription = json['proDescription'];
shortDescription = json['shortDescription'];
proQuantity = json['proQuantity'];
aditionalshipping = json['aditionalshipping'];
combo = json['combo'];
offer = json['offer'];
video = json['video'];
unit = json['unit'];
deliveryarea = json['deliveryarea'];
homedelivery = json['homedelivery'];
returnwarranty = json['returnwarranty'];
codavailable = json['codavailable'];
warranty = json['warranty'];
proLocation = json['proLocation'];
ratting = json['ratting'];
status = json['status'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
reviewsCount = json['reviews_count'];
category = json['category'] != null
? new Category.fromJson(json['category'])
: null;
brand = json['brand'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['proCategory'] = this.proCategory;
data['proSubcategory'] = this.proSubcategory;
data['proChildCategory'] = this.proChildCategory;
data['proBrand'] = this.proBrand;
data['proShop'] = this.proShop;
data['proName'] = this.proName;
data['slug'] = this.slug;
data['proPurchaseprice'] = this.proPurchaseprice;
data['proOldprice'] = this.proOldprice;
data['proNewprice'] = this.proNewprice;
data['proCode'] = this.proCode;
data['proLimit'] = this.proLimit;
data['proDescription'] = this.proDescription;
data['shortDescription'] = this.shortDescription;
data['proQuantity'] = this.proQuantity;
data['aditionalshipping'] = this.aditionalshipping;
data['combo'] = this.combo;
data['offer'] = this.offer;
data['video'] = this.video;
data['unit'] = this.unit;
data['deliveryarea'] = this.deliveryarea;
data['homedelivery'] = this.homedelivery;
data['returnwarranty'] = this.returnwarranty;
data['codavailable'] = this.codavailable;
data['warranty'] = this.warranty;
data['proLocation'] = this.proLocation;
data['ratting'] = this.ratting;
data['status'] = this.status;
data['created_at'] = this.createdAt;
data['updated_at'] = this.updatedAt;
data['reviews_count'] = this.reviewsCount;
if (this.category != null) {
data['category'] = this.category!.toJson();
}
data['brand'] = this.brand;
return data;
}
}
class Category {
int? id;
String? name;
String? slug;
String? image;
String? frontProduct;
String? level;
String? status;
String? createdAt;
String? updatedAt;
Category(
{this.id,
this.name,
this.slug,
this.image,
this.frontProduct,
this.level,
this.status,
this.createdAt,
this.updatedAt});
Category.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
slug = json['slug'];
image = json['image'];
frontProduct = json['frontProduct'];
level = json['level'];
status = json['status'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['slug'] = this.slug;
data['image'] = this.image;
data['frontProduct'] = this.frontProduct;
data['level'] = this.level;
data['status'] = this.status;
data['created_at'] = this.createdAt;
data['updated_at'] = this.updatedAt;
return data;
}
}
class Images {
int? id;
String? productId;
String? image;
String? createdAt;
String? updatedAt;
Images({this.id, this.productId, this.image, this.createdAt, this.updatedAt});
Images.fromJson(Map<String, dynamic> json) {
id = json['id'];
productId = json['product_id'];
image = json['image'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['product_id'] = this.productId;
data['image'] = this.image;
data['created_at'] = this.createdAt;
data['updated_at'] = this.updatedAt;
return data;
}
}
In HomePage.dart i am fetching an api data by using http package and flutter_bloc for the architecture. Now once i get the data and if i select any of the item in HomePage.dart then it will be added in MenuCart.dart. Now the problem i am facing is
If i click the same item more than one time then it shows duplicate card widget.
In MenuCart.dart i have added two buttons + & - and i increases the quantity to 3 then i decided to delete the item. Now i go back to previous screen and again i add that same item and if i go to MenuCart.dart then quantity displays 4.
What i am Expecting
It should not generate duplicate card instead quantity should increment.
After i delete an item and again add the same item then quantity must show 1.
In HomePage.dart i show very limited amount of code because of lengthy, but i have added the code of bloc and MenuCart.dart.
HomePage.dart
GestureDetector(
onTap: () {
BlocProvider.of<MenuCartBloc>(context)
.add(AddToCart(data[index])); // Here adding an item in MenuCart
},
child: Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(4.5)
child: Text('ADD'),
),
),
),
);
DishMenuTypesId.dart (Model)
class DishMenuTypesIdData {
String? id;
int? status;
int? quantity;
String? dishPrice;
String? photo;
DishMenuTypesIdData({
this.id,
this.status,
this.quantity = 1,
this.dishPrice,
this.photo,
});
DishMenuTypesIdData.fromJson(Map<String, dynamic> json) {
id = json['id']?.toString();
status = json['status']?.toInt();
quantity = 1;
dishPrice = json['dish_price']?.toString();
photo = json['photo']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['id'] = id;
data['status'] = status;
data["quantity"] = quantity;
data['dish_price'] = dishPrice;
data['photo'] = photo;
return data;
}
}
class DishMenuTypesId {
String? message;
List<DishMenuTypesIdData?>? data;
DishMenuTypesId({
this.message,
this.data,
});
DishMenuTypesId.fromJson(Map<String, dynamic> json) {
message = json['message']?.toString();
if (json['data'] != null) {
final v = json['data'];
final arr0 = <DishMenuTypesIdData>[];
v.forEach((v) {
arr0.add(DishMenuTypesIdData.fromJson(v));
});
this.data = arr0;
}
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['message'] = message;
if (this.data != null) {
final v = this.data;
final arr0 = [];
v!.forEach((v) {
arr0.add(v!.toJson());
});
data['data'] = arr0;
}
return data;
}
}
MenuCartBloc.dart
class MenuCartBloc extends Bloc<MenuCartEvent, MenuCartState> {
MenuCartBloc() : super(MenuLoaded([]));
List<DishMenuTypesIdData> cart = [];
#override
Stream<MenuCartState> mapEventToState(
MenuCartEvent event,
) async* {
yield MenuLoading();
try {
if (event is AddToCart) {
final itemExist = cart.where((e) => e.id == event.dish.id);
if (itemExist.isNotEmpty) {
print("Not Empty"); // Here i am expecting to show qty 2 if i click an item more than 1 time
} else {
print("Empty");
cart.add(event.dish);
}
} else if (event is DeleteToCart) {
cart.remove(event.dish);
} else if (event is ClearAllCart) {
cart = [];
}
yield MenuLoaded(cart);
} catch (e) {
yield MenuFailed(e.toString());
}
}
}
MenuCartEvent.dart
abstract class MenuCartEvent {}
class AddToCart extends MenuCartEvent {
late final DishMenuTypesIdData dish;
AddToCart(this.dish);
}
class DeleteToCart extends MenuCartEvent {
late final DishMenuTypesIdData dish;
DeleteToCart(this.dish);
}
class ClearAllCart extends MenuCartEvent {}
MenuCartState.dart
abstract class MenuCartState {}
class MenuLoading extends MenuCartState {}
class MenuLoaded extends MenuCartState {
final List<DishMenuTypesIdData> cart;
MenuLoaded(this.cart);
}
class MenuFailed extends MenuCartState {
final String message;
MenuFailed(this.message);
}
MenuCart.dart
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
var lang = translator.activeLanguageCode;
return Container(
child: Padding(
padding: const EdgeInsets.only(top: 20.0, left: 10.0, right: 10.0),
child: BlocBuilder<MenuCartBloc, MenuCartState>(
builder: (context, state) {
DishMenuTypesIdData _cart = DishMenuTypesIdData();
if (state is MenuLoading) {
return PlatformCircularProgressIndicator();
} else if (state is MenuLoaded) {
return SingleChildScrollView(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Your Reservation Details'.tr(),
style: TextStyle(
color: TuxedoColor.blackColor,
fontSize: lang == "en" ? 14.0 : 15.0,
fontFamily: lang == "en"
? 'OpenSansBold'
: 'ArabicSemiBold'),
),
GestureDetector(
onTap: () {
BlocProvider.of<MenuCartBloc>(context)
.add(ClearAllCart());
},
child: Row(
children: [
Icon(
Icons.close,
color: TuxedoColor.redColor,
size: 15.0,
),
Text(
'Clear All'.tr(),
style: TextStyle(
color: TuxedoColor.redColor,
fontSize: 12.0,
fontFamily: lang == "en"
? 'OpenSansRegular'
: 'ArabicLight'),
),
],
),
)
],
),
SizedBox(
height: 25.0,
),
Container(
height: height * 0.3,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: state.cart.length,
itemBuilder: (BuildContext context, int index) {
_cart = state.cart[index];
return Dismissible(
key: UniqueKey(),
background: Container(
alignment: AlignmentDirectional.centerEnd,
color: TuxedoColor.redBrightColor,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.delete,
color: TuxedoColor.whiteColor,
),
),
),
onDismissed: (direction) {
BlocProvider.of<MenuCartBloc>(context)
.add(DeleteToCart(_cart));
setState(() {
state.cart.removeAt(index);
});
},
direction: DismissDirection.endToStart,
child: Card(
child: Row(
children: [
Stack(
children: [
ClipRRect(
borderRadius:
BorderRadius.circular(10.0),
child: CachedNetworkImage(
imageUrl:
_cart.photo!,
placeholder: (context, url) => Center(
child:
PlatformCircularProgressIndicator()),
errorWidget:
(context, url, error) =>
Icon(Icons.error),
width: width * 0.25,
height: height * 0.1,
fit: BoxFit.fill,
),
),
Positioned(
bottom: 0,
right: 0,
child: Container(
decoration: BoxDecoration(
color: TuxedoColor.redColor,
borderRadius: lang == "en"
? BorderRadius.only(
bottomRight:
Radius.circular(
10),
)
: BorderRadius.only(
bottomLeft:
Radius.circular(
10),
)),
height: 25.0,
width: 45.0,
child: Padding(
padding: const EdgeInsets.only(
left: 3.0, right: 3.0),
child: FittedBox(
fit: BoxFit.fitWidth,
child: Text(
'${_cart.dishPrice!} \SR',
style: TextStyle(
color: TuxedoColor
.whiteColor,
fontFamily: lang == "en"
? 'OpenSansSemiBold'
: 'ArabicSemiBold'),
),
),
),
),
)
],
),
Padding(
padding:
const EdgeInsets.only(left: 10.0),
child: Column(
children: [
Container(
width: width * 0.6,
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Container(
height: 25.0,
child: Row(
children: [
MaterialButton(
color: TuxedoColor
.redColor,
shape: CircleBorder(),
onPressed: () {
setState(() {
var minus = state
.cart[index]
.quantity;
if (minus !=
null) {
minus--;
state
.cart[index]
.quantity = minus;
}
});
},
child: Text(
'-',
style: TextStyle(
color: Colors
.white,
fontSize: 20),
),
),
Text(_cart.quantity
.toString()),
MaterialButton(
color: TuxedoColor
.redColor,
shape: CircleBorder(),
onPressed: () {
setState(() {
var add = state
.cart[index]
.quantity;
if (add != null) {
add++;
state
.cart[index]
.quantity = add;
}
});
},
child: Text(
'+',
style: TextStyle(
color: Colors
.white,
fontSize: 20),
),
),
],
),
),
GestureDetector(
onTap: () {
BlocProvider.of<
MenuCartBloc>(
context)
.add(DeleteToCart(
state.cart[
index]));
},
child: Icon(
Icons.delete,
color:
TuxedoColor.redColor,
),
)
],
),
),
SizedBox(
height: 15.0,
)
],
),
),
],
),
),
);
}),
),
],
),
);
} else if (state is MenuFailed) {
return Center(child: Text(state.message));
}
return Container();
},
)),
);
}
Something like that should work:
final itemExist = cart.firstWhere((e) => e.id == event.dish.id, orElse: () => null);
if (itemExist != null) {
itemExist.quantity++;
print("Not Empty"); // Here i am expecting to show qty 2 if i click an item more than 1 time
} else {
print("Empty");
cart.add(event.dish);
}
Basically, we need to check whether the cart already has a dish with the same id or not. If the cart contains the dish with this id we increment dish quantity else we just add a dish to the cart.
Besides that, I see a potential problem with your code. Bloc to work properly requires either creating new instances of models or properly implementing of equals and hashCode. So even the code above may not work properly due to this problem. Be aware of it. You can fix it using this package.
While trying to fetch data using API I didn't get the details . Instead of details I only get null.
How should I solve this?
Hera is my Code .
my screen page code
class ModuleListScreen extends StatefulWidget {
const ModuleListScreen({Key? key}) : super(key: key);
#override
_ModuleListScreenState createState() => _ModuleListScreenState();
}
class _ModuleListScreenState extends State<ModuleListScreen> with HttpMixin {
DatabaseHelper _dbHelper = DatabaseHelper();
List<Item> modules = [];
List<UserTable> userdetails = [];
String userId = '';
String accountId = '';
#override
void initState() {
super.initState();
_dbHelper.getAllUserData().then((value)async{
userdetails = value;
var response = await getmoduleList(value[0].userId.toString(),value[0].accountId.toString());
response.forEach((element) {
setState(() {
modules.add(element);
});
print('Test Printing ${element.pkgSequence}');
print('Test Printing ${modules[0].id}');
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue.shade300,
appBar: AppBar(
backgroundColor: Colors.pink,
actions: [
Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 3),
color: Colors.blue,
borderRadius: BorderRadius.circular(50)),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Image.asset('assets/images/icons/Back.png'),
)),
)
],
title: Center(child: Text('Subject Name')),
leading: Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 3),
color: Colors.blue,
borderRadius: BorderRadius.circular(50)),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Image.asset('assets/images/icons/ride.png'),
)),
),
),
body: Container(
child:
ListView.builder(
itemCount: modules.length,
itemBuilder: (context, index) {
return Container(
height: MediaQuery.of(context).size.height / 3,
margin: EdgeInsets.all(3),
child: Column(
children: [
Container(
padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.height * .15,
5,
MediaQuery.of(context).size.height * .15,
5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.grey),
child: Text(modules[index].title.toString()),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Container(
height: MediaQuery.of(context).size.height / 3,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: ListView.builder(
itemCount: 2,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'{article.chapter}',
style: TextStyle(
color: Colors.grey,
fontSize: 18,
fontWeight: FontWeight.w700),
),
Image(
height: 15,
image: AssetImage(
'assets/images/icons/Download.png'),
)
],
),
);
}),
),
),
)
],
));
})
),
);
}
}
My model page
class ModuleList {
ModuleList({
this.items,
this.subject,
this.grade,
});
List<Item>? items;
String? subject;
String? grade;
factory ModuleList.fromMap(Map<String, dynamic> map) => ModuleList(
items: map["items"] != null ? List<Item>.from(map["items"].map((x) => Item.fromMap(x))):[],
// items: List<Item>.from(json["items"].map((x) => Item.fromJson(x))),
subject: map["subject"],
grade: map["grade"],
);
Map<String, dynamic> toMap() => {
"items": items,
"subject": subject,
"grade": grade,
};
}
class Item {
Item({
this.sequenceno,
this.id,
this.chapter,
this.title,
this.packageDescription,
this.ageLevel,
this.pkgSequence,
this.packagescors,
});
int? sequenceno;
String? id;
String? chapter;
String? title;
String? packageDescription;
List<int>? ageLevel;
String? pkgSequence;
List<Packagescors>? packagescors;
Item.fromMap(Map<String, dynamic> map) {
Item(
sequenceno: map["sequenceno"],
id: map["_id"],
chapter: map["chapter"],
title: map["title"],
packageDescription: map["package_description"],
ageLevel: List<int>.from(map["age_level"].map((x) => x)),
pkgSequence: map["pkg_sequence"],
// packagescors: json["packagescors"] != null ? null : Packagescors.fromJson(json["packagescors"]),
packagescors: map["packagescors"] != null
? List<Packagescors>.from(
map["device_details"].map((x) => Packagescors.fromMap(x)))
: [],
);
}
Map<String, dynamic> toMap() => {
"sequenceno": sequenceno,
"_id": id,
"chapter": chapter,
"title": title,
"package_description": packageDescription,
"age_level": List<dynamic>.from(ageLevel!.map((x) => x)),
"pkg_sequence": pkgSequence,
"packagescors": packagescors,
};
}
class Packagescors {
Packagescors({
this.score,
this.date,
});
List<int>? score;
List<String>? date;
factory Packagescors.fromMap(Map<String, dynamic> map) => Packagescors(
score: List<int>.from(map["score"].map((x) => x)),
date: List<String>.from(map["date"].map((x) => x)),
);
Map<String, dynamic> toMap() => {
"score": List<dynamic>.from(score!.map((x) => x)),
"date": List<dynamic>.from(date!.map((x) => x)),
};
}
My http_mixin code for the above model
Future<List<Item>> getmoduleList(
String userId, String accountId) async {
final queryParameters ={
'subject':'Maths',
'grade':'6'
};
final response = await http
.get(Uri.https(_baseUrl, "MY URI",queryParameters), headers: {
'Content-Type': 'application/json',
'user-id': userId,
'account-id': accountId,
});
List <Item> jsonresponse = json.decode(response.body)['data']['items'].map<Item>((e)=>Item.fromMap(e)).toList();
print((response.body));
return jsonresponse;
}
1.This is My code. Here I want to fetch data from API. Now the result I got when I fetch is null.
I created the model using quick type also done some changes in the model.