I have a list of strings which is held in an object and is stored in shared preferences.
I have used ScopedModel for my state management and I am trying to get it to read the list from the shared preferences from here.
class Item {
String _weight;
String _name;
String _id;
Item(this._weight, this._name, this._id);
Item.fromJson(Map<String, dynamic> m) {
_weight = m['weight'] as String;
_name = m['name'] as String;
_id = m['id'] as String;
}
String get id => _id;
String get name => _name;
String get weight => _weight;
Map<String, dynamic> toJson() => {
'weight': _weight,
'name': _name,
'id': _id,
};
}
My Model in the ScopedModel folder which is passed down;
mixin ListItem on Model {
String itemKey = 'itemKey';
List<Item> _items = [];
List<Item> get items {
return List.from(_items);
}
Future<Null> readList() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final data = json.decode(prefs.getString(itemKey).toString());
final item = List<Item>.from(data.map((i) => Item.fromJson(i)));
_items = item;
print(jsonDecode(prefs.getString(itemKey)));
notifyListeners();
}
Future<Null> addItem({String id, String name, String weight}) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final Item item = Item(
id,
name,
weight,
);
_items.add(item);
prefs.setString(itemKey, jsonEncode(_items));
notifyListeners();
}
Future<Null> deleteProduct() async {
notifyListeners();
}
}
Part of my stateful widget which runs the initState to call the list from sharedPreferences
class _ListItemsState extends State<ListItems> {
final MainModel _model = MainModel();
final TextEditingController controller = TextEditingController();
#override
void initState() {
_model.readList();
super.initState();
}
#override
Widget build(BuildContext context) {
return ScopedModelDescendant<MainModel>(
builder: (BuildContext context, Widget child, MainModel model) {
return Scaffold(
appBar: AppBar(),
body: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
TextField(
controller: controller,
),
FlatButton(
child: Text('Submit'),
onPressed: () {
model.addItem(
id: controller.text,
name: controller.text,
weight: controller.text,
);
},
),
]),
),
model.items.length > 0
? SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Dismissible(
key: Key(model.items[index].id),
background: Container(
color: Colors.redAccent,
),
onDismissed: (DismissDirection direction) {
model.deleteProduct();
},
child: ListTile(
leading: Text(model.items[index].name),
trailing: Text(model.items[index].weight),
onTap: () {},
),
);
},
childCount: model.items.length,
),
)
: SliverFillRemaining(),
],
));
},
);
}
}
My issue is that on the initState the list doesn't appear from the readList() - I'm not sure what I am doing wrong as when I run the print(json.decode(prefs.getString(itemKey)); it calls the list of items that are held from the sharedPreferences as [{weight: HelloWorld, name: HelloWorld, id: HelloWorld}] which looks like it should be fine to decode.
Can anyone help point out what I'm doing wrong? Thanks in advance.
In your code, you have 2 different models:
final MainModel _model = MainModel();
and another model from builder
builder: (BuildContext context, Widget child, MainModel model)
It looks like that there is no connection/link/map between _model and model. You have to link them together like in this discussion.
Related
I am currently developing an ecommerce app. I use a ListView.builder to display data but I don't know how to fetch the products according to the selected category.
Here is the model of the list of categories
class Category {
final int id;
String name;
String image;
String slug;
Category({this.id, this.name, this.image, this.slug,});
factory Category.fromJson(Map<String, dynamic> json) {
return Category(
id: json['id'],
name: json['name'],
image: json['image'].toString(),
slug: json['slug'],
);
}
}
class Produit {
String productName;
String productImage;
int productPrice;
String description;
int rating;
int numberOfRating;
int category;
Produit(
{this.productName,
this.productImage,
this.productPrice,
this.description,
this.rating,
this.numberOfRating,
this.category});
factory Produit.fromJson(Map<String, dynamic> json) {
return Produit(
productName: json['name'],
productImage: json["image"],
productPrice: json["prix"],
description: json["description"].toString(),
rating: json["rating"],
numberOfRating: json["numberOfRating"],
category: json["category"]
);
}
}
This is the widget that displays the list of products by category.
class ProduitPage extends StatefulWidget {
ProduitPage({
Key key,
this.categoryId,
}) : super(key: key);
int categoryId;
#override
_ProduitPageState createState() => _ProduitPageState();
}
class _ProduitPageState extends State<ProduitPage> {
List<Produit> _produits = List<Produit>();
Future<List<Produit>> fetchProduits() async {
//var url = 'http://192.168.8.100:8000/api/produits';
var url = apilink + prod_url;
final response = await http.get(url);
var produits = List<Produit>();
if (response.statusCode == 200) {
var produitsJson = json.decode(response.body);
for (var produitJson in produitsJson) {
produits.add(Produit.fromJson(produitJson));
}
return produits;
} else {
throw Exception('Impossible de charger les données.');
}
}
#override
Widget build(BuildContext context) {
fetchProduits().then((value) {
_produits.addAll(value);
});
return Container(
child: Scaffold(
appBar: AppBar(
title: Text('Restaurant'),
backgroundColor: Colors.amber,
brightness: Brightness.light,
actions: <Widget>[
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
new SearchWidget()));
},
icon: Icon(
Icons.search,
color: Colors.white,
),
iconSize: 30,
),
CartIconWithBadge(),
]),
body: Container(
child: ListView.builder(
itemCount: _produits.length,
itemBuilder: (BuildContext context, int i) {
return Container(
child: (_produits[i].category == categoryId),
);
},
))),
);
}
}
Now I want to display data by selected category. Please I really need your help. thanks!!
Thank you for updating your question
While there are many ways you can achieve your desired result, I have mentioned one solution below.
Since you have a list of products available in the widget, you can use the List.where method to filter the product list by category and display the results of that function in your widget
More details and sample code available on
Note: Replace calling the API function in the build method directly and replace it with the FutureBuilder widget. The code sample above will make a call to the API on each build.
More details and sample code available on flutter docs
I'm trying out the StreamBuilder so I call the API and the return values of the snapshot are always null. When I print the print(snapshot.error.toString()); it returns null. I've tried parsing the data differently but failed to do so. Here is the complete code:
var posts = <Post>[];
var controller = StreamController<List<Post>>();
#override
void initState() {
super.initState();
fetchPosts();
}
fetchPosts() async {
final resp =
await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
final data = json.decode(resp.body);
posts = data.map<Post>((e) => Post()).toList();
print(posts.isEmpty); // returns false
pirnt(data); // returns the entire data
controller.add(posts);
}
bool isSwitched = false;
void toggleSwitch(bool value) {
if (isSwitched == false) {
controller.add(posts..sort((k1, k2) => k1.id.compareTo(k2.id)));
print('Switch Button is ON');
} else {
controller.add(posts..sort((k1, k2) => k2.id.compareTo(k1.id)));
print('Switch Button is OFF');
}
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
children: [
Expanded(
child: TextButton(
child: Text('sort ascending'),
onPressed: () {
toggleSwitch(isSwitched = !isSwitched);
}),
),
],
),
Expanded(
child: StreamBuilder<List<Post>>(
initialData: posts,
stream: controller.stream,
builder: (ctx, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
print(snapshot.error.toString);
Post post = snapshot.data[index];
return ListTile(
title: Text('${posts[index].id}'), // returns null
subtitle: Text('${post.id}'), // returns null
trailing: Text('${snapshot.data[index].id}'), // returns null
);
},
);
},
),
),
],
);
}
The Post model:
import 'package:flutter/foundation.dart';
import 'dart:core';
class Post extends ChangeNotifier {
final int userId;
final int id;
final String title;
final String body;
Post({this.userId, this.id, this.title, this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
userId: json['userId'],
id: json['id'],
title: json['title'],
body: json['body'],
);
}
}
Am I parsing the data wrong in the API call? Or is it something else? Thanks in advance for the help.
So my new teacher/friend #pskink that makes me learn and makes me use my brain these days, again helped me realize the mistake. Always make sure you are parsing the JSON data as it should. In my case, I forgot the fromJson(e) in the fetchPosts() method.
So the answer to this problem is:
posts = data.map<Post>((e) => Post.fromJson(e)).toList();
I am new to flutter and trying to fetch API data into a list. My goal is to later input that information into a ListView.
I am familiar with doing api calls but now I'm triying to get information from a json array. Previously I made a model class to retrieve the objects I need to continue with my process, but I've reached a dead end since I can't seem to figure out how to extract the objects from an array properly.
I am using multiple files. "API Services", "readData Model", and the actual screen where the data will be shown.
Everything else is fine, it's just that I am unable to actually save the data to a list.
First I will show you how my code is set up and the JSON response data I am trying to save:
JSON Response Body:
The example I am showing only has one chunk of image data, but we need an array for it since it should be displaying every chunk in a list.
{"status":200,
"content":[{"image_id":"151",
"image_url":"https:\\\/imageurl.jpg",
"returned_value":"14.0",
"alarm":"false",
"account":"test#email.com",
"create_at":"2020-11-17 07:13:42",
"location":"NY"
}]
}
API POST function:
Future<ReadResponseModel> readData(
ReadRequestModel requestData) async {
final response = await http.post("$url/read",
body: requestData.toJson() ,
headers: {
"Client-Service": "frontend-client",
"Auth-Key": "simplerestapi",
"Content-Type":"application/x-www-form-urlencoded",
"Authorization": token,
"User-ID": userId,
});
print(response.body);
if (response.statusCode == 200 || response.statusCode == 400) {
dynamic resBody = json.decode(response.body);
return ReadResponseModel.fromJson(resBody);
} else {
throw Exception('Failed to load data!');
}
}
readResponseModel Class:
I have tried two methods to process this information but have failed at both of them.
This is Method 1:
This one will give me the following error: [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
Originally set as final String for all values, but since I was getting this error I've been trying to make sure each one is the correct type (ex. retVal as int or alarm as bool). Still no luck so far.
class ReadResponseModel {
final dynamic imageID;
final dynamic imgUrl;
final dynamic retVal;
final bool alarm;
final dynamic account;
final dynamic createAt;
final dynamic location;
ReadResponseModel({this.imageID, this.imgUrl, this.retVal, this.alarm,
this.account, this.createAt, this.location,});
factory ReadResponseModel.fromJson(Map<String , dynamic> json) {
return ReadResponseModel(
imageID: json['content']['image_id'] as String ,
imgUrl: json['content']['image_url'] as String ,
retVal: json['content']["returned_value"] as String,
alarm: json['content']['alarm'] as bool ,
account: json['content']['account'] as String,
createAt: json['content']['create_at'] as String,
location: json['content']['location'] as String,
);
}
}
Method 2:
This one will give me the following error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: type '(dynamic) => Content' is not a subtype of type '(dynamic) => String' of 'f' -- I dont even know where that f came from.
class ReadResponseModel {
List<String> content;
ReadResponseModel({this.content});
factory ReadResponseModel.fromJson(Map<String, dynamic> json) {
return ReadResponseModel(
content: json['content'] != null
? json['content']
.map<String>((json) => Content.fromJson(json))
.toList()
: null,
);
}
}
class Content {
final String imageID;
final String imgUrl;
final String retVal;
final String alarm;
final String account;
final String createAt;
final String location;
final String error;
Content({this.imageID,
this.imgUrl,
this.retVal,
this.alarm,
this.account,
this.createAt,
this.location,
this.error});
factory Content.fromJson(Map<String, dynamic> json) =>
Content(
imageID: json['image_id'],
imgUrl: json['s3_url'],
retVal: json['predict'],
alarm: json['alarm'],
account: json['account'],
createAt: json['create_at'],
location: json['location'],
);
}
The following code is just what I'm doing to connect all this to my widget:
APIService readService = new APIService();
readRequestModel.companyID = "123";
readService.readData(readRequestModel).then((value) async {
if (value != null) {
setState(() {
isApiCallProcess = false;
});
///Trying to call the fetched data and show it in the console:
print("Account: ${value.account}");
print("Returned Value: ${value.retVal}");
print("Image ID: ${value.imgUrl}");
}
I'm not entirely sure why I am getting these errors, and for method 2 I don't even know where that "f" came from. If anyone could shed some light on the subject it would be greatly appreciated.
You can copy paste run full code below
Step 1: Use List<Content> content; not List<String>
Step 2: Use List<Content>.from(json["content"].map((x) => Content.fromJson(x)))
Step 3: In sample JSON's image_url not equal model's s3_url, you need to modify to correct one
code snippet
class ReadResponseModel {
List<Content> content;
ReadResponseModel({this.content});
factory ReadResponseModel.fromJson(Map<String, dynamic> json) {
return ReadResponseModel(
content: json['content'] != null
? List<Content>.from(json["content"].map((x) => Content.fromJson(x)))
: null,
);
}
}
...
dynamic resBody = json.decode(jsonString);
ReadResponseModel model = ReadResponseModel.fromJson(resBody);
print(model.content[0].account);
output
I/flutter ( 4426): test#email.com
full code
import 'package:flutter/material.dart';
import 'dart:convert';
class ReadResponseModel {
List<Content> content;
ReadResponseModel({this.content});
factory ReadResponseModel.fromJson(Map<String, dynamic> json) {
return ReadResponseModel(
content: json['content'] != null
? List<Content>.from(json["content"].map((x) => Content.fromJson(x)))
: null,
);
}
}
class Content {
final String imageID;
final String imgUrl;
final String retVal;
final String alarm;
final String account;
final String createAt;
final String location;
final String error;
Content(
{this.imageID,
this.imgUrl,
this.retVal,
this.alarm,
this.account,
this.createAt,
this.location,
this.error});
factory Content.fromJson(Map<String, dynamic> json) => Content(
imageID: json['image_id'],
imgUrl: json['s3_url'],
retVal: json['predict'],
alarm: json['alarm'],
account: json['account'],
createAt: json['create_at'],
location: json['location'],
);
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
String jsonString = '''
{"status":200,
"content":[{"image_id":"151",
"image_url":"https:\\\/imageurl.jpg",
"returned_value":"14.0",
"alarm":"false",
"account":"test#email.com",
"create_at":"2020-11-17 07:13:42",
"location":"NY"
}]
}
''';
dynamic resBody = json.decode(jsonString);
ReadResponseModel model = ReadResponseModel.fromJson(resBody);
print(model.content[0].account);
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
From the above mentioned code I have created a sample example for you, basically you are messing up with the mode class.Take a look at the example below.
Json you provided:
{"status":200,
"content":[{"image_id":"151",
"image_url":"https:\\\/imageurl.jpg",
"returned_value":"14.0",
"alarm":"false",
"account":"test#email.com",
"create_at":"2020-11-17 07:13:42",
"location":"NY"
}]
}
Based on the json the model class below :
// To parse this JSON data, do
//
// final readResponseModel = readResponseModelFromJson(jsonString);
import 'dart:convert';
ReadResponseModel readResponseModelFromJson(String str) => ReadResponseModel.fromJson(json.decode(str));
String readResponseModelToJson(ReadResponseModel data) => json.encode(data.toJson());
class ReadResponseModel {
ReadResponseModel({
this.status,
this.content,
});
int status;
List<Content> content;
factory ReadResponseModel.fromJson(Map<String, dynamic> json) => ReadResponseModel(
status: json["status"],
content: List<Content>.from(json["content"].map((x) => Content.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"status": status,
"content": List<dynamic>.from(content.map((x) => x.toJson())),
};
}
class Content {
Content({
this.imageId,
this.imageUrl,
this.returnedValue,
this.alarm,
this.account,
this.createAt,
this.location,
});
String imageId;
String imageUrl;
String returnedValue;
String alarm;
String account;
DateTime createAt;
String location;
factory Content.fromJson(Map<String, dynamic> json) => Content(
imageId: json["image_id"],
imageUrl: json["image_url"],
returnedValue: json["returned_value"],
alarm: json["alarm"],
account: json["account"],
createAt: DateTime.parse(json["create_at"]),
location: json["location"],
);
Map<String, dynamic> toJson() => {
"image_id": imageId,
"image_url": imageUrl,
"returned_value": returnedValue,
"alarm": alarm,
"account": account,
"create_at": createAt.toIso8601String(),
"location": location,
};
}
And them main class for fetching the data and showing it in the listview.
import 'package:flutter/material.dart';
import 'package:json_parsing_example/model2.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SampleApp(),
debugShowCheckedModeBanner: false,
);
}
}
class SampleApp extends StatefulWidget {
#override
_SampleAppState createState() => _SampleAppState();
}
class _SampleAppState extends State<SampleApp> {
bool _isLoading = false;
List<Content> list = List();
fetchData() async {
setState(() {
_isLoading = true;
});
String data =
await DefaultAssetBundle.of(context).loadString("json/parse.json");
// This is the above where you get the remote data
// Like var response = await get or post
final readResponseModel = readResponseModelFromJson(data);
list = readResponseModel.content;
setState(() {
_isLoading = false;
});
}
#override
void initState() {
super.initState();
fetchData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Your heading'),
),
body: Container(
child: _isLoading
? Center(child: CircularProgressIndicator())
: Column(
children: <Widget>[
ListView.builder(
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: <Widget>[
Text('${list[index].account}'),
Text('${list[index].location}')
],
),
);
})
],
)));
}
}
Let me know if it works
Can you try setting returned_value and image_id as int instead of string and give it a try ?
I am returning data from MySQL in JSON using this piece of code
while($row = mysqli_fetch_assoc($queryResult)) {
$resultArray[]=$row;
}
echo json_encode($resultArray);
The result is in this format
[{
"reg_number": "FA16-BCS-106",
"teacher_id": "1",
"qr_code": "jamshaid",
"course_name": "COURSE 1"
}, {
"reg_number": "FA16-BCS-106",
"teacher_id": "EMP_FA10_10",
"qr_code": "jamoo",
"course_name": "COURSE 2"
}]
I am decoding the response and storing it in a list using this method which is working fine.
class Student {
final String reg_number;
final String teacher_id;
final String qr_code;
final String course_name;
Student({this.reg_number, this.teacher_id, this.qr_code, this.course_name});
factory Student.fromJson(Map<String, dynamic> json) {
return Student(
reg_number: json['reg_number'],
teacher_id: json['teacher_id'],
qr_code: json['qr_code'],
course_name: json['course_name'],
);
}
}
final parsed =
json.decode(jsonResponse.body).cast<Map<String, dynamic>>();
List<Student> st =
parsed.map<Student>((json) => Student.fromJson(json)).toList();
I am trying to store this List of objects of Student class in SharedPreference using version ^0.5.6. There is no direct method available for this. I've tried using this method but having the following error.
Unhandled Exception: type 'List' is not a subtype of type 'Map'
jsonResponse.body is supposed to be a string but it is reading it as List<dynamic>. Why is that happening? Am I doing anything wrong while parsing the result? Thanks
Here is a simple example created for you to understand how to do this. This is ok for small list but if you have a large list, I dont recommend this because of we are doing too much stuff here.
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Todo {
final String title;
final String description;
Todo(this.title, this.description);
Todo.fromJson(Map<String, dynamic> map) :
title = map["title"],
description = map["description"];
Map<String, dynamic> toMap() => {
"title": title,
"description": description
};
}
void main() {
runApp(MaterialApp(
title: 'Passing Data',
home: HomePage(
todos: List.generate(
20, (i) => Todo(
'Todo $i',
'A description of what needs to be done for Todo $i',
),
),
),
));
}
class HomePage extends StatelessWidget {
final List<Todo> todos;
HomePage({this.todos}) {
saveTodos();
}
void saveTodos() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> values = todos.map((item) => json.encode(item.toMap())).toList();
prefs.setStringList("todos", values);
}
#override
Widget build(BuildContext context) {
return TodosScreen();
}
}
class TodosScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _StateTodosScreen();
}
}
class _StateTodosScreen extends State<TodosScreen> {
Future<List<Todo>> getTodos() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> values = prefs.getStringList("todos");
return values.map((item) => Todo.fromJson(json.decode(item))).toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todos'),
),
body: FutureBuilder(
future: getTodos(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data[index].title),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(todo: snapshot.data[index]),
),
);
},
);
},
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}
class DetailScreen extends StatelessWidget {
final Todo todo;
DetailScreen({Key key, #required this.todo}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(todo.title),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Text(todo.description),
),
);
}
}
But you can simply encode your complete json and store, there will not be much work then, but if it is a complex json you have to handle that also.
I'd like to be able to return my profileList to my ListView in alphabetical order.
I have my "All people" class which has a ListView widget using the json and creating a list of people.
The code below is from my All People class where I'm fetching the json.
class AllPeople extends StatefulWidget {
final String title;
AllPeople(this.title);
#override
AllPeopleState createState() => AllPeopleState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Listviews"),
),
);
}
class AllPeopleState extends State<AllPeople> {
List data;
List<Profile> profiles;
Future<String> getData() async {
var response = await http.get(
Uri.encodeFull("http://test.mallcomm.co.uk/json_feeds/users.json"),
headers: {"Accept": "application/json"});
fetchPeople().then((List<Profile> p) {
this.setState(() {
data = json.decode(response.body);
profiles = p;
});
});
return "Success!";
}
#override
void initState() {
this.getData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('CMS Users'),
),
body: ListView.builder(
padding: EdgeInsets.only(top: 20.0, left: 4.0),
itemExtent: 70.0,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 10.0,
child: InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new PeopleDetails("Profile Page", profiles[index]),
));
},
child: ListTile(
leading: CircleAvatar(
child: Text(profiles[index].getInitials()),
backgroundColor: Colors.deepPurple,
radius: 30.0,
),
title: Text(
data[index]["firstname"] + "." + data[index]["lastname"]),
subtitle: Text(
data[index]["email"] + "\n" + data[index]["phonenumber"]),
),
),
);
}),
);
}
}
Future<List<Profile>> fetchPeople() async {
try {
http.Response response =
await http.get('http://test.mallcomm.co.uk/json_feeds/users.json');
List<dynamic> responseJson = json.decode(response.body);
List<Profile> profileList =
responseJson.map((d) => new Profile.fromJson(d)).toList();
profileList.sort((a, b) {
return a.lastName.toLowerCase().compareTo(b.lastName.toLowerCase());
});
return profileList;
} catch (e) {
print(e.toString());
}
return null;
}
I then have my "User profile" class which is storing my json Profile
class Profile {
final String firstName;
final String lastName;
final String phoneNumber;
final String userEmail;
bool verifiedValue = false;
bool approvedValue = false;
bool securityApprovedValue = false;
bool blockedValue = false;
Profile({this.firstName, this.lastName, this.phoneNumber, this.userEmail});
factory Profile.fromJson(Map<String, dynamic> json) {
return new Profile(
firstName: json["firstname"],
lastName: json["lastname"],
phoneNumber: json["phonenumber"],
userEmail: json["email"],
);
}
I've tried to do something like
profileList.sort((a,b) {
return a.lastName.toLowerCase().compareTo(b.lastName.toLowerCase());
});
just before I return profileList but it didn't work. I've tried looking at some different examples but If i'm honest I don't understand it too well.
The sort function you suggested does seem to work as you'd expect (but, of course, only compares last name - you might want to compare first name if the last names are equal). I tidied up a bit, to produce this working example:
import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;
main() async {
fetchPeople().then((list) {
list.forEach(print);
});
}
Future<List<Profile>> fetchPeople() async {
try {
http.Response response =
await http.get('http://test.mallcomm.co.uk/json_feeds/users.json');
List<dynamic> responseJson = json.decode(response.body);
List<Profile> profileList =
responseJson.map((d) => new Profile.fromJson(d)).toList();
profileList.sort((a, b) {
return a.lastName.toLowerCase().compareTo(b.lastName.toLowerCase());
});
return profileList;
} catch (e) {
print(e.toString());
}
}
class Profile {
final String firstName;
final String lastName;
final String phoneNumber;
final String userEmail;
bool verifiedValue = false;
bool approvedValue = false;
bool securityApprovedValue = false;
bool blockedValue = false;
Profile({this.firstName, this.lastName, this.phoneNumber, this.userEmail});
factory Profile.fromJson(Map<String, dynamic> json) {
return new Profile(
firstName: json["firstname"],
lastName: json["lastname"],
phoneNumber: json["phonenumber"],
userEmail: json["email"],
);
}
#override
String toString() {
return 'Profile: $firstName $lastName';
}
}
Here's a State example that works.
class _MyHomePageState extends State<MyHomePage> {
List<Profile> profiles = [];
#override
void initState() {
super.initState();
_refresh();
}
void _refresh() {
fetchPeople().then((list) {
setState(() {
profiles = list;
});
});
}
Future<List<Profile>> fetchPeople() async {
try {
http.Response response =
await http.get('http://test.mallcomm.co.uk/json_feeds/users.json');
List<dynamic> responseJson = json.decode(response.body);
List<Profile> profileList =
responseJson.map((d) => new Profile.fromJson(d)).toList();
profileList.sort((a, b) {
return a.lastName.toLowerCase().compareTo(b.lastName.toLowerCase());
});
return profileList;
} catch (e) {
print(e.toString());
return [];
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new ListView.builder(
itemBuilder: (context, i) => new Text('${profiles[i].firstName} ${profiles[i].lastName}'),
itemCount: profiles.length,
),
);
}
}