I tried to display the output of this data into a list but it can't
this is my data output
{activity: {"project":" Distributions","code":2000,"code_name":"OpenProcessSnapshot","activity":{"id_process_snapshot":988,"name":"Android Process"}}, created_at: 2019-06-20 08:58:48.492885+07, id: 1, id_user: 1}
{activity: {"project":"Distributions","code":2000,"code_name":"OpenProcessSnapshot","activity":{"id_process_snapshot":988,"name":"Android Process"}}, created_at: 2019-06-20 08:58:48.492885+07, id: 1, id_user: 1}
{activity: {"project":" Distributions","code":2000,"code_name":"OpenProcessSnapshot","activity":{"id_process_snapshot":988,"name":"Android Process"}}, created_at: 2019-06-20 08:58:48.492885+07, id: 1, id_user: 1}
and this is my code
FutureBuilder(
future: UserController.getActivity(_selectedUser),
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data.toString());
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data.toString()),
],
);
} else {
return Center(
child: Text("No data displayed"),
);
}
return Center(
child: CircularProgressIndicator(),
);
},
),
what if I want to display created_at and project?
You can use jsonDecode to get that specific element.
Documentation Link
For your case you have to create a new widget function and return it:
//put this method before your widget build function
Widget _mapJsonDataToText(String data){
Map<String, List<dynamic>> jsonData = jsonDecode(data);
Map<String, dynamic> jsonDataInner = jsonDecode(jsonData['activity']);
return Text(jsonDataInner['created_at']);
//do the same for project
}
children: <Widget>[
//gets the method that returns the text widget
_mapJsonDataToText(snapshot.data.toString()),
],
I have a different method, this will add up the data into the list. Not using future builder, just making use of my common sense to display the data logically into the list.
Assuming you know about http of flutter, if you don't then this is the link for you: Fetch data from the internet
Suppose you have a data[], in which activity{} are being displayed in your JSON output.
List<String> project = [];
List<String> createdAt = [];
void initState(){
super.initState();
//this will run this method on call of this page, everytime
this.fetchData();
}
Future<void> fetchData() async{
List<String> _project = [];
List<String> _createdAt = [];
final response =
await http.get('your_api_url');
//looping through the array of activity object
(response['data'] as list).forEach((item){
//check if the data comes correct
print(item['activity']['project']);
print(item['created_at']);
_project.add(item['activity']['project']);
_createdAt.add(item['created_at']);
});
setState((){
this.project = _project;
this.createdAt = _createdAt;
});
}
//In order to show them in the list of project, call ListView()
List<Widget> projectWidget(){
List<Widget> _widget = [];
this.project.forEach((item){
_widget.add(item);
});
return _widget;
}
//In order to show them in the list of createdAt, call ListView()
List<Widget> createdAtWidget(){
List<Widget> _anotherWidget = [];
this.createdAt.forEach((item){
_anotherWidget.add(item);
});
return _anotherWidget;
}
Display the data as you want in your UI. Let me if it works for you. Thanks :)
Related
I have problem with checkbox to add parameter hit to POST data for API.
This is POST data sent when I clicked Save Button :
Map<String, String> params = {
'breed_id': selectedBreedID!,
'gender': _selectedGender!,
'weight': weightTxtCtrl.text,
'date_of_birth': _dateController.text,
pHfirst! : pHlast!
};
final response = await http.post(
Uri.parse(
"http://localhost:8000/api/v1/pet",
),
headers: {'Authorization': 'Bearer $token'},
body: params,
);
}
this is my checkbox code :
String? pHfirst = "";
String? pHlast = "";
List<PetHealthModel> petHealths = [];
List<PetHealthModel>customPets=[];
petHealths.isNotEmpty
? Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: petHealths.map((e) {
var healthsID = customPets.map((e) => e.id).toList();
return CheckboxListTile(
title: Text(e.healthStatus),
value: healthsID.contains(e.id),
onChanged: (bool? value) {
if (value == true) {
setState ((){
customPets.add(e);
for (var element in customPets) {
pHfirst = "pet_healths["+element.id.toString()+"]";
pHlast = ""+element.id.toString()+",";
log(pHfirst!+" : "+pHlast!);
}
});
} else {
setState((){
customPets.remove(e);
for (var element in customPets) {
pHfirst = "pet_healths["+element.id.toString()+"]";
pHlast = ""+element.id.toString()+",";
log(pHfirst!+" : "+pHlast!);
}
});
}
}
);
}).toList(),
),
),
Here's the log that printed :
sample if select 3, 4, 5
sample if select 2 only
From the sample below is I know that my code works, but when I called it in Map<String, String> params it only called the last pet_healths that I selected not print all of that :
This is the result that in debut we can see that 5 data printed, but when it called to Map<String, String> Param it only 1 last data
Being new to flutter, I'm learning and stumbling on the go.
I am trying to pass an array that I have received from json into an already waiting widget structure but can't quite seem to get the connection.
Here's the sample code:
class Products extends StatefulWidget {
#override
_ProductsState createState() => _ProductsState();
}
class _ProductsState extends State<Products> {
#override
void initState() {
_getProducts();
}
Future<List<Single_prod>> _getProducts() async {
var url = "";
var data = await http.get(url);
var jsonData = json.decode(data.body) as Map<String, dynamic>;
//print(jsonData.toString());
//jsonData.forEach((k, v) => print("Key : $k, Value : $v"));
List<Single_prod> items = [];
jsonData.forEach((k, v){
Single_prod item = Single_prod(v["error"], v["id"], v["name"], v["price"], v["image"]);
items.add(item);
});
//print(items.length);
return items; <---Tring to pass this to Widget build but not recognized.....
}
#override
Widget build(BuildContext context) {
return GridView.builder(
itemCount: items.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index){
return Single_prod(
prod_err: items[index]['error'], <--- This items array is not recognized
prod_id: items[index]['id'],
prod_name: items[index]['name'],
prod_price: items[index]['price'],
prod_image: items[index]['image'],
);
});
}
}
The items array is not recognized in the widget
Here is the rest of the code:
class Single_prod extends StatelessWidget {
final prod_err;
final prod_id;
final prod_name;
final prod_price;
final prod_image;
Single_prod({
this.prod_err,
this.prod_id,
this.prod_name,
this.prod_price,
this.prod_image,
});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(
tag: prod_name,
child: Material(
child: InkWell(
onTap: () => Navigator.of(context).push(new MaterialPageRoute(
// here we are passing the values of the products to the details page
builder: (context) => new ProductDetails(
prod_detail_name: prod_name,
prod_detail_image: prod_image,
prod_detail_id: prod_id,
prod_detail_price: prod_price,
))),
child: GridTile(
footer: Container(
height: 40.0,
color: Colors.white70,
child: ListTile(
leading: Text(prod_name, style: TextStyle(fontWeight: FontWeight.bold),),
title: Text(
prod_price,
style: TextStyle(color: Colors.blue, fontWeight: FontWeight.w800, fontSize: 12),
),
/*subtitle: Text(
prod_oldprice,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w800, fontSize: 11, decoration: TextDecoration.lineThrough),
),*/
),
),
child: Image.asset(prod_image,
fit: BoxFit.cover,),
),
),
),
),
);
}
}
How does the upper code connect with the lower code?
Thanks in advance.
First, look at the scope of your 'items' variable: it is defined in getItems() function, and it is not visible outside the function. So, first thing: make it class level property.
Next - your initState will call your method. Method is async, and the way to handle it in initState to use '.then' on the Future returned by your method. What you want to do here is: once the future completes, you want to set your class level variable to hold the value returned by _getProduct() function.
And finally - this is very important to understand: you don't call build method yourself - flutter framework does it for you. Now, flutter does not have a magic way of knowing when you changed the data - it won't observe your code, so you need to tell it somehow that your state object changed, and it requires rebuild. You do it by calling setState() function.
I think you have another issue here actually: you already bulit your Single_prod widget in _getProduct(), no need to build it again. I tried to correct this also.
Try this (I didn't compile it so it might have few errors):
class Products extends StatefulWidget {
#override
_ProductsState createState() => _ProductsState();
}
class _ProductsState extends State<Products> {
List<Single_prod> items = [];
#override
void initState() {
super.initState();
_getProducts().then( (result) {
setState(() {
items=result;
}
});
}
Future<List<Single_prod>> _getProducts() async {
var url = "";
var data = await http.get(url);
var jsonData = json.decode(data.body) as Map<String, dynamic>;
//print(jsonData.toString());
//jsonData.forEach((k, v) => print("Key : $k, Value : $v"));
List<Single_prod> items = [];
jsonData.forEach((k, v){
Single_prod item = Single_prod(v["error"], v["id"], v["name"], v["price"], v["image"]);
items.add(item);
});
//print(items.length);
return items;
}
#override
Widget build(BuildContext context) {
return GridView.builder(
itemCount: items.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index){
return items[index];
});
}
}
I have a problem right now
I need to use StreamBuilder to get all the data from my database and then build every data into a widget with position in it.
Because I use position, I need to use Stack as a parent widget.
But the problem is I can't use ListView builder to loop the snapshot data
Is there any way to loop inside so I can return the widget?
Stack(
children: <Widget>[
Container(
color: Colors.white,
),
StreamBuilder(
// initialData: {'handler': "handler"},
stream: mapPlacementStream.stream,
builder: (context, snapshotPlacement) {
dataPlacement = snapshotPlacement.data;
if(!snapshotPlacement.hasData){
return const Text('Connecting...');
}
else{
return new StreamBuilder(
// initialData: {0: true},
stream: mapStateStream.stream,
builder: (context, snapshotState) {
dataState = snapshotState.data;
if(!snapshotState.hasData){
return const Text('Connecting...');
}
else{
return ParkPainter(
1,
20,
20,
1,
true
);
}
);
}
}
),
],
)
On Else I return the ParkPainter to see if it can print the ParkPainter (the widget with position)
It works
I have a profile screen. and getting data from the cloud store and showing in the profile screen.
I guess there is no problem while retrieving data but the problem is while showing. I don't know how I mess up?
Now the error is only showing "Loading" Text.
Help me
class Profile extends StatefulWidget {
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
bool userFlag = false;
var users;
#override
void initState() {
// TODO: implement initState
super.initState();
UserManagement().getData().then((QuerySnapshot docs){
userFlag = true;
users = docs.documents[0].data;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile'),
),
body: Container(
padding: EdgeInsets.all(50),
child: Column(
children:<Widget>[
name(),
],
),
),
);
}
Widget name() {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
"Name",
style: TextStyle(fontWeight: FontWeight.w600,fontSize: 18),
),
SizedBox(
width: 45,
),
userFlag ? Text(users['Name'],
style: TextStyle(fontWeight: FontWeight.w400,fontSize: 18),
)
:Text('Loading'),
],
),
);
}
for getting Data i have:
getData(){
return Firestore.instance
.collection('users').getDocuments();
}
I get and Use Data that way:
QuerySnapshot Users = await _fs
.collection("users")
.getDocuments();
It will give you all the users in the users collection.
so for retrieving one user in specific I use a "for loop".
String myEmail = "email#gmail.com";
String username;
for (var user in users.documents) {
if ( myEmail == user.data["email"]){
// you have all the field for the user using "myEmail".
username = user.data["username"];
} else {
print("There is no User with this email");
}
}
But I think there might be a better way to do it.
This error is because, You should initialize your user variable like
var users = {}; instead of
var user;
I am going to use a real json. First of all, I should run the project that is written in Flask, then use the local host to achieve data.
Here is the real Json I`m using
{
"devices":[
{
"device_desc":"cooler",
"device_title":"cooler",
"functions":[
{
"device_id":1,
"function_desc":"pomp",
"function_title":"pomp",
"status":1
},
{
"device_id":1,
"function_desc":"less",
"function_title":"less",
"status":1
},
{
"device_id":1,
"function_desc":"up",
"function_title":"up",
"status":1
}
],
"image_path":"fdfdfsf",
"status_id":1,
"statuss":{
"status_desc":"device is on",
"status_title":"on"
}
},
{
"device_desc":"panke",
"device_title":"panke",
"functions":[
{
"device_id":2,
"function_desc":"less",
"function_title":"pomp",
"status":2
},
{
"device_id":2,
"function_desc":"less",
"function_title":"less",
"status":2
}
],
"image_path":"vfx",
"status_id":2,
"statuss":{
"status_desc":"device is off",
"status_title":"off"
}
}
]
}
This is my code:
these are data models for defining json properties:
class Base{
//the type of our object is the array
List<Device> _devices;
Base(this._devices);
List<Device> get devices => _devices;
set devices(List<Device> value) {
_devices = value;
}
}
class Device {
String _device_desc,_device_title,_image_path;
int _status_id;
List<function> _functions;
List<Status> _statuss ;
Device(this._device_desc, this._device_title, this._image_path,
this._status_id, this._functions, this._statuss);
List<Status> get statuss => _statuss;
set statuss(List<Status> value) {
_statuss = value;
}
List<function> get functions => _functions;
set functions(List<function> value) {
_functions = value;
}
int get status_id => _status_id;
set status_id(int value) {
_status_id = value;
}
get image_path => _image_path;
set image_path(value) {
_image_path = value;
}
get device_title => _device_title;
set device_title(value) {
_device_title = value;
}
String get device_desc => _device_desc;
set device_desc(String value) {
_device_desc = value;
}
}
class Status {
String _status_desc, _status_title;
Status(this._status_desc, this._status_title);
get status_title => _status_title;
set status_title(value) {
_status_title = value;
}
String get status_desc => _status_desc;
set status_desc(String value) {
_status_desc = value;
}}
class function {
String _function_desc, _function_title;
int _device_id, _status;
function(this._function_desc, this._function_title, this._device_id,
this._status);
get status => _status;
set status(value) {
_status = value;
}
int get device_id => _device_id;
set device_id(int value) {
_device_id = value;
}
get function_title => _function_title;
set function_title(value) {
_function_title = value;
}
String get function_desc => _function_desc;
set function_desc(String value) {
_function_desc = value;
}}
and this is the stateful class :
class MyHomePage extends StatefulWidget {
var title;
MyHomePage({Key key, this.title}) : super(key: key);
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<Base> _getBase() async {
var data = await http.get(Uri.encodeFull("http://192.168.1.111:5000/mobile-home"));
var jsonData = json.decode(data.body);
Base base = Base(jsonData);
return Base(jsonData[0]);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Container(
child: FutureBuilder(
future: _getBase(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: Text("Loading..."),
),
);
} else {
return ListView.builder(
itemCount: snapshot.data.devices.length,
itemBuilder: (BuildContext context, int index) {
snapshot.data.devices.map<Widget>((devices){
return ListTile(
subtitle: Text(devices[index].device_desc.toString()),
title: Text(devices[index].device_title),
/*leading: CircleAvatar(
// ignore: argument_type_not_assignable
backgroundImage: NetworkImage(snapshot.data[index].thumbnailUrl),
)*/
);
}
);
},
);
}
},
),
),
);
}
}
I got an error when while debugging:
"type 'List<dynamic>' is not a subtype of type 'List<Device>'"
I can not get the data from json.
There was no question in your question, but I assume the question is:
My Json code is not working - How do I efficiently parse and encode complex json objects in my
flutter program.
For complex JSON you may want to consider using code generation to reduce the boiler plate you have to write. The flutter page has a good example using JsonSerializable. Here the basic instructions for your example:
Add dependencies to pubspec.yaml and run flutter pub get in the command line:
dependencies:
json_annotation: ^1.2.0
dev_dependencies:
build_runner: ^1.0.0
json_serializable: ^1.5.1
Create the basic Object model (similar to what you have done). Except for the following differences:
You don't have a List of Status for the field statuss, but a single Status object.
Don't use private fields.
To enable json boiler plate code generation do the following three steps:
add the json-annotations to each class,
add a factory .fromJson method on each class and
add a .toJson method on each class:
#JsonSerializable()
class Base {
List<Device> devices;
Base({this.devices});
factory Base.fromJson(Map<String, dynamic> json) => _$BaseFromJson(json);
Map<String, dynamic> toJson() => _$BaseToJson(this);
}
#JsonSerializable()
class Device {
String device_desc,device_title,image_path;
int status_id;
List<function> functions;
Status statuss ;
Device(this.device_desc, this.device_title, this.image_path,
this.status_id, this.functions, this.statuss);
factory Device.fromJson(Map<String, dynamic> json) => _$DeviceFromJson(json);
Map<String, dynamic> toJson() => _$DeviceToJson(this);
}
#JsonSerializable()
class Status {
String status_desc, status_title;
Status(this.status_desc, this.status_title);
factory Status.fromJson(Map<String, dynamic> json) => _$StatusFromJson(json);
Map<String, dynamic> toJson() => _$StatusToJson(this);
}
#JsonSerializable()
class function {
String function_desc, function_title;
int device_id, status;
function(this.function_desc, this.function_title, this.device_id,
this.status);
factory function.fromJson(Map<String, dynamic> json) => _$functionFromJson(json);
Map<String, dynamic> toJson() => _$functionToJson(this);
}
Run the command line to start code generation in the project root folder:
flutter packages pub run build_runner watch
Now an additional source file appears with your generated boiler plate code. Add this file to your own source file using the part keyword, for example if your source file is main.dart add the following line:
part 'main.g.dart';
And you are done - This is all you need to test your encoding / decoding. For example with the following code:
import 'dart:convert';
void main() => (){
var jsonExample = '{"devices": [{"device_desc": "cooler", "device_title": "cooler", "functions": [{"device_id": 1, "function_desc": "pomp", "function_title": "pomp", "status": 1}, {"device_id": 1, "function_desc": "less", "function_title": "less", "status": 1}, {"device_id": 1, "function_desc": "up", "function_title": "up", "status": 1}], "image_path": "fdfdfsf", "status_id": 1, "statuss": {"status_desc": "device is on", "status_title": "on"}}, {"device_desc": "panke", "device_title": "panke", "functions": [{"device_id": 2, "function_desc": "less", "function_title": "pomp", "status": 2}, {"device_id": 2, "function_desc": "less", "function_title": "less", "status": 2}], "image_path": "vfx", "status_id": 2, "statuss": {"status_desc": "device is off", "status_title": "off"}}]}';
Map base_example = json.decode(jsonExample);
Base base_example_parsed = Base.fromJson(base_example);
var numberDevices = base_example_parsed.devices.length;
var numberFuncs = base_example_parsed.devices[0].functions.length;
print('$base_example_parsed has $numberDevices devices and the first device has $numberFuncs functions');
var base_example_encoded_again = json.encode(base_example_parsed);
print('$base_example_encoded_again');
};
For more information please refer to:
1. the official example.
2. this blog.
There's a very good article about how to parse complex JSON in Flutter. Here's a quick summary...
Simple Stuff:
{
"id":"487349",
"name":"Pooja Bhaumik",
"score" : 1000
}
becomes...
class Student{
String studentId;
String studentName;
int studentScores;
Student({
this.studentId,
this.studentName,
this.studentScores
});
factory Student.fromJson(Map<String, dynamic> parsedJson){
return Student(
studentId: parsedJson['id'],
studentName : parsedJson['name'],
studentScores : parsedJson ['score']
);
}
}
You create a new Student object like Student.fromJson(your_parsed_json).
Sub-objects work in a similar way. For each object inside the parent object you make a new Dart object, each with it's own parser for fromJson. Then inside the parent factory you call that fromJson method (like so)... This also works for lists of objects.
factory Student.fromJson(Map<String, dynamic> parsedJson){
return Student(
studentId: parsedJson['id'],
studentName : parsedJson['name'],
studentScores : Teacher.fromJson(parsedJson['teacher'])
);