How to fix "Unhandled Exception: Null check operator used on a null value" error in flutter? - flutter

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}),
);

Related

flutter: Unhandled Exception: type 'Null' is not a subtype of type 'String'

I tried to use Moralis API to call NFT via wallet address, but got following error.
Unhandled Exception: type 'Null' is not a subtype of type 'String'
These are the code lines that were pointed out as having errors.
final meta = jsonDecode(map?['metadata']);
meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';
if (response.statusCode == 200) {
nfts = jsonDecode(response.body)['result'].map<Nfts>((result) {
return Nfts.fromMap(result);
}).toList();
}
The full code for the first one is below.
import 'dart:convert';
class Nfts {
late String total;
late String page;
late String page_size;
late String cursor;
late String result;
late String token_id;
late String token_address;
late String amount;
late String owner_of;
late String token_hash;
late String block_number_minted;
late String block_number;
late String contract_type;
late String name;
late String symbol;
late String token_uri;
late String metadata;
late String last_token_uri_sync;
late String last_metadata_sync;
late String minter_address;
late String meta_name;
late String meta_image;
late String meta_description;
Nfts({
required this.total,
required this.page,
required this.page_size,
required this.cursor,
required this.result,
required this.token_id,
required this.token_address,
required this.amount,
required this.owner_of,
required this.token_hash,
required this.block_number_minted,
required this.block_number,
required this.contract_type,
required this.name,
required this.symbol,
required this.token_uri,
required this.metadata,
required this.last_token_uri_sync,
required this.last_metadata_sync,
required this.minter_address,
required this.meta_name,
required this.meta_image,
required this.meta_description,
});
Nfts.fromMap(Map<String, dynamic>? map) {
total = map?['total'] ?? '';
page = map?['page'] ?? '';
page_size = map?['page_size'] ?? '';
cursor = map?['cursor'] ?? '';
result = map?['result'] ?? '';
token_id = map?['token_id'] ?? '';
token_address = map?['token_address'] ?? '';
amount = map?['amount'] ?? '';
owner_of = map?['owner_of'] ?? '';
token_hash = map?['token_hash'] ?? '';
block_number_minted = map?['block_number_minted'] ?? '';
block_number = map?['block_number'] ?? '';
contract_type = map?['contract_type'] ?? '';
name = map?['name'] ?? '';
symbol = map?['symbol'] ?? '';
token_uri = map?['token_uri'] ?? '';
metadata = map?['metadata'] ?? '';
last_token_uri_sync = map?['last_token_uri_sync'] ?? '';
last_metadata_sync = map?['last_metadata_sync'] ?? '';
minter_address = map?['minter_address'] ?? '';
final meta = jsonDecode(map?['metadata']);
meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';
}
}
The full code for the second one is below.
class NftsProviders{
Uri uri = Uri.parse('https://deep-index.moralis.io/api/v2/(personal metamask wallet address)/nft?chain=polygon&format=decimal');
Future<List<Nfts>> getNfts() async {
List<Nfts> nfts = [];
final response = await http.get(uri, headers: {
'accept': 'application/json',
'X-API-Key' : 'o1g9ywaRjZvZaeaByxhZc7mFOBVVvDJEksU0jeZ8b34fNX03ISTc72fltfsAnuYG'
});
if (response.statusCode == 200) {
nfts = jsonDecode(response.body)['result'].map<Nfts>((result) {
return Nfts.fromMap(result);
}).toList();
}
else {
throw Exception('Failed to load NFT');
}
return nfts;
}
}
With this API, I tried to create a Gridview.builder.
class NftsScreen extends StatefulWidget {
#override
_NftsScreenState createState() {
return new _NftsScreenState();
}
}
class _NftsScreenState extends State<NftsScreen> {
List<Nfts> nfts = [];
bool isLoading = true;
NftsProviders nftsProvider = NftsProviders();
Future initNfts() async {
nfts = await nftsProvider.getNfts();
}
#override
void initState() {
super.initState();
initNfts().then((_) {
setState(() {
isLoading = false;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("nfts http"),
),
body: isLoading
? Center(
child: const CircularProgressIndicator(),
)
: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.5,
crossAxisSpacing: 20,
mainAxisSpacing: 20),
itemCount: nfts.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
// Text(nfts[index].name),
// Text(nfts[index].metadata),
CupertinoButton(
onPressed: () {},
// CircleAvatar with NetworkImage(nfts[index].meta_image)
// size of 100, 100
child: CircleAvatar(
radius: 100,
backgroundImage: NetworkImage(nfts[index].meta_image,),
)
)
],
),
);
}),
);
}
}
I want to request NFT information according to the user's wallet address called from Firebase.
Thanks in advance.
This is part of the api call response.
{
"total": null,
"page": 1,
"page_size": 100,
"cursor": null,
"result": [
{
"token_address": "0x53a0018f919bde9c254bda697966c5f448ffddcb",
"token_id": "46388765668907266497641806581710410401632846941109288029645926940148068689172",
"owner_of": "0xe3281571a136c11cc66d225902d494d29aaf7cb9",
"block_number": "30362645",
"block_number_minted": "30362645",
"token_hash": "8b025de30055bd161b2774da64fc283a",
"amount": "1",
"contract_type": "ERC721",
"name": "EDNS",
"symbol": "EDNS",
"token_uri": "https://api.edns.domains/metadata/0x53a0018f919bde9c254bda697966c5f448ffddcb/46388765668907266497641806581710410401632846941109288029645926940148068689172/metadata.json",
"metadata": "{\"name\":\"goyangtwo.meta\",\"description\":\"Domain goyangtwo.meta from EDNS Domains\",\"image\":\"https://api.edns.domains/metadata/0x53a0018f919bde9C254bda697966C5f448ffDDcB/46388765668907266497641806581710410401632846941109288029645926940148068689172/image.svg\",\"attributes\":[{\"trait_type\":\"TLD\",\"value\":\"meta\"}]}",
"last_token_uri_sync": "2022-12-06T14:08:39.924Z",
"last_metadata_sync": "2022-12-06T14:08:44.789Z",
"minter_address": "0x805ec22fca66eca02e244689b47fc2f180a94f01"
}
],
"status": "SYNCED"
}
can you share the response of the api call, most probably there will be a typo in the JSON decoding
meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';
try quicktype.io to generate response models
What's the source of Nfts? Do you not have accidently defined a field like cursor or total as String instead of String? Otherwise, please provide the code for Nfts as it might have fields of type String without defaults that are not present in the json, causing the Nfts.fromMap(result); to fail.
As a general tip, it is wise to NOT assume that this will always succeed. In case it fails, then i.e. return null instead of crashing your app.
Edit added solution:
In the function
Nfts.fromMap(Map<String, dynamic>? map) {}
the variable map will be the full map (with total, page, result, etc. entries) which does not contain a metadata tag, so...
final meta = jsonDecode(map?['metadata']);
will be the same as
final meta = jsonDecode(null);
which is the reason for the error message. A string is expected!
However, you already jsonDecode (d) the response, so why do it again, because you already have a map of the response :)
You just need to pick the right tags from the map.
final result = map?['result'];
final metadata = result?['metadata'];
meta_name = metadata?['name'] ?? '';
meta_image = metadata?['image'] ?? '';
meta_description = metadata?['description'] ?? '';
final result = map?['result'];
final metadata = result?['metadata'];
meta_name = metadata?['name'] as String? ?? '';
meta_image = metadata?['image'] as String? ?? '';
meta_description = metadata?['description'] as String? ?? '';

Display data fetched from JSON API in app

I am developing a Stock app in which I have to display News related to the stocks. I made a News class for the same as well as a factory constructor to convert the data from json
class News {
final String title;
final String desc;
final String imgURL;
final String url;
News(
{required this.title,
required this.desc,
required this.imgURL,
required this.url});
factory News.fromJSON(Map<String, dynamic> json) {
final title = json["title"] as String;
final desc = json["description"] as String;
final imgUrl = json["image_url"] as String;
final url = json["url"] as String;
return News(title: title, desc: desc, imgURL: imgUrl, url: url);
}
}
I have made a method to fetch the data from the API:
Future getNews() async {
final response = await http.get(Uri.parse(
'https://api.stockdata.org/v1/news/all?&filter_entities=true&language=en&api_token=${api_token}&countries=${country}'));
if (response.statusCode == 200) {
final jsonResponse = json.decode(response.body);
return jsonResponse.map((data) => News.fromJSON(data));
} else {
throw Exception('Unexpected error occurred!');
}
}
I am having trouble understanding how I can display the data in my app. I tried using FutureBuilder but I can't seem to understand how it's working.
Any help would be appreciated!
For the FutureBuilder you can do it this way :
FutureBuilder(
future: getNews(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
// Save your data in a variable
List<News> news = snapshot.data;
// Create a listview to show all of the news
return newsListView(news); //This is a list
} else {
return Center(
child: Container(
width: 300,
height: 290,
child: Center(child: Text("Error"))
)
);
}
}
),

Flutter show data from mock .json file

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'),
),
);
}
}

fetch data by using flutter http request and load more data on scroll down the screen

i fetch data from server using flutter http request and load more data when user scroll to bottom of screen. i receive this error "Unhandled Exception: type 'List' is not a subtype of type 'Product'". Please help, i struggle all day without success.
model.dart file
class Product {
final int id;
final String accountName,
callNumber,
whatsappNumber,
businessLocation,
caption;
final List<Images> productPhoto;
Product({
this.id,
this.accountName,
this.callNumber,
this.whatsappNumber,
this.businessLocation,
this.caption,
this.productPhoto,
});
// this is static method
factory Product.fromJson(Map<String, dynamic> json) {
return Product(
id: json['id'],
accountName: json['account_name'],
callNumber: json['call_number'],
whatsappNumber:
json['whatsapp_number'] != null ? json['whatsapp_number'] : null,
businessLocation: json['business_location'],
caption: json['caption'],
productPhoto:
(json['post_photos'] as List).map((i) => Images.fromJson(i)).toList(),
);
}
}
class Images {
final String filename;
Images({this.filename});
factory Images.fromJson(Map<String, dynamic> json) {
return Images(
filename: json['filename'],
);
}
}
explore.dart file (i import models.dart to this file)
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:windowshoppi/models/global.dart';
import 'package:windowshoppi/models/product.dart';
import 'package:http/http.dart' as http;
class Explore extends StatefulWidget {
#override
_ExploreState createState() => _ExploreState();
}
class _ExploreState extends State<Explore> {
ScrollController _scrollController = ScrollController();
List<Product> data;
String nextUrl;
#override
void initState() {
// TODO: implement initState
super.initState();
this.fetchProduct(http.Client(), ALL_PRODUCT_URL);
_scrollController.addListener(() {
// print(_scrollController.position.pixels);
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
if (nextUrl != null) {
this.fetchProduct(http.Client(), nextUrl);
}
// print(nextUrl);
}
});
}
Future<List<Product>> fetchProduct(http.Client client, url) async {
final response = await client.get(url);
if (response.statusCode == 200) {
Map<String, dynamic> mapResponse = json.decode(response.body);
nextUrl = mapResponse['next'];
if (mapResponse["count"] != "") {
final products = mapResponse["results"].cast<Map<String, dynamic>>();
final listOfProducts = await products.map<Product>((json) {
return Product.fromJson(json);
}).toList();
// return listOfProducts;
setState(() {
data.add(listOfProducts);
});
} else {
return [];
}
} else {
throw Exception('failed to load data from internet');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('http get'),
),
body: ListView.builder(
controller: _scrollController,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Container(
height: 200,
color: Colors.blue,
child: Text(data[index].caption),
),
);
},
),
);
}
}
Have a look at this part of the code.
final listOfProducts = await products.map<Product>((json) {
return Product.fromJson(json);
}).toList();
In the .map() method you are casting it to type < Product >. So judging by the error you have mentioned, "Unhandled Exception: type 'List' is not a subtype of type Product"
I think the json data being returned contains a List, instead of the product fields. I would highly recommend you to once check the json data being returned, and double-check if you are targeting the correct JSON tree nodes.
Let me know if this solved the issue.

List from json API response

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