I am trying to get string value from the API to the list in a flutter.
Each time I try to get the list there is an exception "Unhandled Exception: type 'String' is not a subtype of type 'Map'"
the data I have is in the format given below:
{
"status": 1,
"data": [
"Chapter 1",
"Chapter 2",
]
}
Use this response class to load response and access all the variables.
class ResponseData {
String status;
List<String> data;
ResponseData({
this.status,
this.data,
});
factory ResponseData.fromJson(Map<String, dynamic> json) => ResponseData(
status: json["status"],
data: List<String>.from(json["data"].map((x) => x)),
);
}
Add our response json to ResponseData class
ResponseData responseDataFromJson(String responseFromServiceCall) => ResponseData.fromJson(json.decode(responseFromServiceCall));
From the above mentioned json i have created a sample json for ListView :
{
"status": 1,
"data": [
"Chapter 1",
"Chapter 2"
]
}
Creating a model class from the json :
// To parse this JSON data, do
//
// final data = dataFromJson(jsonString);
import 'dart:convert';
Data dataFromJson(String str) => Data.fromJson(json.decode(str));
String dataToJson(Data data) => json.encode(data.toJson());
class Data {
int status;
List<String> data;
Data({
this.status,
this.data,
});
factory Data.fromJson(Map<String, dynamic> json) => Data(
status: json["status"],
data: List<String>.from(json["data"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"status": status,
"data": List<dynamic>.from(data.map((x) => x)),
};
}
Parsing data and then rendering it on ui :
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dummy.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<String> dataList = List();
bool _isLoading = false;
#override
void initState() {
super.initState();
loadYourData();
}
Future<String> loadFromAssets() async {
return await rootBundle.loadString('json/parse.json');
}
loadYourData() async {
setState(() {
_isLoading = true;
});
String jsonString = await loadFromAssets();
final data = dataFromJson(jsonString);
// here you get the complete object
dataList = data.data;
setState(() {
_isLoading = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: _isLoading
? CircularProgressIndicator()
: ListView.builder(
itemCount: dataList.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(dataList[index]),
),
],
),
);
},
),
),
),
);
}
}
Following is the parse.json file :
And below is the pubspec file where you need to define the json folder :
Let me know if it works.
Related
im trying to call an api.
This is model :
// To parse this JSON data, do
//
// final economylist = economylistFromJson(jsonString);
import 'dart:convert';
Economylist economylistFromJson(String str) => Economylist.fromJson(json.decode(str));
String economylistToJson(Economylist data) => json.encode(data.toJson());
class Economylist {
Economylist({
required this.success,
required this.result,
});
bool success;
List<dynamic> result;
factory Economylist.fromJson(Map<String, dynamic> json) => Economylist(
success: json["success"],
result: List<dynamic>.from(json["result"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"success": success,
"result": List<dynamic>.from(result.map((x) => x)),
};
}
class ResultClass {
ResultClass({
required this.key,
required this.url,
required this.description,
required this.image,
required this.name,
required this.source,
});
String key;
String url;
String description;
String image;
String name;
String source;
factory ResultClass.fromJson(Map<String, dynamic> json) => ResultClass(
key: json["key"],
url: json["url"],
description: json["description"],
image: json["image"],
name: json["name"],
source: json["source"],
);
Map<String, dynamic> toJson() => {
"key": key,
"url": url,
"description": description,
"image": image,
"name": name,
"source": source,
};
}
This is my file where i call api
import 'package:flutter/material.dart';
import 'package:halkaarzhisseler/models/apis/economy_api.dart';
import 'package:http/http.dart' as http;
class Economy extends StatefulWidget {
const Economy({Key? key}) : super(key: key);
#override
State<Economy> createState() => _EconomyState();
}
class _EconomyState extends State<Economy> {
final scaffoldKey = GlobalKey<ScaffoldState>();
final url = Uri.parse('https://api.collectapi.com/news/getNews?country=tr&tag=economy');
var counter;
Economylist? haberResult;
Future callHaber() async {
try{
Map<String, String> requestHeaders = {
'Content-Type': 'application/json',
'Authorization': 'apikey xxx'
};
final response = await http.get(url,headers:requestHeaders);
if(response.statusCode == 200){
var result = economylistFromJson(response.body);
if(mounted);
setState(() {
counter = result.result.length;
haberResult = result;
});
return result;
} else {
print(response.statusCode);
}
} catch(e) {
print(e.toString());
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
callHaber();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
automaticallyImplyLeading: false,
title: Text(
'Hisseler'
),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: counter != null ?
ListView.builder(
itemCount: counter,
itemBuilder: (context, index){
return Card(
child: ListTile(
title: Text(haberResult?.result[index].name??""),
subtitle: Text(haberResult?.result[index].source??""), ),
);
}) : Center(child: CircularProgressIndicator(
)),
),
),
);
}
}
This is the error i get :
I think im making some mistake when im calling the api about Future but i couldnt fix it. How can i fix this?
thanks for your help
You need to change result property of Economylist class to List. use this model class:
class Economylist {
Economylist({
required this.success,
required this.result,
});
bool success;
List<ResultClass> result;
factory Economylist.fromJson(Map<String, dynamic> json) => Economylist(
success: json["success"],
result: json["result"].map<ResultClass>((x) => ResultClass.fromJson(x)).toList(),
);
Map<String, dynamic> toJson() => {
"success": success,
"result": result.map((x) => x.toJson()),
};
}
I have this API https://questinternational.ph/api/get_hotelphotos
[{
"id": 1,
"photo": "https://images.unsplash.com/photo-1520342868574-5fa3804e551c?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=6ff92caffcdd63681a35134a6770ed3b&auto=format&fit=crop&w=1951&q=80",
"price": 120.12
},
{
"id": 2,
"photo": "https://images.unsplash.com/photo-1522205408450-add114ad53fe?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=368f45b0888aeb0b7b08e3a1084d3ede&auto=format&fit=crop&w=1950&q=80",
"price": 4303.22
}]
How can I implement in carousel_slider 4.1.1
Using http request?
You can create a model and map the retrieved data with the API to facilitate further manipulation of the information in the code
class Hotel {
final int id;
final String photo;
final double price;
Hotel({
required this.id,
required this.photo,
required this.price,
});
factory Hotel.fromMap(Map<String, dynamic> map) {
return Hotel(
id: map['id'],
photo: map['photo'],
price: (map['price'] as num).toDouble(),
);
}
}
Now you can retrieve the list with a helper
import 'package:http/http.dart' as http;
import 'dart:convert';
class Helper {
static Future<List<Hotel>> getListHotel() async {
late List<Hotel> listHotels = [];
var url = Uri.parse("https://questinternational.ph/api/get_hotelphotos");
var response = await http.get(url);
var hotelMap = json.decode(response.body);
for (var item in hotelMap) {
listHotels.add(Hotel.fromMap(item));
}
return listHotels;
}
}
The view:
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
TestPage({Key? key}) : super(key: key);
#override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Image Slider demo')),
body: FutureBuilder(
future: Helper.getListHotel(),
builder: ((context, AsyncSnapshot<List<Hotel>> snapshot) {
var data = snapshot.data;
if (data == null) {
return Center(child: CircularProgressIndicator());
}
return CarouselSlider(
options: CarouselOptions(),
items: data
.map((item) => Container(
child: Image.network(item.photo,
fit: BoxFit.cover, width: 1000),
))
.toList(),
);
}),
),
);
}
}
But don't forget that it's just a proposal, because there are several ways to do it.
I'm trying to show data of only one object from the list below based on the value of its selected id, using the flutter DropdownMenuItem widget
The list received from the REST API looks like this:
[ {
"id" : "123",
"name" : "firstItem",
"description" : "firstDescription",
}, {
"id" : "321",
"name" : "secondItem",
"description" : "secondDescription",
} ]
And the code I use to handle the response looks like this:
Future<List<ObjectName>>? getData() async {
const String url = 'urlOfAPI';
var response = await http.get(
Uri.parse(url),
headers: {
"content-type": "application/json",
"accept": "application/json",
},
);
if (response.statusCode == 200) {
final parsed = json.decode(response.body).cast<Map<String, dynamic>>();
return parsed.map<ObjectName>((json) => ObjectName.fromJson(json)).toList();
} else {
throw Exception('Failed to load');
}
}
I'd like to know how to access the objects from inside flutter DropdownButton widget and show each object's "name" and "description" values based on the selected "id" value inside
DropdownMenuItem e.g.
if selected value == "321"
return secondItem & secondDescription
Here is the example to check the selected value inside onChange
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
final jsonString =
'[{"id":"123","name":"firstItem","description":"firstDescription"},{"id":"321","name":"secondItem","description":"secondDescription"}]';
void main() {
runApp(MyApp());
}
//Create it as Global key
final myListKey = GlobalKey<AnimatedListState>();
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({
Key? key,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<User> users = [];
User? selected;
#override
void initState() {
super.initState();
fetchAndShow();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: DropdownButton<User>(
value: selected,
onChanged: (User? newValue) {
// here you'll get selected value
setState(() {
selected = newValue!;
});
},
items: users
.map(
(e) => DropdownMenuItem(
child: Text(e.name),
value: e,
),
)
.toList(),
),
),
);
}
Future<List<User>>? getData() async {
//API call here and return users
return userFromJson(jsonString);
}
Future<void> fetchAndShow() async {
final users = await getData();
setState(() {
this.users = users ?? [];
});
}
}
List<User> userFromJson(String str) =>
List<User>.from(json.decode(str).map((x) => User.fromJson(x)));
String userToJson(List<User> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class User {
User({
required this.id,
required this.name,
required this.description,
});
String id;
String name;
String description;
factory User.fromJson(Map<String, dynamic> json) => User(
id: json["id"],
name: json["name"],
description: json["description"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"description": description,
};
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class DataTableDemo extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Service History'),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
PaginatedDataTable(
header: Text('Service Details'),
rowsPerPage: 4,
columns: [
DataColumn(label: Text('SrNo.')),
DataColumn(label: Text('Customer Name')),
DataColumn(label: Text('Mobile Number')),
DataColumn(label: Text('Address')),
DataColumn(label: Text('Company')),
DataColumn(label: Text('Model')),
DataColumn(label: Text('REGNo')),
],
source: _DataSource(context),
),
],
),
);
}
}
fetchSummary() async {
final response = await http.get('https://api');
if (response.statusCode == 200) {
var parsed = json.decode(response.body);
List jsonResponse = parsed["Table"] as List;
return jsonResponse.map((job) => new _Row.fromJson(job)).toList();
} else {
print('Error, Could not load Data.');
throw Exception('Failed to load Data');
}
}
class _Row {
_Row(
this.srNo,
this.customerName,
this.mobileNumber,
this.address,
this.company,
this.model,
this.rEGNo,
);
final int srNo;
final String customerName;
final String mobileNumber;
final String address;
final String company;
final String model;
final String rEGNo;
bool selected = false;
factory _Row.fromJson(Map<String, dynamic> json) {
return _Row(
json['SrNo'],
json['CustomerName'],
json['MobileNumber'],
json['Address'],
json['Company'],
json['Model'],
json['REGNo'],
);
}
}
class _DataSource extends DataTableSource {
_DataSource(this.context) {
_rows =
fetchSummary();
}
final BuildContext context;
List<_Row> _rows;
int _selectedCount = 0;
#override
DataRow getRow(int index) {
assert(index >= 0);
if (index >= _rows.length) return null;
final row = _rows[index];
return DataRow.byIndex(
index: index,
//selected: row.selected,
onSelectChanged: (value) {
if (row.selected != value) {
_selectedCount += value ? 1 : -1;
assert(_selectedCount >= 0);
row.selected = value;
notifyListeners();
}
},
cells: [
DataCell(Text(row.srNo.toString())),
DataCell(Text(row.customerName)),
DataCell(Text(row.mobileNumber)),
DataCell(Text(row.address)),
DataCell(Text(row.company)),
DataCell(Text(row.model)),
DataCell(Text(row.rEGNo)),
],
);
}
#override
int get rowCount => _rows.length;
#override
bool get isRowCountApproximate => false;
#override
int get selectedRowCount => _selectedCount;
}
i have tried this code but getting error when bind data. when i call API and get data (Json format) from server, unable to convert data and got error.how can i convert my data and bind into PaginatedDataTable.
Source Code From: [https://material.io/components/data-tables/flutter#theming-data-tables] .
What you need is a change notifier.
Lets make a quick example.
Here is my model:
{
"id":1,
"name": "John Doe",
"username":"johndoe",
"email":"johndoe#mail.com",
"address":"address",
"phone":"1234567890",
"website":"johndoe.com",
"company":"johndoe pty ltd"
}
then my flutter data model will look something like this:
import 'dart:convert';
List<UserModel> userModelFromJson(String str) =>
List<UserModel>.from(json.decode(str).map((x) => UserModel.fromJson(x)));
String userModelToJson(List<UserModel> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class UserModel {
UserModel({
this.id,
this.name,
this.username,
this.email,
this.address,
this.phone,
this.website,
this.company,
});
int id;
String name;
String username;
String email;
Address address;
String phone;
String website;
Company company;
factory UserModel.fromJson(Map<String, dynamic> json) => UserModel(
id: json["id"],
name: json["name"],
username: json["username"],
email: json["email"],
address: Address.fromJson(json["address"]),
phone: json["phone"],
website: json["website"],
company: Company.fromJson(json["company"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"username": username,
"email": email,
"address": address.toJson(),
"phone": phone,
"website": website,
"company": company.toJson(),
};
}
Next I will create a Data Change Notifier for the UserModel Class:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart' show PaginatedDataTable;
class UserDataNotifier with ChangeNotifier {
UserDataNotifier() {
fetchData();
}
List<UserModel> get userModel => _userModel;
var _userModel = <UserModel>[]
Future<void> fetchData() async {
_userModel = await Api.fetchData();
notifyListeners();
}
}
Notice that we are using _userModel = await Api.fetchData(); this can be your own implementation for an API. If you need assistance with this, look into Dio for Flutter.
Data is fetched on the init of the ChangeNotifier.
Next we will create a datasource to house all the data:
import 'package:flutter/material.dart';
class UserDataTableSource extends DataTableSource {
UserDataTableSource({
#required List<UserModel> userData,
#required this.onRowSelect,
}) : _userData = userData,
assert(userData != null);
final List<UserModel> _userData;
final OnRowSelect onRowSelect;
#override
DataRow getRow(int index) {
assert(index >= 0);
if (index >= _userData.length) {
return null;
}
final _user = _userData[index];
return DataRow.byIndex(
index: index, // DON'T MISS THIS
cells: <DataCell>[
DataCell(Text('${_user.name}')),
DataCell(Text('${_user.username}')),
DataCell(Text('${_user.email}')),
DataCell(Text('${_user.address}')),
DataCell(Text('${_user.phone}')),
DataCell(Text('${_user.website}')),
DataCell(Text('${_user.company}')),
],
);
}
#override
bool get isRowCountApproximate => false;
#override
int get rowCount => _userData.length;
#override
int get selectedRowCount => 0;
}
Lastly we will use this Change Notifier and DataSource within our Widget:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class DataTableScreen extends StatelessWidget {
const DataTableScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
//
return Stack(
// scrollDirection: Axis.horizontal,
children: [
ChangeNotifierProvider(
create: (_) => UserDataNotifier(),
child: _InternalWidget()
)
],
);
}
}
class _InternalWidget extends StatelessWidget {
const _InternalWidget({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
//
final _provider = context.watch<UserDataNotifier>();
final _model = _provider.userModel;
if (_model.isEmpty) {
return const SizedBox.shrink();
}
final _dtSource = UserDataTableSource(
userData: _model,
);
return PaginatedDataTable(
source: _dtSource,
horizontalMargin: 10,
columnSpacing: 10,
showFirstLastButtons: true,
rowsPerPage: PaginatedDataTable.defaultRowsPerPage,
columns: const [
DataColumn(
label: Text("Name"),
),
DataColumn(
label: Text("User Name"),
),
DataColumn(
label: Text("E-mail"),
),
DataColumn(
label: Text("Address"),
),
DataColumn(
label: Text("Phone"),
),
DataColumn(
label: Text("Website"),
),
DataColumn(
label: Text("Company"),
)
],
);
}
}
I am trying to show the JSON data from a URL to my Flutter application and haven't found any solution yet.
How to show this data in the ListView in Flutter?
Here is my complete Flutter project code:
Main.dart
import 'package:flutter/material.dart';
import 'package:jsontest/Json.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Cricket',
theme: new ThemeData(
primarySwatch: Colors.green,
),
home: new JsonParseDemo(),
);
}
}
Match.dart Where Json Data is in organized form
import 'dart: convert';
Match matchesFromJson(String str) => Match.fromJson(json.decode(str));
String matchesToJson(Match data) => json.encode(data.toJson());
class Match {
Match({
this.name,
this.status,
});
String name;
String status;
factory Match.fromJson(Map<String, dynamic> json) => Match(
name: json["name"],
status: json["status"],
);
Map<String, dynamic> toJson() => {
"name": name,
"status": status,
};
}
Service.dart Here is the base URL to get JSON data
import 'package:http/http.dart' as http;
import 'Users.dart';
class Services {
//
static const String url = 'https://api.cricket.com.au/matches';
static Future<List<Match>> getMatches() async{
try{
final response = await http.get(url);
if (200 == response.statusCode){
final List<Match> match = matchesFromJson(response.body) as List<Match>;
return match;
}
else{
return List<Match>();
}
}
catch(e){
return List<Match>();
}
}
}
And here is the code of my main class where I want to show the data.
JsonParser.dart
import 'package:flutter/material.dart';
import 'Services.dart';
import 'Users.dart';
class JsonParseDemo extends StatefulWidget {
//
JsonParseDemo() : super();
#override
_JsonParseDemoState createState() => _JsonParseDemoState();
}
class _JsonParseDemoState extends State<JsonParseDemo> {
//
List<Match> _match;
bool _loading;
#override
void initState() {
super.initState();
_loading = true;
Services.getMatches().then((matches) {
setState(() {
_loading = false;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_loading ? 'Loading...' : 'Matches'),
),
body: Container(
color: Colors.white,
child: ListView.builder(
itemCount: null == _match ? 0 : _match.length,
itemBuilder: (context, index) {
Match match = _match[index];
return ListTile(
title: Text(match.name),
subtitle: Text(match.status),
);
},
),
),
);
}
}
How to get "Name and Status" of the match from this JSON?
Try my code below :
json_parse_demo_screen.dart
class JsonParseDemo extends StatefulWidget {
//
JsonParseDemo() : super();
#override
_JsonParseDemoState createState() => _JsonParseDemoState();
}
class _JsonParseDemoState extends State<JsonParseDemo> {
//
List<Match> _match;
bool _loading = true;
#override
void initState() {
super.initState();
_loading = true;
Services.getMatches().then((matches) {
setState(() {
_match = matches;
_loading = false;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_loading ? 'Loading...' : 'Matches'),
),
body: Container(
color: Colors.white,
child: ListView.builder(
itemCount: null == _match ? 0 : _match.length,
itemBuilder: (context, index) {
Match match = _match[index];
return ListTile(
title: Text(match.name),
subtitle: Text(match.status),
);
},
),
),
);
}
}
match.dart
import 'dart:convert';
String matchesToJson(Match data) => json.encode(data.toJson());
class Match {
Match({
this.name,
this.status,
});
String name;
String status;
factory Match.fromJson(Map<String, dynamic> json) => Match(
name: json["name"],
status: json["status"],
);
Map<String, dynamic> toJson() => {
"name": name,
"status": status,
};
}
service.dart
Here, you will have to check the hierarchy of the response you get.
The hierarchy of response is:
- meta
- matchList
- matches
Then you have to look for the result you expect (here matches)
class Services {
//
static const String url = 'https://api.cricket.com.au/matches';
static Future<List<Match>> getMatches() async{
try{
final response = await http.get(url);
final responseFormatted = json.decode(response.body);
final matches = responseFormatted["matchList"]["matches"];
if (200 == response.statusCode){
final List<Match> match = matches.map<Match>((item) => Match.fromJson(item)).toList();
return match;
}
else{
return List<Match>();
}
}
catch(e){
return List<Match>();
}
}
}
Output
You didn't initialize match
List<Match> _match;
You can do it like this
Services.getMatches().then((matches) {
setState(() {
_match=matches
_loading = false;
});
});