I'm trying to load data from a mock recipes.json file in flutter and I have a structure like this
lib
|__mock_data
|__recipes.json
|__src
|__models
|__components
|__screens
|__app.dart
|__main.dart
Now I have created a model which looks like this:
class RecipeModel {
RecipeModel({
required this.id,
required this.name,
required this.videoLink,
required this.author,
required this.category,
required this.time,
});
String id;
String name;
String videoLink;
String author;
String category;
String time;
factory RecipeModel.fromJson(Map<String, dynamic> json) => RecipeModel(
id: json["id"] == null ? null : json["id"],
name: json["name"] == null ? null : json["name"],
videoLink:
json["audioAssetPath"] == null ? null : json["audioAssetPath"],
author: json["isRemoteUrl"] == null ? null : json["isRemoteUrl"],
category: json["iconUrl"] == null ? null : json["iconUrl"],
time: json["vol"] == null ? null : json["vol"].toDouble(),
);
}
In the page where I want to show the data I'm doing this:
Future<List<RecipeModel>> fetchRecipes() async {
String url =
"https://raw.githubusercontent.com/boriszv/json/master/random_example.json";
var response = await http.get(url); ----------->The argument type 'String' can't be assigned to the parameter type 'Uri'
print(response);
var recipes = <RecipeModel>[];
var recipesJson = json.decode(response.body);
for (var index in recipesJson) {
recipes.add(RecipeModel.fromJson(index));
}
throw '';
}
#override
void initState() {
super.initState();
fetchRecipes();
}
I get a error when assigning the URL and also how to load the current recipe.json data?
N.B: Are the models written right?Because there might be a shift from json to protobuf
To load a local file, you can put the file in the assets folder.
Future<List<RecipeModel>> loadLocalRecipe() async {
try {
String response = await rootBundle.loadString('assets/recipe.json');
List<dynamic> result = json.decode(response);
return result.map((n) => RecipeModel.fromJson(n)).toList();
} catch (e) {
throw Padding(
padding: EdgeInsets.only(top: 50),
child: Center(
child: Text('Convert Error'),
),
);
}
}
pubspec.yaml
flutter:
assets:
- assets/receipe.json
To get server data, you can use this.
Future<List<RecipeModel>> getRecipe() async {
try {
final http.Response response = await http.get("https://example.com",
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
// print(response.body);
List<dynamic> result = json.decode(response.body) as List;
return result.map((n) => RecipeModel.fromJson(n)).toList();
} catch (e) {
throw Padding(
padding: EdgeInsets.only(top: 50),
child: Center(
child: Text('Connection Error'),
),
);
}
}
Related
I'm trying to fetch data from an api by passing bearer token but it is throwing this exception. Here's my code below :
This is my afterLoginResponse.dart class -
class AfterLoginResponse {
LoginData? data;
bool? operator;
bool? success;
AfterLoginResponse({
required this.operator,
required this.success,
required this.data,
});
AfterLoginResponse.fromJson(Map<String, dynamic> json) {
operator = json['operator'];
success = json['success'];
data = LoginData.fromJson(json["data"]);
}
Map<String, dynamic> toJson() => {
"operator": operator,
"success": success,
"data": data!.toJson(),
};
}
Below is my loginData.dart class ->
class LoginData {
String? name;
String? ext;
String? dName;
String? password;
LoginData({
required this.name,
required this.ext,
required this.dName,
required this.password,
});
factory LoginData.fromJson(Map<String, dynamic> json) {
return LoginData(
name: json['name'],
ext: json['ext'],
dName: json['d_Name'],
password : json['password'],
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['name'] = name;
data['ext'] = ext;
data['d_Name'] = dName;
data['password'] = password;
return data;
}
}
This is my apiService.dart class -
class ApiService{
String? token;
var response1;
var response2;
Future<LoginResponseData> loginApiCall(Map<String, dynamic> param) async{
var url = Uri.parse(ApiUrls.login_url);
response1 = await http.post(url, body: param);
final data = jsonDecode(response1.body);
token = LoginResponseData.fromJson(json.decode(response1.body)).token;
return LoginResponseData(user: data['user'], token:
data['token'],error:data['error']);
}
Future<AfterLoginResponse> postLoginApiCall() async{
var afterLoginUrl = Uri.parse(ApiUrls.postLogin_url);
response2 = await http.get(afterLoginUrl , headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer
${LoginResponseData.fromJson(json.decode(response1.body)).token}'
});
if(response2.statusCode == 200){
var data = jsonDecode(response2.body);
return AfterLoginResponse.fromJson(data);
}else{
throw Exception('Failed to load data');
}
}
}
Here is my UI -
class HomePage extends StatefulWidget {
String email, password;
HomePage({Key? key, required this.email, required this.password})
: super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late Future<AfterLoginResponse> afterLoginResponse;
final apiService = ApiService();
callPostLoginApi(){
return FutureBuilder<AfterLoginResponse>(
future: afterLoginResponse,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
print(snapshot.data);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home page'),
centerTitle: true,
),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: callPostLoginApi,
child: const Text('Click me'))
],
),
)
);
}
The above code is throwing following exception -
Unhandled Exception: NoSuchMethodError: The getter 'body' was called on null.
Receiver: null
E/flutter (28599): Tried calling: body
E/flutter (28599): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:38:5)
.
.
.
in the postLoginApiCall you are calling body with response1 variable which is at that very time null that is causing the issue change that to response2 like this:
Future<AfterLoginResponse> postLoginApiCall() async{
var afterLoginUrl = Uri.parse(ApiUrls.postLogin_url);
response2 = await http.get(afterLoginUrl , headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer
${LoginResponseData.fromJson(json.decode(response2.body)).token}'
});
if(response2.statusCode == 200){
var data = jsonDecode(response2.body);
return AfterLoginResponse.fromJson(data);
}else{
throw Exception('Failed to load data');
}
}
}
You should call the postLoginApiCall after getting response from the loginApiCall
Future<LoginResponseData> loginApiCall(Map<String, dynamic> param) async{
...
}
Future<AfterLoginResponse> postLoginApiCall() async{
...
}
loginApiCall().then((value) => postLoginApiCall()); // like this
Im trying to make a searchbar that fetch data from mysql , but i have a problem that when i call data fetch function it returns
Instance of '_Future<List>'
this is my code
Future<List<Students>> getStudents(String id) async {
var url = 'http://localhost/getStudents.php';
final response = await http.post(Uri.parse(url), body: {
'id':id,
});
var res = jsonDecode(response.body)['fname'] as List;
if (response.statusCode == 200) {
return res.map((std) => Students.fromJson(std)).toList();
}else {
throw Exception('Failed to load shows');
}
}
my class :
class Students{
final int id;
final String fname;
final String sname;
final String tname;
const Students( {
required this.id,
required this.sname,
required this.tname,
required this.fname,
});
factory Students.fromJson(Map<String, dynamic> json) => Students(
id: json['Id'],
sname: json['secname'],
tname:json['thirdname'] ,
fname: json['firstname'],
);
}
getStudents is a future function and you need to await for it:
List<Students> result = await getStudents('');
I am trying to fetch image from an api. For that I am using http package for flutter. I created Model View Controller pattern to arrange the structure of the project. Here is the api link and response:
https://wrestlingworld.co/wp-json/wp/v2/posts/128354
Response =>
[{"id":128640,"date":"2022-11-04T15:09:58","date_gmt":"2022-11-04T09:39:58","guid":{"rendered":"https:\/\/wrestlingworld.co\/?p=128640"},"modified":"2022-11-04T15:10:04","modified_gmt":"2022-11-04T09:40:04","slug":"impact-knockouts-tag-team-championship-match-announced-for-over-drive-2022","status":"publish","type":"post","link":"https:\/\/wrestlingworld.co\/news\/impact-knockouts-tag-team-championship-match-announced-for-over-drive-2022","title":{"rendered":"Impact Knockouts Tag Team Championship Match Announced for Over Drive"},"content":{"rendered":"\n<p>Impact Knockouts Tag Team Championships will be on the line at Over Drive on November 18th. It has <a href=\"https:\/\/impactwrestling.com\/2022\/11\/03\/tasha-steelz-savannah-evans-look-to-topple-the-death-dollz-in-knockouts-world-tag-team-title-showdown-at-over-drive\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">been announced<\/a> that Death Dollz (Taya Valkyrie and Jessicka) will be defending their titles against Tasha Steelz and Savannah
Here is my model:
class NewsModel {
int? id;
String? date;
String? slug;
String? status;
Title? title;
Title? content;
List<OgImage>? ogImage;
int? author;
NewsModel(
{this.id,
this.date,
this.slug,
this.status,
this.title,
this.content,
this.ogImage,
this.author});
NewsModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
date = json['date'];
slug = json['slug'];
status = json['status'];
title = json['title'] != null ? new Title.fromJson(json['title']) : null;
content =
json['content'] != null ? new Title.fromJson(json['content']) : null;
if (json['og_image'] != null) {
ogImage = <OgImage>[];
json['og_image'].forEach((v) {
ogImage!.add(new OgImage.fromJson(v));
});
}
author = json['author'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['date'] = this.date;
data['slug'] = this.slug;
data['status'] = this.status;
if (this.title != null) {
data['title'] = this.title!.toJson();
}
if (this.content != null) {
data['content'] = this.content!.toJson();
}
if (this.ogImage != null) {
data['og_image'] = this.ogImage!.map((v) => v.toJson()).toList();
}
data['author'] = this.author;
return data;
}
}
class Title {
String? rendered;
Title({this.rendered});
Title.fromJson(Map<String, dynamic> json) {
rendered = json['rendered'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['rendered'] = this.rendered;
return data;
}
}
class OgImage {
String? url;
OgImage({this.url});
OgImage.fromJson(Map<String, dynamic> json) {
url = json['url'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['url'] = this.url;
return data;
}
}
Here you can see OgImage is a list So I created a card and tried this code:
final int id;
final String title;
final String description;
final List<dynamic> img;
const NewsCard({
required this.id,
required this.title,
required this.description,
required this.img,
});
ListView.builder(
itemCount: img.length,
itemBuilder: (context, item){
return Image.network(
img[item],
height: 120,
width: double.infinity
);
},
),
Here is the front end code where I am passing value :
Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: allNews.length,
itemBuilder: (context, i) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: NewsCard(
id: allNews[i].id as int,
title: allNews[i].title!.rendered!,
description: allNews[i].content!.rendered!,
img: allNews[i].ogImage?[0].url as List<dynamic>,
),
);
}),),
Here is my controller :
Future<bool> getNews() async {
var url = Uri.parse(urlnews);
// var token = storage.getItem('token');
try {
http.Response response = await http.get(url);
print(response.body);
var data = json.decode(response.body) as List;
// print(data);
List<NewsModel> temp = [];
data.forEach((element) {
NewsModel product = NewsModel.fromJson(element);
temp.add(product);
});
_news = temp;
notifyListeners();
return true;
} catch (e) {
print(e);
return false;
}
}
List<NewsModel> get allNews {
return [..._news];
}
This code has errors I mentioned in the title already. Here I have a qustion like how can I pass list value inside the card. What is right way to fetch lists of image inside a widget.
There are a few issues with your code:
1. In your NewsModel class file, you're mapping it all wrong.
You're mapping json['og_image'] to a List, while json['og_image'] doesn't exist in the first place. If you see the JSON response, instead it's within the json['yoast_head_json'] key. So, instead of json['og_image'] you need to do json['yoast_head_json']['og_image'].
Change:
if (json['og_image'] != null) {
ogImage = <OgImage>[];
json['og_image'].forEach((v) {
ogImage!.add(new OgImage.fromJson(v));
});
}
to:
if (json['yoast_head_json'] != null &&
json['yoast_head_json']['og_image'] != null) {
ogImage = <OgImage>[];
json['yoast_head_json']['og_image'].forEach((v) {
ogImage!.add(OgImage.fromJson(v));
});
2. In your frontend part, you're trying to cast a nullable type of list allNews[i].ogImage?[0].url as List<dynamic> to List<dynamic>, which will throw exception in case the list is NULL which is in your case.
so, instead of:
img: allNews[i].ogImage?[0].url as List<dynamic>
do:
img: allNews[i].ogImage ?? []
3. Finally, in your NewsCard class:
Change:
Image.network(
img[item],
...
);
to
Image.network(
img[item].url,
...
);
Enjoy :)
I'm new to flutter.
I want to pass data from frontend to node.js backend through rest APIs(using post method). But it shows following error when app is executed.
This is the code I wrote so far. I tried to find what the error is, but unfortunately I could not find it. can somebody to help me to figure out this issue?
Model file
DataModel dataModelFromJSON(String str) => DataModel.fromJson(jsonDecode(str));
String dataModelToJson(DataModel data) => json.encode(data.toJson());
class DataModel {
DataModel({required this.title, required this.id});
String title;
String id;
factory DataModel.fromJson(Map<String, dynamic> json) =>
DataModel(title: json['title'], id: json['id']);
Map<String, dynamic> toJson() => {"name": title, "id": id};
}
Error occurred page
class PurchaseOrder extends StatefulWidget {
#override
_PurchaseOrderState createState() => _PurchaseOrderState();
}
Future<DataModel?> submitData(String title) async {
var response = await http.post(
Uri.http('176.12.10.0:8020', 'order/create'),
body: {"title": title},
);
print(title);
var data = response.body;
print(data);
if (response.statusCode == 201) {
String responseString = response.body;
return dataModelFromJSON(responseString);
} else
return null;
}
class _PurchaseOrderState extends State<PurchaseOrder> {
String today = DateFormat('yMd').format(DateTime.now());
late DataModel _dataModel;
TextEditingController titleController = TextEditingController();
#override
Widget build(BuildContext context) {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
return Container(
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your email',
),
controller: titleController,
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton(
onPressed: () async {
String title = titleController.text;
DataModel? data = await submitData(title);
setState(() {
_dataModel = data!;
});
},
child: Text("Submit"),
),
),
),
],
),
);
}
}
I hope your help to fix this issue.
Thank you
Edited:
I did following changes to the code. Error is gone. But data have not passed to the backend. What can I do.
I changed,
_dataModel = data!;
to
if (data != null) {
_dataModel = data;
}
The only null check operator in your code is _dataModel = data!;
That means your submitData method has returned a null value that was passed to data. Or when you put a null check operator you have to make sure the variable isn't null.
To avoid this error you could check if data is null and if true pass another value :
_dataModel = data ?? otherValue
The error means that somewhere in your code you are doing something with a non-nullable type, but the value is actually null.
When you use data! for example, you are telling the compiler that data will not be null, but it actually is.
You could use data ?? someValue to have a fallback, in case data is null.
I could fix "data not passing issue" also.
What I did?
I changed post request from,
var response = await http.post(
Uri.http('176.12.10.0:8020', 'order/create'),
body: {"title": title},
);
to
var response = await http.post(
Uri.parse('http://176.12.10.0:8020/order/create'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({"title": title}),
);
I'm trying to use https://pub.dev/packages/flappy_search_bar#-readme-tab- to create a list of data which I plan on getting from an api(just testing now), but I can't seem to add the list created from the response json to the search widget.
The argument type 'Future<List<Album>> Function()' can't be assigned to the parameter type 'Future<List<Album>> Function(String)'.
class Album {
final int userId;
final int id;
final String title;
Album({this.userId, this.id, this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
Future<List<Album>> fetchAlbum() async {
final response =
await http.get('https://jsonplaceholder.typicode.com/albums/1');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
List jsonResponse = json.decode(response.body);
return jsonResponse.map((job) => Album.fromJson(job)).toList();
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
#override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SearchBar<Album>(
onSearch: fetchAlbum, <------ error here
onItemFound: (Album post, int index) {
return ListTile(
onTap: () => widget.setProviderData(post.title),
title: Text(post.title),
subtitle: Text(post.id.toString()),
);
},
),
),
);
}
Can anyone help me with this, please?
I can't test your code right now, but at first glance the problem is onSearch expects a function that gets String parameter and your code doesn't provide it.
You should modify this line Future<List<Album>> fetchAlbum() async as follows:
Future<List<Album>> fetchAlbum(String album) async