显示单页中API的嵌套JSON,带有多个列表
我是新手的Flutter,我正在为API的嵌套JSON挣扎,我想在一个页面中显示该数据。
我从URL中获得此JSON并在类中解码,这很好:
{
"service1": [
{
"firstname": "Peter",
"lastname": "Smith"
},
{
"firstname": "Paul",
"lastname": "Johnson"
}
],
"service2": [
{
"firstname": "Mary",
"lastname": "Williams"
},
{
"firstname": "Guy",
"lastname": "Brown"
}
]
}
类:
/*------------------------------
staff.dart
------------------------------*/
import 'dart:convert';
class Staff {
String? service;
String? firstname;
String? lastname;
Staff({this.service, this.firstname, this.lastname});
factory Staff.fromMap(Map<String, dynamic> data) => Staff(
service: data['service'] as String?,
firstname: data['firstname'] as String?,
lastname: data['lastname'] as String?,
);
Map<String, dynamic> toMap() => {
'service': '',
'firstname': firstname,
'lastname': lastname,
};
/// Parses the string and returns the resulting Json object.
factory Staff.fromJson(String data) {
return Staff.fromMap(json.decode(data) as Map<String, dynamic>);
}
/// Converts [Staff] to a JSON string.
String toJson() => json.encode(toMap());
}
/*------------------------------
servicedesk.dart
------------------------------*/
import 'dart:convert';
import 'staff.dart';
class ServiceDesk {
List<Staff>? service1;
List<Staff>? service2;
ServiceDesk({
this.service1,
this.service2,
});
factory ServiceDesk.fromMap(Map<String, dynamic> data) => ServiceDesk(
service1: (data['service1'] as List<dynamic>?)
?.map((e) => Staff.fromMap(e as Map<String, dynamic>))
.toList(),
service2: (data['service2'] as List<dynamic>?)
?.map((e) => Staff.fromMap(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> toMap() => {
'service1': service1?.map((e) => e.toMap()).toList(),
'service2': service2?.map((e) => e.toMap()).toList(),
};
/// Parses the string and returns the resulting Json object as [ServiceDesk].
factory ServiceDesk.fromJson(String data) {
var object = ServiceDesk.fromMap(json.decode(data) as Map<String, dynamic>);
object.b1!.insert(0, Staff(service: 'Title for Service1'));
object.b2!.insert(0, Staff(service: 'Title for Service2'));
return object;
}
/// Converts to a JSON string.
String toJson() => json.encode(toMap());
}
这是我拥有的代码(伪码):
// PSEUDOCODE!!
Widget ListWithService(List<Staff>? entry) {
return ListView.builder(
itemCount: entry!.length,
padding: const EdgeInsets.all(2.0),
itemBuilder: (context, position) {
final item = entry[position];
if (item.service != null) {
return ListTile(
title: Text(
'${item.service}',
style: Theme.of(context).textTheme.headline5,
),
);
} else {
return ListTile(
title: Text(
'${item.firstname} ${item.lastname}',
style: Theme.of(context).textTheme.bodyText1,
),
);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Service Desk'),
),
body: FutureBuilder<sdclass.ServiceDesk>(
future: getData(),
builder: (context, snapshot) {
if (snapshot.hasData == true) {
return [
ListWithService(snapshot.data.service1),
ListWithSercice(snapshot.data.service1);
] // PSEUDOCODE!!
} else if (snapshot.hasError) {
return const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
}
),
);
}
我最终应该在完整页面上看起来像这样:
Service 1 (标题)
彼得·史密斯
保罗·约翰逊(Paul Johnson)
Service 2 (标题)
玛丽·威廉姆斯
盖伊·布朗(Guy Brown)
有人可以帮我处理代码以使其工作吗?
更新代码
感谢您的更新示例。我用代码测试了它。首先,一切看起来都很好。但是Wenn我使用JSON切换到屏幕,我会发现一个错误:
期望'futureor的值
import 'dart:convert';
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class ServiceDesk extends StatelessWidget {
const ServiceDesk({Key? key}) : super(key: key);
Future<Map<String, List<Map<String, String>>>> getData() async {
String link = "https://url-to-json-file.json";
final res = await http
.get(Uri.parse(link), headers: {"Accept": "application/json"});
if (res.statusCode == 200) {
var utf8decoded = utf8.decode(res.body.toString().codeUnits);
var decoded = json.decode(utf8decoded);
return decoded;
} else {
throw Exception('Failed to load JSON');
}
}
Widget listViewWidget(
Iterable<MapEntry<String, List<Map<String, String>>>> entries) {
return ListView.builder(
itemCount: entries.length,
padding: const EdgeInsets.all(2.0),
itemBuilder: (context, index) {
final entry = entries.elementAt(index);
final key = entry.key;
final values = entry.value;
return Column(
children: [
ListTile(
title: Text(
'Title for $key',
style: Theme.of(context).textTheme.headline5,
),
),
for (var person in values)
ListTile(
title: Text(
'${person["firstname"]} ${person["lastname"]}',
style: Theme.of(context).textTheme.bodyText1,
),
),
],
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Service Desk'),
),
body: FutureBuilder(
future: getData(),
builder: (_,
AsyncSnapshot<Map<String, List<Map<String, String>>>> snapshot) {
if (snapshot.hasData == true) {
final entries = snapshot.data?.entries ?? {};
return listViewWidget(entries);
} else if (snapshot.hasError) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Text("Fehler: ${snapshot.error}"),
],
));
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
}),
);
}
}
Im new in Flutter and i'm struggeling with a nested JSON from API which data i want to show in one single page.
I get this JSON from a URL and decode it in a class, which is working fine:
{
"service1": [
{
"firstname": "Peter",
"lastname": "Smith"
},
{
"firstname": "Paul",
"lastname": "Johnson"
}
],
"service2": [
{
"firstname": "Mary",
"lastname": "Williams"
},
{
"firstname": "Guy",
"lastname": "Brown"
}
]
}
Classes:
/*------------------------------
staff.dart
------------------------------*/
import 'dart:convert';
class Staff {
String? service;
String? firstname;
String? lastname;
Staff({this.service, this.firstname, this.lastname});
factory Staff.fromMap(Map<String, dynamic> data) => Staff(
service: data['service'] as String?,
firstname: data['firstname'] as String?,
lastname: data['lastname'] as String?,
);
Map<String, dynamic> toMap() => {
'service': '',
'firstname': firstname,
'lastname': lastname,
};
/// Parses the string and returns the resulting Json object.
factory Staff.fromJson(String data) {
return Staff.fromMap(json.decode(data) as Map<String, dynamic>);
}
/// Converts [Staff] to a JSON string.
String toJson() => json.encode(toMap());
}
/*------------------------------
servicedesk.dart
------------------------------*/
import 'dart:convert';
import 'staff.dart';
class ServiceDesk {
List<Staff>? service1;
List<Staff>? service2;
ServiceDesk({
this.service1,
this.service2,
});
factory ServiceDesk.fromMap(Map<String, dynamic> data) => ServiceDesk(
service1: (data['service1'] as List<dynamic>?)
?.map((e) => Staff.fromMap(e as Map<String, dynamic>))
.toList(),
service2: (data['service2'] as List<dynamic>?)
?.map((e) => Staff.fromMap(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> toMap() => {
'service1': service1?.map((e) => e.toMap()).toList(),
'service2': service2?.map((e) => e.toMap()).toList(),
};
/// Parses the string and returns the resulting Json object as [ServiceDesk].
factory ServiceDesk.fromJson(String data) {
var object = ServiceDesk.fromMap(json.decode(data) as Map<String, dynamic>);
object.b1!.insert(0, Staff(service: 'Title for Service1'));
object.b2!.insert(0, Staff(service: 'Title for Service2'));
return object;
}
/// Converts to a JSON string.
String toJson() => json.encode(toMap());
}
That's the code i have (Pseudocode between):
// PSEUDOCODE!!
Widget ListWithService(List<Staff>? entry) {
return ListView.builder(
itemCount: entry!.length,
padding: const EdgeInsets.all(2.0),
itemBuilder: (context, position) {
final item = entry[position];
if (item.service != null) {
return ListTile(
title: Text(
'${item.service}',
style: Theme.of(context).textTheme.headline5,
),
);
} else {
return ListTile(
title: Text(
'${item.firstname} ${item.lastname}',
style: Theme.of(context).textTheme.bodyText1,
),
);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Service Desk'),
),
body: FutureBuilder<sdclass.ServiceDesk>(
future: getData(),
builder: (context, snapshot) {
if (snapshot.hasData == true) {
return [
ListWithService(snapshot.data.service1),
ListWithSercice(snapshot.data.service1);
] // PSEUDOCODE!!
} else if (snapshot.hasError) {
return const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
}
),
);
}
What i would have at the end should look like this on the full page:
Title for Service1 (Headline)
Peter Smith
Paul Johnson
Title for Service2 (Headline)
Mary Williams
Guy Brown
Could someone help me with the code to get it work?
Update Code
Thanks for your updated example. I tested it in my code. First, everything looks fine. But wenn i switch to the screen with the json, i get a error:
Expected a value of type 'FutureOr<Map<String, List<Map<String, String>>>>', but got one of type '_JsonMap'
import 'dart:convert';
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class ServiceDesk extends StatelessWidget {
const ServiceDesk({Key? key}) : super(key: key);
Future<Map<String, List<Map<String, String>>>> getData() async {
String link = "https://url-to-json-file.json";
final res = await http
.get(Uri.parse(link), headers: {"Accept": "application/json"});
if (res.statusCode == 200) {
var utf8decoded = utf8.decode(res.body.toString().codeUnits);
var decoded = json.decode(utf8decoded);
return decoded;
} else {
throw Exception('Failed to load JSON');
}
}
Widget listViewWidget(
Iterable<MapEntry<String, List<Map<String, String>>>> entries) {
return ListView.builder(
itemCount: entries.length,
padding: const EdgeInsets.all(2.0),
itemBuilder: (context, index) {
final entry = entries.elementAt(index);
final key = entry.key;
final values = entry.value;
return Column(
children: [
ListTile(
title: Text(
'Title for $key',
style: Theme.of(context).textTheme.headline5,
),
),
for (var person in values)
ListTile(
title: Text(
'${person["firstname"]} ${person["lastname"]}',
style: Theme.of(context).textTheme.bodyText1,
),
),
],
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Service Desk'),
),
body: FutureBuilder(
future: getData(),
builder: (_,
AsyncSnapshot<Map<String, List<Map<String, String>>>> snapshot) {
if (snapshot.hasData == true) {
final entries = snapshot.data?.entries ?? {};
return listViewWidget(entries);
} else if (snapshot.hasError) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Text("Fehler: ${snapshot.error}"),
],
));
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
}),
);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在DART语言中,您可以在列表中使用循环,它使使用Flutter UI更容易。
复制和粘贴在
In the Dart language, you can use for loop in the list, it makes it easier to work with Flutter UI.
Copy and paste in the DartPad to test it.