How to access array inside array in flutter - json

Here i got some list of array
{
"id": 1,
"username": "dragonknight",
"password": "123",
"email": "dragon#mail.com",
"nama_lengkap": "Dragon Knight",
"createdAt": "2022-04-13T05:50:00.559Z",
"updatedAt": "2022-04-13T05:50:00.559Z",
"grupId": 1,
"grup": {
"id": 1,
"nama_grup": "fleetime",
"deskripsi": "Ini deskripsi",
"createdAt": "2022-04-13T05:53:18.423Z",
"updatedAt": "2022-04-13T05:53:18.423Z"
}
},
the problem is i want to enter grup array and enter nama_grup in flutter how do i do that. i tried with username and nama_lengkap and data show up correctly. but with grup it shows as null.
home.dart
https://pastebin.com/raw/F3Ha8vKK

You need to separate grup from object then access it. Wait for shared instance loaded then find for user string, if found do the json decode. Here is the working example:
class _DashboardState extends State<Dashboard> {
final Future<SharedPreferences> localStorage = SharedPreferences.getInstance();
String nama_grup = '';
#override
void initState() async {
super.initState();
// wait for SharedPreferences instance
final prefs = await localStorage;
// find user string from SharedPreferences
final String? user = prefs.getString('user');
var userGrup = [];
if (user != null) {
// decode json string if found
var userDecoded = json.decode(user);
setState(() {
userGrup.add(userDecoded['grup']);
nama_grup = userGrup[0]['nama_grup'];
});
}
}
...

Related

How can I update/add new information to my local JSOn file in Flutter? (without creating any classes)

I made a small application, sort of like a library app where you can add books you've read. So, I have a local JSON file, which looks like this:
[
{
"name": "Harry Potter and the Deathly Hallows",
"author": "J.K. Rowling",
"rating": "4.5",
"category": "Fantasy",
"url": "some url"
},
{
"name": "For Whom The Bell Tolls",
"author": "E. Hemingway",
"rating": "4",
"category": "Novel",
"url": "some url#2"
}
]
In my main.dart file I have a function that reads my JSON file, decodes and loads it in a list named "data":
readData(){
DefaultAssetBundle.of(context).loadString("json/books.json").then((s){
setState(() {
data = json.decode(s);
});
});
}
#override
void initState() {
super.initState();
readData();
}
I can easily add new books to "data" and everything is fine except for one thing, - I don't know how to update/write information to JSON, so the app could show me the updated list with the new book after a restart. I've added. How do I do this? And what should I write into the JSON file, - the updated List with all books or just a Map with a new book?
Answer to NelsonThiago
This code is in "class AddingPageState extends State":
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/books.json');
}
Future<File> writeData(List list) async { // "list" is the updated book-list
final file = await _localFile;
String encodedData = jsonEncode(list);
return file.writeAsString('$encodedData');
}
And I call "writeData" in onPressed function.
It would be better to make this using a local NoSql database like sembast, this way you could add, delete and update your data. But as you are already working with json, You just need to encode your new changed data to json and write to the file again.
To write and read files, instead of using rootBundle read this read and write files.
As I can see from your JSON file, you are storing the Books as a list of JSON objects, which will make things easier.
But your request of solving this without adding new classes is a bit strange because adding a Book class in your case would make things much easier.
So I am going to give you a solution that assumes that you create a new Book class.
Start by reading the file as you are currently doing.
Store the content of the file in a List of dynamic List.
Iterate through the list using the map function, add using the from JSON function in the Book class decode the JSON to a book object, then apply the toList() function on that map.
Return the result to your UI and treat it as any other list.
When you want to add a new Book, create a new object of the book class and add it to your list.
When the user finishes adding, transform the list to a JSON object agian and store it in the file again;
Something like this:
The Book Class:
class Book {
String? name;
String? author;
String? rating;
String? category;
String? url;
Book({
required this.name,
required this.author,
required this.rating,
required this.category,
required this.url,
});
Book.fromJson(Map<String, dynamic> json) {
name = json['name'];
author = json['author'];
rating = json['rating'];
category = json['category'];
url = json['url'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['author'] = this.author;
data['rating'] = this.rating;
data['category'] = this.category;
data['url'] = this.url;
return data;
}
#override
String toString() {
return 'Book(name: $name, author: $author, rating: $rating, category: $category, url: $url)';
}
}
And main function
void main() {
/// read the file the way you like
List<dynamic> list = [
{
"name": "Harry Potter and the Deathly Hallows",
"author": "J.K. Rowling",
"rating": "4.5",
"category": "Fantasy",
"url": "some url"
},
{
"name": "For Whom The Bell Tolls",
"author": "E. Hemingway",
"rating": "4",
"category": "Novel",
"url": "some url#2"
}
];
List<Book> books = list
.map(
(jsonObject) => Book.fromJson(jsonObject),
)
.toList();
print(books);
Book newBook = Book(
name: 'Some Book',
author: 'Some Author',
rating: 'Some rating',
category: 'Some category',
url: 'Some Url');
books.add(newBook);
print(books);
books
.map(
(book) => book.toJson(),
)
.toList();
//Write the the file again to storage or anywhere else
}
See the following example. But it requires to create a class. The sample json file is like below (pretty much similar to your json file) -
[
{"name":"Ash","age":"22","hobby":"golf"},
{"name":"philip","age":"17","hobby":"fishing"},
{"name":"charles","age":"32","hobby":"drawing"},
]
And I am editing the above code answered by Ward Suleiman so that you can read from a local json file and write to it-
import 'dart:io';
import 'dart:convert';
List<Player> players = [];
void main() async{
print("hello world");
final File file = File('D:/Sadi/.../test.json'); //load the json file
await readPlayerData(file); //read data from json file
Player newPlayer = Player( //add a new item to data list
'Samy Brook',
'31',
'cooking'
);
players.add(newPlayer);
print(players.length);
players //convert list data to json
.map(
(player) => player.toJson(),
)
.toList();
file.writeAsStringSync(json.encode(players)); //write (the whole list) to json file
}
Future<void> readPlayerData (File file) async {
String contents = await file.readAsString();
var jsonResponse = jsonDecode(contents);
for(var p in jsonResponse){
Player player = Player(p['name'],p['age'],p['hobby']);
players.add(player);
}
}
And the Player class -
class Player {
late String name;
late String age;
late String hobby;
Player(
this.name,
this.age,
this.hobby,
);
Player.fromJson(Map<String, dynamic> json) {
name = json['name'];
age = json['age'];
hobby = json['hobby'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['age'] = this.age;
data['hobby'] = this.hobby;
return data;
}
}

Assign value to a variable from list object converted from JSON in Flutter

I'm really new to flutter. I tried searching for this question and although I have found a solution but not all my problems are solved, as most of it just use return.
I have a JSON that i get from API calling here:
{
"error": false,
"message": "LOGIN_SUCCESS",
"user": {
"id": 1219,
"email": "john#example.com"
"name": "John Doe",
"category": 1,
"branch": 1004,
"lastlogin": "2020-12-04 03:12:43"
}
}
I already create the class for user as below
class User {
int id;
String name;
String email;
String category;
String branch;
String lastLogin;
User({
this.id,
this.name,
this.email,
this.category,
this.branch,
this.lastLogin
});
factory User.fromJson(Map<String, dynamic> datauser){
return User(
id: datauser['id'],
name: datauser['name'],
email: datauser['email'],
category: datauser['category'],
branch: datauser['branch'],
lastLogin: datauser['lastlogin']
);
}
}
and a result class as below..
class Result {
String message;
User user;
Result({
this.message,
this.user
});
factory Result.fromJson(Map<String, dynamic> resultData){
return Result(
message: resultData['message'],
user: User.fromJson(resultData['user'])
);
}
}
now here comes my problem as i don't know how to move forward from this point
login() async {
List<User> users;
final response = await http.post("myUrlWithAPIcalls",
body: {"email": email, "password": password});
final data = jsonDecode(response.body);
var rest = data['user'] as List;
users = rest.map<User>((json) => User.fromJson(json)).toList();
}
so the question is, how can i assign the value i get from the JSON that has converted into list into a variable?
now in example if it was only a simple JSON object, i could do it like this..
final data = jsonDecode(response.body);
int id = data['id'];
String name = data['name'];
String email = data['email'];
String category = data['category'];
String branch = data['branch'];
but how can i do that in a list object?
as of anyone was wondering why do i do like this, i was trying to save the data into a sharedpref class that i copied from someone else code.
Shared preferences are not meant to store objects. Use something like sqflite to persist objects (official cookbook here).
I don't understand why your JSON shows one user's data, but the login() function seems to decode a list of users.
I'm guessing that's what you want :
login() async {
final response = await http.post("myUrlWithAPIcalls",
body: {"email": email, "password": password});
final data = jsonDecode(response.body);
var user = User.fromJson(data['user']); // the variable you want
}
You don't say where that login() function is, or what you want to do with that User object. FYI, an essential part of Flutter is state management.

How to decode large json array in flutter

I have a rather large json file that I have downloaded using my flutter app from a web api that's around 200MB using
final response = Dio().get(uri, options: Options(responseType: ResponseType.plain));
(Using default Dio options also uses json decoding, resulting in an out of memory exception.
This is not directly part of my problem but maybe it helps)
Now the problem starts after obtaining the json string.
When I use jsonDecode on the response body I run out of memory. (maybe the same function Dio uses?)
final data = jsonDecode(response.body); this runs out of memory
The json object itself is an array with a lot of items with a format like this:
[
{"data": {independent data1}},
{"data": {independent data2}},
...
]
and i would be fine just decoding one item at a time instead of everything at once to reduce memory usage. Is there another way to do process all the items in this array? Something like
jsonArrayDecode(response.body, onItemDecode: (item) { /*do stuff with item */ });
Or do I have to write my own json reader that can sequentially decode it?
Thanks to #pskink, I managed to solve my problem. I used the ResponseType.stream from Dio to get stream which can be processed using the reviver function argument from the JsonDecoder. I process all the data in the reviver and ignore the data in the onData function of the listener.
...
final response = await dio.get(uri,
options: Options(responseType: ResponseType.stream);
Function reviver = (key, value) {
if (/*value is element from top level list*/) {
processItem(value);
return null;
}
return value;
}
final completer = Completer();
response.data.stream.cast<List<int>>()
.transform(utf8.decoder)
.transform(JsonDecoder(reviver))
.listen(null, onDone: () { completer.complete(); });
await completer.future;
...
If the problem is really that the data file is very large, then the problem can be solved by not storing unnecessary objects during parsing.
This will only make sense if not all of the data is needed, but only some of the data.
In this case, we are talking about filtering data on the fly, that is, directly during the data parsing process.
Below is a small example of how this can be implemented.
import 'package:fast_json/fast_json_selector.dart' as parser;
import 'package:fast_json/fast_json_selector.dart' show JsonSelectorEvent;
void main(List<String> args) {
// Select users from the list by indexes [2..3] and terminate selection
final users = <User>[];
final level = '{} data [] 0 {}'.split(' ').length;
final elementLevel = '{} data [] 0'.split(' ').length;
void select(JsonSelectorEvent event) {
final levels = event.levels;
if (levels.length == level) {
final index = event.levels[elementLevel - 1] as int;
if (index >= 2 && index <= 3) {
final map = event.lastValue as Map;
final user = User.fromJson(map);
users.add(user);
}
// Free up memory
event.lastValue = null;
if (users.length == 2) {
throw const _TerminateException();
}
}
}
try {
parser.parse(_data, select: select);
} on _TerminateException {
//
}
print(users.join(', '));
}
const _data = '''
{
"success":true,
"data":[
{
"id":1,
"name":"Leanne Graham",
"username":"Bret",
"email":"Sincere#april.biz",
"address":{
"street":"Kulas Light",
"suite":"Apt. 556",
"city":"Gwenborough",
"zipcode":"92998-3874",
"geo":{
"lat":"-37.3159",
"lng":"81.1496"
}
},
"phone":"1-770-736-8031 x56442",
"website":"hildegard.org",
"company":{
"name":"Romaguera-Crona",
"catchPhrase":"Multi-layered client-server neural-net",
"bs":"harness real-time e-markets"
}
},
{
"id":2,
"name":"Ervin Howell",
"username":"Antonette",
"email":"Shanna#melissa.tv",
"address":{
"street":"Victor Plains",
"suite":"Suite 879",
"city":"Wisokyburgh",
"zipcode":"90566-7771",
"geo":{
"lat":"-43.9509",
"lng":"-34.4618"
}
},
"phone":"010-692-6593 x09125",
"website":"anastasia.net",
"company":{
"name":"Deckow-Crist",
"catchPhrase":"Proactive didactic contingency",
"bs":"synergize scalable supply-chains"
}
},
{
"id":3,
"name":"Clementine Bauch",
"username":"Samantha",
"email":"Nathan#yesenia.net",
"address":{
"street":"Douglas Extension",
"suite":"Suite 847",
"city":"McKenziehaven",
"zipcode":"59590-4157",
"geo":{
"lat":"-68.6102",
"lng":"-47.0653"
}
},
"phone":"1-463-123-4447",
"website":"ramiro.info",
"company":{
"name":"Romaguera-Jacobson",
"catchPhrase":"Face to face bifurcated interface",
"bs":"e-enable strategic applications"
}
},
{
"id":4,
"name":"Patricia Lebsack",
"username":"Karianne",
"email":"Julianne.OConner#kory.org",
"address":{
"street":"Hoeger Mall",
"suite":"Apt. 692",
"city":"South Elvis",
"zipcode":"53919-4257",
"geo":{
"lat":"29.4572",
"lng":"-164.2990"
}
},
"phone":"493-170-9623 x156",
"website":"kale.biz",
"company":{
"name":"Robel-Corkery",
"catchPhrase":"Multi-tiered zero tolerance productivity",
"bs":"transition cutting-edge web services"
}
},
{
"id":5,
"name":"Chelsey Dietrich",
"username":"Kamren",
"email":"Lucio_Hettinger#annie.ca",
"address":{
"street":"Skiles Walks",
"suite":"Suite 351",
"city":"Roscoeview",
"zipcode":"33263",
"geo":{
"lat":"-31.8129",
"lng":"62.5342"
}
},
"phone":"(254)954-1289",
"website":"demarco.info",
"company":{
"name":"Keebler LLC",
"catchPhrase":"User-centric fault-tolerant solution",
"bs":"revolutionize end-to-end systems"
}
}
]
}''';
class Company {
final String name;
Company({required this.name});
#override
String toString() {
return name;
}
static Company fromJson(Map json) {
return Company(
name: json['name'] as String,
);
}
}
class User {
final String city;
final int id;
final String name;
User({required this.city, required this.id, required this.name});
#override
String toString() {
return '$id:$name from $city';
}
static User fromJson(Map json) {
return User(
city: json['address']['city'] as String,
id: json['id'] as int,
name: json['name'] as String,
);
}
}
class _TerminateException {
const _TerminateException();
}

Unable to load JSON data to show in ListView

I need to get the json array data in flutter app by providing the get method.
The problem that I am facing is that I am not able to put the records in the empty list carList.
but I am getting the array of objects as shown below(POSTMAN) by
print(json.decode(response.body)) // in the file cars.dart
Hence if you could please help me on how to get the response in the List carlist = [];
Car_list.dart file calls the method for the get request.
Please let me know if you require any further information from my end.
Thankyou
POSTMAN
[
{
"id": "1",
"carModel" : "Maruti swift",
"carDescription" : "The car has a top speed of 180 km/hr"
},
{
"id": "1",
"carModel" : "Hyundai santro",
"carDescription" : "The car has a top speed of 150 km/hr"
},
{
"id": "1",
"carModel" : "Hyundai creta",
"carDescription" : "The car has a top speed of 160 km/hr"
}
]
CarsModel.dart
class Cars with ChangeNotifier{
String userId;
String carModel
String carDescription;
Cars(
{
this.userId = '1111',
this.carModel,
this.carDescription,
}
);
factory Cars.fromJSON(Map<String,dynamic> json) => Cars(
userId : json['userId'],
carModel : json['CarModel'],
carDescription : json['carDescription'],
);
toJSON() {
return {
'userId':'111',
'carModel':carModel,
'carDescription' : carDescription
};
}
cars.dart
class CarProvider with ChangeNotifier{
List<Cars> carlist = [
//Sample data to show the format in which the data needs to be shown as the listview gets populated from below records which we are supposed to get from postman
//Cars (
// userid: 1111,
// carModel: 'Maruti Alto',
// carDescription: 'Top speed 140 km/hr'
),
];
Future<void> readListofCars(int id) async {
print(id.toString());
const url = 'http://localhost/userlist';
// {'id': id.toString()
Map<String, String> headers = {
"Content-type": "application/json"};
try
{
final response = await http.get(url,headers: headers);
List<dynamic> bodyCars = jsonDecode(response.body);
List<Cars> loadedCars = bodyCars.map((dynamic item) => new Cars.fromJSON(item)).toList();
/*
for (Map i in bodyCars) {
_notificationitems.add(Cars.fromJSON(i));
}
*/
});
print(response.statusCode);
carlist = loadedCars;
print(json.decode(response.body));
notifyListeners();
}catch (error){
throw error;
}
}
Car_list.dart
class TabScreenCar extends StatefulWidget {
final String userId;
TabScreenCar(this.userId);
#override
_TabScreenCarState createState() => _TabScreenCarState();
}
class _TabScreenCarState extends State<TabScreenCar> {
#override
void didChangeDependencies() {
final id = 1111;
Provider.of<CarProvider>(context).readListofCars(id);
super.didChangeDependencies();
}
In your model class you have incorrect variable to fetch the json data
to make the process simple you can have a look at this link
https://stackoverflow.com/a/58708634/9236994
just paste your json response in https://javiercbk.github.io/json_to_dart/
and use the json model class which will be generated.
your issue will be resolved.
variable which you are using doesn't match with your json response
OR to keep it simple
use below mentioned fromJSON method
factory Cars.fromJSON(Map<String,dynamic> json) => Cars(
userId : json['id'],
carModel : json['carModel'],
carDescription : json['carDescription'],
);
EDIT
I think you are facing issue with setting up the data in your list variable too.
use below shown code to fill the response into list if cars data
List<Cars> loadedCars = List<Cars>();
var data = jsonDecode(response.body);
data.forEach((val) {
loadedCars.add(Cars.fromJSON(val));
}

Flutter json decode returns null

I'm getting a null return when I run the following code. Apparently I'm not accessing json correctly.
Is there another way to access json data? Or is it ok to use it like that?
Future Class - parsing json from a url
Future<List<User>> _getUsers() async {
var data = await http.get("https://...api.php");
if (data.statusCode == 200) {
print('Status Code 200: Ok!');
var jsonData = json.decode(data.body);
List<User> users = [];
for (var u in jsonData[0]) {
print(u[0]["title"]);
User user = User(u["id"], u["source"], u["desc"], u["link"], u["title"]);
users.add(user);
}
print(users.length);
return users;
} else {
throw Exception('Failed to load json');
}
}
Class
class User {
final int id;
final String source;
final String desc;
final String link;
final String title;
User(this.id, this.source, this.desc, this.link, this.title);
}
Basic json structure:
{
"0":{
"id":0,
"source":"XXX",
"link":"XXXX",
"title":"XXXX",
"desc":"XXXX"
},
"1":{
"id":1,
"source":"XXX",
"link":"XXXX",
"title":"XXXX",
"desc":"XXXX"
}
}
What am missing here? thanks.
You're trying to use something that isn't a list as a list. The json structure you've provided looks like part of an object and not a list.
A list would look like this:
[{
"id": 0,
"source": "XXX",
"link": "XXXX",
"title": "XXXX",
"desc": "XXXX"
}]
But since the underlying structure is a Map you could iterate over the keys, doing something like this:
for (var k in jsonData.keys) {
var u = jsonData[k];
print(u["title"]);
User user = User(u["id"], u["source"], u["desc"], u["link"], u["title"]);
}
Your json structure is not a real json. But if your json is like this:
{
"0":{
"id":0,
"source":"XXX",
"link":"XXXX",
"title":"XXXX",
"desc":"XXXX"
},
"1":{
"id":1,
"source":"XXX",
"link":"XXXX",
"title":"XXXX",
"desc":"XXXX"
}
}
You can get data like this:
for (int i = 0; i < length; i ++) {
User user = User(u["$i"]["id"], u["$i"]["source"], u["$i"]["desc"], u["$i"]["link"], u["$i"]["title"]);
users.add(user);
}