I'm making a POST request using HTTPClient and posting a form's data. The request is successful when I tried with only 3 fields, but now I want to add all the fields so I added the complete JSON object model in the parameter and body of the POST function.
I've used Postman to get the entire JSON data and used quicktype.io tool to parse it into a model class which I've passed as parameters to the function and also to the requests body.
I have a save button in the UI which when clicked should post all the form data, I'm having trouble building that function saveContact() and getting the fields from the Model and initializing it to the form field controllers.
API_Manager class:
Future<AddContactModel> addContact(AddContactModel contact) async {
var client = http.Client();
String addContactUrl =
"https://example.com/ma/api/contacts/new";
String basicAuth = 'Basic examplebasicauthkey';
var response = await client.post(addContactUrl,
headers: <String, String>{
'authorization': basicAuth,
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
},
body: contact.toJson()); //from the Model class
// print(response.statusCode);
developer.log(response.body);
if (response.statusCode == 201) {
final String responseString = response.body;
return addContactModelFromJson(responseString);
} else {
return null;
}
}
SAVE FUNCTION to call POST request's function:
Future saveContact() async { //Need to call function here, get Model fields
//and initialize it to the controllers.
//await API_Manager().addContact(contact);
//Something like this but sure of the full code
}
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Scaffold(
appBar: AppBar(
title: Text('Add Contact'),
actions: <Widget>[
FlatButton(
textColor: Colors.white,
onPressed: () async {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState.validate()) {
await saveContact();
}
},
child: Text(
'SAVE',
style: TextStyle(
fontSize: 18,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
shape:
CircleBorder(side: BorderSide(color: Colors.transparent)),
)
],
),
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_contact == null
? Container()
:
//Text("The user ${_contact.contact.fields.all.firstname} is created successfully at time ${_contact.contact.lastActive.toIso8601String()}"),
TextFormField(
onSaved: null,
controller: _ipCountryCode,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'IP Country Code',
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(8)),
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: DateTimeFormField(
decoration: InputDecoration(
labelText: 'Time First Seen',
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(8)),
onDateSelected: (DateTime value) {
setState(() {
timeFirstSeen = value;
});
},
),
),
],
),
TextFormField(
onSaved: null,
controller: _eventRevenue,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Event Revenue',
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(8)),
),
//Not the full code
addContactModel class:
import 'dart:convert';
AddContactModel addContactModelFromJson(String str) => AddContactModel.fromJson(json.decode(str));
String addContactModelToJson(AddContactModel data) => json.encode(data.toJson());
class AddContactModel {
AddContactModel({
this.contact,
});
Contact contact;
factory AddContactModel.fromJson(Map<String, dynamic> json) => AddContactModel(
contact: Contact.fromJson(json["contact"]),
);
Map<String, dynamic> toJson() => {
"contact": contact.toJson(),
};
}
class Contact {
Contact({
this.isPublished,
this.dateAdded,
this.dateModified,
this.createdBy,
this.createdByUser,
this.modifiedBy,
this.modifiedByUser,
this.id,
this.points,
this.color,
this.fields,
this.lastActive,
this.owner,
this.ipAddresses,
this.tags,
this.utmtags,
this.stage,
this.dateIdentified,
this.preferredProfileImage,
this.doNotContact,
this.frequencyRules,
});
bool isPublished;
DateTime dateAdded;
dynamic dateModified;
int createdBy;
String createdByUser;
dynamic modifiedBy;
dynamic modifiedByUser;
int id;
int points;
dynamic color;
Fields fields;
dynamic lastActive;
dynamic owner;
List<dynamic> ipAddresses;
List<dynamic> tags;
dynamic utmtags;
dynamic stage;
dynamic dateIdentified;
dynamic preferredProfileImage;
List<dynamic> doNotContact;
List<dynamic> frequencyRules;
factory Contact.fromJson(Map<String, dynamic> json) => Contact(
isPublished: json["isPublished"],
dateAdded: DateTime.parse(json["dateAdded"]),
dateModified: json["dateModified"],
createdBy: json["createdBy"],
createdByUser: json["createdByUser"],
modifiedBy: json["modifiedBy"],
modifiedByUser: json["modifiedByUser"],
id: json["id"],
points: json["points"],
color: json["color"],
fields: Fields.fromJson(json["fields"]),
lastActive: json["lastActive"],
owner: json["owner"],
ipAddresses: List<dynamic>.from(json["ipAddresses"].map((x) => x)),
tags: List<dynamic>.from(json["tags"].map((x) => x)),
utmtags: json["utmtags"],
stage: json["stage"],
dateIdentified: json["dateIdentified"],
preferredProfileImage: json["preferredProfileImage"],
doNotContact: List<dynamic>.from(json["doNotContact"].map((x) => x)),
frequencyRules: List<dynamic>.from(json["frequencyRules"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"isPublished": isPublished,
"dateAdded": dateAdded.toIso8601String(),
"dateModified": dateModified,
"createdBy": createdBy,
"createdByUser": createdByUser,
"modifiedBy": modifiedBy,
"modifiedByUser": modifiedByUser,
"id": id,
"points": points,
"color": color,
"fields": fields.toJson(),
"lastActive": lastActive,
"owner": owner,
"ipAddresses": List<dynamic>.from(ipAddresses.map((x) => x)),
"tags": List<dynamic>.from(tags.map((x) => x)),
"utmtags": utmtags,
"stage": stage,
"dateIdentified": dateIdentified,
"preferredProfileImage": preferredProfileImage,
"doNotContact": List<dynamic>.from(doNotContact.map((x) => x)),
"frequencyRules": List<dynamic>.from(frequencyRules.map((x) => x)),
};
}
class Fields {
Fields({
this.core,
this.social,
this.personal,
this.professional,
this.all,
});
All core;
Social social;
List<dynamic> personal;
List<dynamic> professional;
All all;
//Not the full code
I have this post request you can change it to your desire
this is Post Function
Future<ResponseModel> HTTPPOST<T>(String url, List<QueryModel> query,
var body, HeaderEnum headerType, ResponseEnum responseType) async {
try {
var response = await http.post(
UrlGenerator(url, query),
headers: headerGetter(headerType),
body: body,
);
return responseGetter<T>(responseType, response);
} catch (e) {
return ResponseModel(
isSuccess: false,
statusCode: "500",
data: null,
message: "خطایی در عملیات رخ داده است");
}
}
this is the responseGetter function
responseGetter<T>(ResponseEnum typeEnum, http.Response response) {
try {
switch (typeEnum) {
case ResponseEnum.ResponseModelEnum:
String data = utf8.decode(response.bodyBytes);
if (data == null || data.isEmpty)
return ResponseModel(
statusCode: "555",
isSuccess: false,
data: null,
);
return ResponseModel().fromJson(
json.decode(data),
);
default:
return response.bodyBytes;
}
} catch (e) {
return ResponseModel(
isSuccess: false,
statusCode: "500",
data: null,
message: "خطایی در عملیات رخ داده است");
}
}
and this is using post function in an example
Future<ResponseModel<CartHeader>> AddProduct(int productId, int qty) async {
var map = {"productId": productId, "qty": qty};
var json = jsonEncode(map);
var response = await HTTPPOST(
RoutingCart.POST_AddProduct,
[],
json,
HeaderEnum.BearerHeaderEnum,
ResponseEnum.ResponseModelEnum,
);
return ResponseModel<CartHeader>(
isSuccess: response.isSuccess,
statusCode: response.statusCode,
data: response.data,
message: response.message,
); }
Related
I'm using FutureBuilder for fetching API request. but it only builds once and it doesn't update ui unless hot reloded. i aslo tried StreamBuilder and convert the future method to stream. so how can i update my ui. please i already asked this question and got no answer. whay is this happening?
model
import 'dart:convert';
List<User> usersFromJson(String str) =>
List<User>.from(json.decode(str).map((json) => User.fromJson(json)));
String usersToJson(List<User> data) =>
json.encode(List<dynamic>.from(data.map((e) => e.toJson())));
class User {
int? id;
String? name;
String? username;
String? email;
String? role;
User({this.id, this.name, this.username, this.email, this.role});
#override
toString() => 'User: $name';
factory User.fromJson(Map<String, dynamic> json) => User(
email: json['email'],
name: json['name'],
id: json['id'],
username: json['username'],
role: json['role']);
Map<String, dynamic> toJson() =>
{"name": name, "username": username, "email": email, "role": role};
}
api call
Future fetchUsers() async {
Uri url = Uri.parse("${BASE_URL}user");
final response = await http.get(url, headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer $TOKEN',
});
var userview = <User>[];
if (response.statusCode == 200) {
var jsonres = json.decode(response.body);
for (var res in jsonres) {
userview.add(User.fromJson(res));
}
}
return userview;
}
Future createUser(String name, String username, String email, String password,
String roles) async {
Uri url = Uri.parse("${BASE_URL}user");
final response = await http
.post(url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer $TOKEN',
},
body: jsonEncode(<String, dynamic>{
'name': name,
'email': email,
'username': username,
'password': password,
'roles': roles
}))
.then((value) => fetchUsers());
}
and my page
StreamBuilder(
stream: fetchUsers().asStream(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: [
PaginatedDataTable(
sortColumnIndex: sortColumnIndex,
sortAscending: isAscending,
columns: [
DataColumn(
label: const Text("Id"),
onSort: onSort),
DataColumn(
label: const Text("Name"),
onSort: onSort),
DataColumn(
label: const Text("Username"),
onSort: onSort),
DataColumn(
label: const Text("Email"),
onSort: onSort),
DataColumn(
label: const Text("Roles"),
onSort: onSort),
DataColumn(
label: const Text("Actions"),
onSort: onSort),
],
header: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"Manage Users",
style: TextStyle(
fontSize: width * 0.04,
fontWeight: FontWeight.normal),
),
MaterialButton(
onPressed: () {
showMaterialModalBottomSheet(
context: context,
builder: (context) => SizedBox(
height: height * 0.9,
child:
BottomSheetWidget(),
),
shape:
const RoundedRectangleBorder(
borderRadius:
BorderRadius.only(
topLeft: Radius
.circular(
15),
topRight: Radius
.circular(
15))));
},
color: const Color.fromRGBO(
30, 119, 66, 1),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10)),
child: Text(
"Add User",
style: TextStyle(
color: Colors.white,
fontSize: width * 0.03),
),
)
],
),
source: dataSource(
snapshot.data! as List<User>))
],
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return const Center(
child: CircularProgressIndicator());
})
additionally i'm using paginated datatable and this is the code for that.(it's related)
in the page
DataTableSource dataSource(List<User> userList) =>
MyTable(datasList: userList, context: context);
and the datasource page i'm calling the createUser here.
class MyTable extends DataTableSource {
MyTable({required this.datasList, required this.context});
final List<User> datasList;
BuildContext context;
Widget Button(String title, Color color, String id) {
return MaterialButton(
onPressed: () {
//deleteUser(id);
//updateUser(id, title);
createUser("name2", "user2", "email2#email.com", "password", "Admin");
},
child: Text(
title,
style: const TextStyle(color: Colors.white),
),
color: color,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
);
}
#override
DataRow? getRow(int index) {
return DataRow.byIndex(index: index, cells: [
DataCell(Text(datasList[index].id.toString())),
DataCell(ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: Text(
datasList[index].name.toString(),
overflow: TextOverflow.ellipsis,
),
)),
DataCell(ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: Text(
datasList[index].username.toString(),
overflow: TextOverflow.ellipsis,
))),
DataCell(ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: Text(
datasList[index].email.toString(),
overflow: TextOverflow.ellipsis,
))),
DataCell(ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: Text(
datasList[index].role.toString(),
overflow: TextOverflow.ellipsis,
))),
DataCell(Row(
children: [
Button("Edit", Colors.lightBlue, datasList[index].id.toString()),
const SizedBox(
width: 5,
),
Button("Delete", Colors.red, datasList[index].id.toString()),
],
)),
]);
}
#override
bool get isRowCountApproximate => false;
#override
int get rowCount => datasList.length;
#override
int get selectedRowCount => 0;
}
StreamBuilder class
Widget rebuilding is scheduled by each interaction, using
State.setState, but is otherwise decoupled from the timing of the
stream.
i see the code and can't found any issue. but im bit doubt with asStream().
as documentation said: asStream method:
Creates a Stream containing the result of this future.
maybe you can try with this : stream.fromFuture
found the issue here: https://stackoverflow.com/a/55169382/12838877
since your fetch method is not common , it is a Future method that return value of Future value.
Stream.fromFuture(fetchUsers)
it's just my doubt. hope solve the problem. because it's too long to explain in the comments, so I'll put it in the answer section
I'm trying to get some images from an API but facing this error
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'Map<dynamic, dynamic>'
The Json from the API looks like this and it's from www.themoviedb.org:
{
"page": 1,
"results": [
{
"adult": false,
"backdrop_path": "/qxeqKcVBWnQxUp1w6fwWcxZEA6m.jpg",
"genre_ids": [
28,
12,
14
],
"id": 436270,
"original_language": "en",
"original_title": "Black Adam",
"overview": "Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods—and imprisoned just as quickly—Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the modern world.",
"popularity": 6041.545,
"poster_path": "/3zXceNTtyj5FLjwQXuPvLYK5YYL.jpg",
"release_date": "2022-10-19",
"title": "Black Adam",
"video": false,
"vote_average": 7.2,
"vote_count": 425
},
],
"total_pages": 35601,
"total_results": 712013
}
Here is the code:
Movie
class Movie {
final int id;
final String name;
final String description;
final String? posterPath;
//<editor-fold desc="Data Methods">
Movie({
required this.id,
required this.name,
required this.description,
this.posterPath,
});
Movie copyWith({
int? id,
String? name,
String? description,
String? posterPath,
}) {
return Movie(
id: id ?? this.id,
name: name ?? this.name,
description: description ?? this.description,
posterPath: posterPath ?? this.posterPath,
);
}
factory Movie.fromJson(Map<String, dynamic> map) {
return Movie(
id: map['id'] as int,
name: map['title'] as String,
description: map['overview'] as String,
posterPath: map['poster_path'] as String,
);
}
// Poster url ****************************************************************
String posterUrl() {
Api api = Api();
return api.baseUrl + posterPath!;
}
//</editor-fold>
}
API
class Api {
final String apiKey = ApiKey.apiKey;
final String baseUrl = "https://developers.themoviedb.org/3";
final String baseImageUrl = "https://image.tmdb.org/t/p/w500/";
final String baseVideoUrl = "https://www.youtube.com/watch?=v";
}
ApiKey
class ApiKey {
static String apiKey = "my_api_key";
}
ApiService
class ApiService {
final Api api = Api();
final Dio dio = Dio();
Future<Response> getData(String path, {Map<String, dynamic>? params}) async {
String url = api.baseUrl + path;
Map<String, dynamic> query = {
"api_key": api.apiKey,
"language": "en-US",
};
if(params != null) {
query.addAll(params);
}
final response = await dio.get(url, queryParameters: query);
if(response.statusCode == 200) {
return response;
}
else {
throw response;
}
}
//****************************************************************************
// Get popular movies
//****************************************************************************
Future getPopularMovies({required int pageNumber}) async{
Response response = await getData(
"/movie/popular",
params: {
"page": pageNumber,
}
);
if(response.statusCode == 200){
Map data = response.data; // <--------------------------- Problem is here
List<dynamic> results = data["results"]; // <--------------------------- And here
List<Movie> movies = [];
for(Map<String, dynamic> json in results){
Movie movie = Movie.fromJson(json);
movies.add(movie);
}
return movies;
}
else{
throw response;
}
}
}
HomeScreen
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List<Movie>? movies;
#override
void initState() {
super.initState();
getMovies();
}
//****************************************************************************
// Get movies
//****************************************************************************
void getMovies(){
ApiService().getPopularMovies(pageNumber: 1)
.then((movieList){
setState(() {
movies = movieList;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kBackgroundColor,
appBar: AppBar(
backgroundColor: kBackgroundColor,
leading: Image.asset(
"assets/images/netflix_logo_2.png"
),
),
body: ListView(
children: [
Container(
height: 500,
color: Colors.red,
child: movies == null
? const Center()
: Image.network(
movies![0].posterUrl(),
fit: BoxFit.cover,
),
),
const SizedBox(height: 15,),
Text("Current trends",
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold
),
),
const SizedBox(height: 5,),
SizedBox(
height: 160,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return Container(
width: 110,
margin: const EdgeInsets.only(right: 8),
color: Colors.yellow,
child: Center(
child: Text(index.toString()),
),
);
},
),
),
const SizedBox(height: 15,),
Text("Currently in cinema",
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold
),
),
const SizedBox(height: 5,),
SizedBox(
height: 320,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return Container(
width: 220,
margin: const EdgeInsets.only(right: 8),
color: Colors.blue,
child: Center(
child: Text(index.toString()),
),
);
},
),
),
const SizedBox(height: 15,),
Text("Available soon",
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold
),
),
const SizedBox(height: 5,),
SizedBox(
height: 160,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return Container(
width: 110,
margin: const EdgeInsets.only(right: 8),
color: Colors.green,
child: Center(
child: Text(index.toString()),
),
);
},
),
),
],
),
);
}
}
What I've tried:
I've tried to replace Map with var in ApiService but the problem isn't solved because another error is shown in the logcat doing this:
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
Thanks in advance for the help
in the ApiService file
first import
import 'dart:convert';
then in the same line where the problem occurred add jsonDecode, like this
Map data = jsonDecode(response.data);
#hamza aboshhiwa thanks for the answer
I finally found, the 2 mistakes were in Movie and API replacing:
String posterUrl() {
Api api = Api();
return api.baseUrl + posterPath!;
}
By:
String posterUrl() {
Api api = Api();
return api.baseImageUrl + posterPath!;
}
And:
class Api {
final String apiKey = ApiKey.apiKey;
final String baseUrl = "https://developers.themoviedb.org/3";
final String baseImageUrl = "https://image.tmdb.org/t/p/w500/";
final String baseVideoUrl = "https://www.youtube.com/watch?=v";
}
By:
class Api {
final String apiKey = ApiKey.apiKey;
final String baseUrl = "https://api.themoviedb.org/3"; //<-----------------
final String baseImageUrl = "https://image.tmdb.org/t/p/w500/";
final String baseVideoUrl = "https://www.youtube.com/watch?=v";
}
Now it works
I am trying to select an index from a list of images in flutter. While passing the image list to the Image.network() i get an error:
The following NetworkImageLoadException was thrown resolving an image codec:
HTTP request failed, statusCode: 500, http://10.0.2.2:8000/static/product_images/b0bf3474f9c5a6b6cfcf.jpg,http://10.0.2.2:8000/static/product_images/e307dccf6bbc2700e683.jpg,http://10.0.2.2:8000/static/product_images/6e91cff1ce07d72fc127.jpg
Please how do i seperate the images so that only the index i pick is selected?
Below is the Product Model:
import 'dart:convert';
List<ProductModel> productsFromJson(String str) => List<ProductModel>.from(
json.decode(str).map((x) => ProductModel.fromJson(x)));
String productsToJson(List<ProductModel> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class ProductModel {
ProductModel({
required this.name,
required this.price,
required this.isActive,
required this.imgsUrl,
required this.id,
required this.description,
required this.ownerId,
});
String name;
double price;
bool isActive;
List<String> imgsUrl;
int id;
String description;
int ownerId;
factory ProductModel.fromJson(Map<String, dynamic> json) => ProductModel(
name: json["name"],
price: json["price"].toDouble(),
isActive: json["is_active"],
imgsUrl: List<String>.from(json["imgs_url"].map((x) => x)),
id: json["id"],
description: json["description"],
ownerId: json["owner_id"],
);
Map<String, dynamic> toJson() => {
"name": name,
"price": price,
"is_active": isActive,
"imgs_url": List<dynamic>.from(imgsUrl.map((x) => x)),
"id": id,
"description": description,
"owner_id": ownerId,
};
}
I am using a futurebuilder with dio to fetch the data from the API:
FutureBuilder<List<ProductModel>>(
future: productModel,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('${snapshot.error}');
} else if (snapshot.hasData) {
debugPrint('${snapshot.data}');
return SizedBox(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: Container(
decoration: const BoxDecoration(
color: styles.AppColors.facebookBlue),
child: Text('$finalName products online'),
),
),
Expanded(
child: StaggeredGridView.countBuilder(
crossAxisCount: 2,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(children: [
Container(
height: 180,
width: double.infinity,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(4)),
child:
Image.network(snapshot
.data![index].imgsUrl[0])
]),
const SizedBox(
height: 8,
),
Text(snapshot.data![index].name),
Text(
"\$${snapshot.data![index].price.toString()}",
)
],
),
),
);
},
staggeredTileBuilder: (int index) =>
const StaggeredTile.fit(1),
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
),
],
),
);
} else {
return const Center(child: CircularProgressIndicator());
}
}),
For the API call with DioClient:
Future<List<ProductModel>> fetchVProduct() async {
await SecureStorage.readSecureData("vt")
.then((value) => finalToken = value);
try {
final response = await Dio().get(
'$productsEndpoint/me/items/',
options: Options(
headers: {
'Content-Type':
'application/x-www-form-urlencoded;charset=UTF-8;application/json;multipart/form-data',
'Accept': 'application/json',
"Authorization": "Bearer $finalToken",
},
followRedirects: false,
validateStatus: (status) {
return status! < 500;
}),
);
debugPrint(response.toString());
return (response.data as List)
.map((x) => ProductModel.fromJson(x))
.toList();
} on DioError catch (e) {
debugPrint("Status code: ${e.response?.statusCode.toString()}");
throw Exception("Failed to load currently Logged in Vendor Products");
}
}
For the sample json from my apicall:
{
"name": "sa",
"price": 44,
"is_active": true,
"imgs_url": [
"http://10.0.2.2:8000/static/product_images/f3e6421737643e583a1d.jpg, http://10.0.2.2:8000/static/product_images/b53bf8aeb27d27a739cc.jpg, http://10.0.2.2:8000/static/product_images/75a80e7c04ebaed3e425.jpg"
],
"id": 43,
"description": "hfg",
"owner_id": 1
}
Please what do i do next? Thank you.
In data imgs_url is a single string containing three urls.
"imgs_url": [
"http://10.0.2.2:8000/static/product_images/f3e6421737643e583a1d.jpg, http://10.0.2.2:8000/static/product_images/b53bf8aeb27d27a739cc.jpg, http://10.0.2.2:8000/static/product_images/75a80e7c04ebaed3e425.jpg"
],
Change it to
"imgs_url": [
"http://10.0.2.2:8000/static/product_images/f3e6421737643e583a1d.jpg",
"http://10.0.2.2:8000/static/product_images/b53bf8aeb27d27a739cc.jpg",
"http://10.0.2.2:8000/static/product_images/75a80e7c04ebaed3e425.jpg"
],
My dropdown working as expected . but when I selected a item my app crashing with error
There should be exactly one item with [DropdownButton]'s value: Instance of 'Partner'.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
First I declare my variable in class
class _MultipleTestBookingState extends State<MultipleTestBooking> {
Partner? _selectedLab;
Datum? _selectedTest;
....................
declare with Partner?_selectedLab; because my dropdown menu takes in a list of Partners
Then using this variable to show the selected value in my dropdown
Container(
child: FutureBuilder<List<Partner>>(
future: AllPathLab(),
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState !=ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Somthing went wrong");
}
if (snapshot.hasData) {
return DropdownButton<Partner>(
value: _selectedLab,
hint: Text("Select Lab"),
items: snapshot.data.map((Partner data) =>
DropdownMenuItem<Partner>(
child: Text("${data.partnerName}"),
value: data,
)
).toList().cast<DropdownMenuItem<Partner>>(),
onChanged: (value){
setState(() {
_selectedLab=value;
encLabId = value!.encPartnerId;
GetTestByLab();
});
}
);
}
return Text("Waiting for Internet Connection");
},
),
),
Full code with my JSON response
So from the data that you provided i have created the code below:
import 'package:date_time_picker/date_time_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/Patner.dart';
import 'package:flutter_app/dataModel.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
const MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Partner _selectedLab;
Datum _selectedTest;
Future getAllPathLabResults;
Future getTestByLabResult;
String encLabId = '';
void initState() {
super.initState();
getAllPathLabResults = allPathLab();
getTestByLabResult = getTestByLab();
}
String _selectedDate = DateTime.now().toString();
Future<List<Partner>> allPathLab() async {
String jsonData = jsonstring;
final model = modelFromJson(jsonData);
print("This is the list length : ${model.partner.length}");
List<Partner> arrData = model.partner;
// this Future is for sample as you will be fetching the api data remove this one
Future.delayed(Duration(seconds: 3));
return arrData;
}
Future<List<Datum>> getTestByLab() async {
print("This is the Id :$encLabId");
_selectedTest = null;
var response = await http.post(
Uri.parse("http://medbo.digitalicon.in/api/medboapi/GetTestByLab"),
body: ({"EncId": encLabId}));
if (response.statusCode == 200) {
final dataModel = dataModelFromJson(response.body);
print(dataModel.data.length);
for (final item in dataModel.data) {
print("This is hte test name :${item.testName}");
}
List<Datum> arrData = dataModel.data;
return arrData;
}
return [];
}
#override
Widget build(BuildContext context) {
var screenWidth = MediaQuery.of(context).size.width;
var screenHeight = MediaQuery.of(context).size.height;
var blockSizeHorizontal = (screenWidth / 100);
var blockSizeVertical = (screenHeight / 100);
return Scaffold(
body: SafeArea(
child: Container(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
title: Text("Booking Information",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: blockSizeHorizontal * 5,
fontFamily: 'Poppins',
color: Theme.of(context).primaryColor,
)),
subtitle: Text("Preferred Visit Date"),
),
),
Container(
margin: EdgeInsets.only(left: 20),
padding: EdgeInsets.only(left: 0, right: 150),
decoration: BoxDecoration(
color: Colors.lightBlue[50],
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: DateTimePicker(
initialValue: DateTime.now().toString(),
//initialValue:'', // initialValue or controller.text can be null, empty or a DateTime string otherwise it will throw an error.
type: DateTimePickerType.date,
dateLabelText: 'Select Date',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: blockSizeHorizontal * 3.5,
fontFamily: 'Poppins',
color: Colors.green,
letterSpacing: 2.0,
),
firstDate: DateTime.now(),
lastDate: DateTime.now().add(Duration(days: 30)),
// This will add one year from current date
validator: (value) {
return null;
},
onChanged: (value) {
if (value.isNotEmpty) {
setState(() {
_selectedDate = value;
});
}
},
onSaved: (value) {
if (value.isNotEmpty) {
_selectedDate = value;
}
},
),
),
),
ListTile(
title: Text(
"Select Pathological Lab",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: blockSizeHorizontal * 4.0,
fontFamily: 'Poppins',
color: Theme.of(context).primaryColor,
),
),
),
Container(
child: FutureBuilder<List<Partner>>(
future: getAllPathLabResults,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Somthing went wrong");
}
if (snapshot.hasData) {
List<Partner> data =
snapshot.hasData ? snapshot.data : [];
return DropdownButton<Partner>(
value: _selectedLab,
hint: Text("Select Lab"),
//underline: SizedBox(),
//isExpanded: true,
items: data
.map((Partner data) => DropdownMenuItem<Partner>(
child: Text("${data.partnerName}"),
value: data,
))
.toList()
.cast<DropdownMenuItem<Partner>>(),
onChanged: (value) {
setState(() {
_selectedLab = value;
encLabId = value.encPartnerId;
getTestByLabResult = getTestByLab();
});
//GetTestByLab(value!.encPartnerId); // passing encid to my next API function
// GetTestByLab();
},
);
}
return Text("Waiting for Internet Connection");
},
),
),
//=========================================================== Dependent drop down===================================
ListTile(
title: Text(
"Test Name",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: blockSizeHorizontal * 4.0,
fontFamily: 'Poppins',
color: Theme.of(context).primaryColor,
),
),
),
Container(
child: FutureBuilder<List<Datum>>(
future: getTestByLabResult,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Select a Lab for your Test");
}
if (snapshot.hasData) {
List<Datum> data = snapshot.hasData ? snapshot.data : [];
return DropdownButton<Datum>(
value: _selectedTest,
hint: Text(""),
//underline: SizedBox(),
//isExpanded: true,
items: data
.map((Datum data) => DropdownMenuItem<Datum>(
child: Text("${data.testName}"),
value: data,
))
.toList()
.cast<DropdownMenuItem<Datum>>(),
onChanged: (value) {
print("This is the value : ${value.testName}");
setState(() {
_selectedTest = value;
});
//GetTestByLab(value!.encPartnerId); // passing encid to my next API function
});
}
return Text("Waiting for Internet Connection");
},
),
),
],
),
),
),
);
}
}
// used this as a sample
String jsonstring = '''{
"Status": "1",
"Message": "",
"Partner": [
{
"EncPartnerId": "IujyQXg8KZg8asLvK/FS7g==",
"PartnerName": "dasfdsf"
},
{
"EncPartnerId": "pEl2B9kuumKRxIxLJO76eQ==",
"PartnerName": "partner172"
},
{
"EncPartnerId": "eYwtNBXR6P/JDtsIwr+Bvw==",
"PartnerName": "nnkb"
},
{
"EncPartnerId": "kFgorcFF0G6RQD4W+LwWnQ==",
"PartnerName": "nnkjj"
},
{
"EncPartnerId": "U4exk+vfMGrn7cjNUa/PBw==",
"PartnerName": "mahadev"
},
{
"EncPartnerId": "tqkaSjTFgDf0612mp9mbsQ==",
"PartnerName": null
},
{
"EncPartnerId": "0aruO0FbYOu5IerRBxdT8w==",
"PartnerName": "Suraksha Diagnostics"
},
{
"EncPartnerId": "65gtodyhbtdInTsJWr1ZkA==",
"PartnerName": "Rasomoy pvt. Hospital"
},
{
"EncPartnerId": "LEuT1eIlpLEMAAkZme3wpQ==",
"PartnerName": "Tangra medical House"
},
{
"EncPartnerId": "q8O8YMzYKXSB4RtkX4k7Lw==",
"PartnerName": "Partner new"
}
]
}''';
Models for the apis:
// To parse this JSON data, do
//
// final model = modelFromJson(jsonString);
import 'dart:convert';
Model modelFromJson(String str) => Model.fromJson(json.decode(str));
String modelToJson(Model data) => json.encode(data.toJson());
class Model {
Model({
this.status,
this.message,
this.partner,
});
String status;
String message;
List<Partner> partner;
factory Model.fromJson(Map<String, dynamic> json) => Model(
status: json["Status"],
message: json["Message"],
partner:
List<Partner>.from(json["Partner"].map((x) => Partner.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Status": status,
"Message": message,
"Partner": List<dynamic>.from(partner.map((x) => x.toJson())),
};
}
class Partner {
Partner({
this.encPartnerId,
this.partnerName,
});
String encPartnerId;
String partnerName;
factory Partner.fromJson(Map<String, dynamic> json) => Partner(
encPartnerId: json["EncPartnerId"],
partnerName: json["PartnerName"] == null ? null : json["PartnerName"],
);
Map<String, dynamic> toJson() => {
"EncPartnerId": encPartnerId,
"PartnerName": partnerName == null ? null : partnerName,
};
}
second api parsing model
// To parse this JSON data, do
//
// final dataModel = dataModelFromJson(jsonString);
import 'dart:convert';
DataModel dataModelFromJson(String str) => DataModel.fromJson(json.decode(str));
String dataModelToJson(DataModel data) => json.encode(data.toJson());
class DataModel {
DataModel({
this.status,
this.message,
this.data,
});
String status;
String message;
List<Datum> data;
factory DataModel.fromJson(Map<String, dynamic> json) => DataModel(
status: json["Status"],
message: json["Message"],
data: json["Data"] == null
? []
: List<Datum>.from(json["Data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Status": status,
"Message": message,
"Data":
data == null ? [] : List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
Datum({
this.testId,
this.encTestId,
this.testName,
this.noOfPartner,
this.testFee,
this.discountedFee,
this.bookingFee,
this.reportTime,
this.note,
this.createBy,
this.createDate,
this.modBy,
this.modDate,
this.activeStatus,
this.permission,
});
String testId;
dynamic encTestId;
String testName;
dynamic noOfPartner;
dynamic testFee;
dynamic discountedFee;
dynamic bookingFee;
dynamic reportTime;
dynamic note;
dynamic createBy;
dynamic createDate;
dynamic modBy;
dynamic modDate;
dynamic activeStatus;
dynamic permission;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
testId: json["TestId"],
encTestId: json["EncTestId"],
testName: json["TestName"],
noOfPartner: json["NoOfPartner"],
testFee: json["TestFee"],
discountedFee: json["DiscountedFee"],
bookingFee: json["BookingFee"],
reportTime: json["ReportTime"],
note: json["Note"],
createBy: json["CreateBy"],
createDate: json["CreateDate"],
modBy: json["ModBy"],
modDate: json["ModDate"],
activeStatus: json["ActiveStatus"],
permission: json["Permission"],
);
Map<String, dynamic> toJson() => {
"TestId": testId,
"EncTestId": encTestId,
"TestName": testName,
"NoOfPartner": noOfPartner,
"TestFee": testFee,
"DiscountedFee": discountedFee,
"BookingFee": bookingFee,
"ReportTime": reportTime,
"Note": note,
"CreateBy": createBy,
"CreateDate": createDate,
"ModBy": modBy,
"ModDate": modDate,
"ActiveStatus": activeStatus,
"Permission": permission,
};
}
So when you initially fetch the data based on the id and select the second dropdown. now when you change the lab you have the make the selected text to null.
and you are are also using the futurebuilder method in wrong manner as there is setstate getting called it is creating multiple rebuids and giving error.
please run the code and check if its working.
I have logged in from an Api of login. Then i got a response data of json. I need to show that json data in a list view. and need to show the array count in notification icon for counting it. How can i do it ? please help.
The response json format is -
{
"id": 1,
"name": "Mr Admin",
"email": "admin2#gmail.com",
"username": "admin2",
"api_token": "oYfajebhRzlxpMZV8dHI6w5R8CrpgybaGqX2ZaIXkGpumE9hZSgLVVINAgaF",
"user_types_id": null,
"created_at": "2020-01-21 16:21:48",
"updated_at": "2020-10-14 11:31:10",
"deleted_at": null,
"unread_notifications": [
{
"id": "d54ee0cc-054a-4d51-a53b-5f6f658841ae",
"type": "App\\Notifications\\HandSlipStatusNotification",
"notifiable_id": 1,
"notifiable_type": "App\\User",
"data": {
"payment_id": 471,
"generate_payment_id": "10200471",
"message": "Hand Slip Settled.",
"amount": 850
},
"read_at": null,
"created_at": "2020-10-12 15:50:38",
"updated_at": "2020-10-12 15:50:38"
},
{
"id": "aedb7880-4201-4805-b017-62242dfed741",
"type": "App\\Notifications\\HandSlipStatusNotification",
"notifiable_id": 1,
"notifiable_type": "App\\User",
"data": {
"payment_id": 471,
"generate_payment_id": "10200471",
"message": "Hand Slip Disbursed.",
"amount": 850
},
"read_at": null,
"created_at": "2020-10-12 15:50:25",
"updated_at": "2020-10-12 15:50:25"
},
i can show the id , name , email etc but cann't access unread_notifications.
my code -
api_service.dart ->
class LoginResponseModel {
final String token;
final String error;
LoginResponseModel({this.token, this.error});
factory LoginResponseModel.fromJson(Map<String, dynamic> json) {
return LoginResponseModel(
token: json["token"] != null ? json["token"] : "",
error: json["error"] != null ? json["error"] : "",
);
}
}
class LoginRequestModel {
String email;
String password;
String username;
LoginRequestModel({
this.email,
this.password,
this.username,
});
Map<String, dynamic> toJson() {
Map<String, dynamic> map = {
// 'email': email.trim(),
'username': username.trim(),
'password': password.trim(),
};
return map;
}
}
login_model
class LoginResponseModel {
final String token;
final String error;
LoginResponseModel({this.token, this.error});
factory LoginResponseModel.fromJson(Map<String, dynamic> json) {
return LoginResponseModel(
token: json["token"] != null ? json["token"] : "",
error: json["error"] != null ? json["error"] : "",
);
}
}
class LoginRequestModel {
String email;
String password;
String username;
LoginRequestModel({
this.email,
this.password,
this.username,
});
Map<String, dynamic> toJson() {
Map<String, dynamic> map = {
// 'email': email.trim(),
'username': username.trim(),
'password': password.trim(),
};
return map;
}
}
login.dart
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'homepage.dart';
class Login extends StatefulWidget {
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
var allData ;
TextEditingController _userController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
bool _isLoading = false;
// arrange method for api log in
signIn( String username,String password) async {
// String url = "https://reqres.in/api/login";
String url = "my url";
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
Map body = { "username": username, "password": password
};
var notificatiion;
var jsonResponse;
var res = await http.post(url, body: body);
//need to check the api status
if (res.statusCode == 200) {
jsonResponse = json.decode(res.body);
notificatiion = jsonResponse['unread_notifications'];
print("Response status: ${res.statusCode}");
print("Response status: ${res.body}");
if (jsonResponse != null) {
setState(() {
_isLoading = false;
});
sharedPreferences.setString("token", jsonResponse['token']);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (BuildContext) =>
HomePage(
email: jsonResponse['email'],
name: jsonResponse['name'],
username : jsonResponse['username'],
notification: notificatiion,
),
),
(Route<dynamic> route) => false);
}
} else {
setState(() {
_isLoading == false;
});
print(" Response status : ${res.body}");
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SingleChildScrollView(
child: Center(
child: Container(
padding: EdgeInsets.fromLTRB(20, 100, 20, 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Login",
style: TextStyle(fontSize: 32),
),
SizedBox(
height: 30,
),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
height: 220,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(30),
child: TextField(
controller: _userController,
decoration: InputDecoration(hintText: "username"),
),
),
Padding(
padding: const EdgeInsets.all(30),
child: TextField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(hintText: "Password"),
),
),
],
),
),
),
SizedBox(
height: 60,
width: MediaQuery.of(context).size.width,
child: RaisedButton(
color: Colors.lightBlue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Text("Sign In"),
onPressed: _userController.text == ""||
_passwordController.text == ""
? null
: () {
setState(() {
_isLoading = true ;
});
signIn(_userController.text, _passwordController.text);
},
),
),
SizedBox(
height: 20,
),
FlatButton(
child: Text("Forgot password"),
onPressed: (){
},
),
],
),
),
),
),
),
);
}
}
I want to show all the response value in home page .In notification's icon i want to show array count.
homepage.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'login.dart';
import 'login.dart';
class HomePage extends StatelessWidget {
String email;
String name;
String username;
List<dynamic> notification;
HomePage({this.email, this.name, this.username, this.notification, });
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Cash-Management"),
backgroundColor: Colors.blue,
actions: [
IconButton(icon: Icon(Icons.notifications), onPressed: () {}),
IconButton(
icon: Icon(Icons.exit_to_app),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Login()),
);
}),
],
),
body: ListView(
children: <Widget>[
Container(
height: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
" $email ",
style: TextStyle(fontSize: 16),
),
Text(" $name "),
Text(" $username "),
],
),
),
Container(
height: 300,
child: ListView.builder(
itemCount: notification == null ? 0 : notification.length,
itemBuilder: (context, index){
return ListTile(
title: Text(notification[index] ["id"]),
subtitle: Text(notification[index]["type"]),
);
}),
),
],
),
),
);
}
}