Payload data as a String, Flutter - flutter

I receive an object from my payload data (which has to be a String) like this: {id: 24VQUCeGD4KnW6tvfhj8MJjuASk, event: user}. Since it is a string now, how can I access the key and value pair of both items in flutter from a String? I have tried creating a model class for it, making a Map again out of the String, decoding it back to json object but all failed. How can I get the key/value pair in a proper way?
Code:
await _notificationsPlugin.show(
id,
'New notification',
'You have received a new notification!',
notificationDetails,
payload: message.data.toString(), // the payload data has to be a string
);
When you press on the notification:
onSelectNotification: (String data) async {
//here is where I want to access the key/value pair of that String 'data'
// i tried something like this but failed
var someData = jsonEncode(jsonDecode(data));
var className = ClassName.fromJson(someData);
print(className.id);
.. but nothing prints
//... some logic
}
class ClassName {
ClassName({
this.id,
this.event,
});
String id;
String event;
ClassName.fromJson(Map<String, dynamic> json) {
id = json['id'];
user = json['event'];
}
}
Any form of help is appreciated!

try this:
import 'dart:convert';
void processData(String data) {
Map<String, dynamic> someData = jsonDecode(data);
var className = ClassName.fromJson(someData);
print(className.id);
}
class ClassName {
ClassName({
required this.id,
required this.user,
});
String id;
String user;
ClassName.fromJson(Map<String, dynamic> json) :
id = json['id'],
user = json['user'];
}
void main() {
processData("{\"id\": \"24VQUCeGD4KnW6tvfhj8MJjuASk\", \"user\": \"user\"}");
}
p.s it seems that your provided JSON has id and event keys but in your ClassName, you are reading id and user keys which doesn't exist.

it happens that the id string isn't delimited so, you may try to custom decode like:
Map<String, String> decodePayload(String eventData) {
final aString = eventData.substring(5, eventData.length - 1);
final parts = aString.split(', ');
final id = parts[0];
final event = parts[1].substring(7, );
return {'id': id, 'event':event};
}
It doesn't looks nice but it may works

Related

Convert class object to data value flutter dart

This is my JSON:
{
'malls' : [{'id':1 , 'name': 'salam'},{'id':2 , 'name': 'salam2'}]
}
And this is my modeling JSON classes:
class MALL {
final int id;
final String name;
MALL({required this.id, required this.name});
factory MALL.fromJson(Map<String, dynamic> data) {
return MALL(id: data['id'], name: data['name']);
}
}
class City {
final List<MALL> malls;
City({required this.malls});
factory City.fromJson(Map<String, dynamic> data) {
var list = data['malls'] as List;
List<MALL> mallList = list.map((i) => MALL.fromJson(i)).toList();
return City(malls: mallList);
}
}
This is my get method:
Future<List<MALL>> get() async {
var response = await http.get(Uri.parse(URL), headers: {"authorization": "Bearer ${token}", "Content-Type": "application/json"});
var data = jsonDecode(response.body);
City api = City.fromJson(data);
return data['malls'];
}
I get this output:
[Instance of 'MALL', Instance of 'MALL']
I want my JSON in output by I got the instance of my classes.
How can I convert the instances to my data? It means I want to return my JSON in output and I can access the keys of malls in my FutureBuilder.
If you wanna print the response of a Class you can override the toString method to print the response of the Class. Example:
class MALL {
final int id;
final String name;
MALL({required this.id, required this.name});
factory MALL.fromJson(Map<String, dynamic> data) {
return MALL(id: data['id'], name: data['name']);
}
#override
String toString() => "{ id : $id, name : $name}";
}
Now you will see the result in console.
Inside your FutureBuilder yo will get list of Malls. Thats you have to use loop or list view builder to access those elemet.
if you want to print the list data. you have to print first element
inside your future build when data is loded.
print(data.first.toString())
add this line of code inside your malls calss
#override
String toString() => "{ id : $id, name : $name}";

Firebase Realtime database serialization in Flutter

I'm struggling a bit with getting data I push to Firebase Realtime DB in Flutter.
I'm using this code to push data to FB:
DatabaseReference newPostRef = news_dbRef.push();
final newKey = news_dbRef.child('News').push().key;
newPostRef.set({
"timestamp": timestamp,
"content": content_u,
"title": title_u,
"imgURL": imageUrl_u.substring(0,imageUrl_u.lastIndexOf('?')),
"fileURL": fileUrl_u.substring(0,fileUrl_u.lastIndexOf('?')),
"user": _user
});
so it creates a desired object in Firebase like this:
screenshot from Firebase
Now when I'm trying to get this data to my app, I'm having issues with proper serialization with it.
This is what I'm doing:
DatabaseReference newsCountRef =
FirebaseDatabase.instance.ref().child('News');
newsCountRef.onValue.listen((DatabaseEvent event) {
var data = event.snapshot.value;
String encoded = jsonEncode(data);
Map<String, dynamic> postslist = jsonDecode(encoded);
var somelist = postslist.entries.map((e) => TestNewsModel(e.key, e.value)).toList();
so it brings me to a stage that I have a list... but cannot read values for each line.
Do you have any ideas what I'm missing? Here's a class I'm using for serialization:
class TestNewsModel {
String recordid;
dynamic fields;
TestNewsModel(this.recordid, this.fields);
String toString() {
return '{ ${this.recordid}, ${this.fields} }';
}
}
class Field {
String timestamp;
String content;
String title;
String imgURL;
String fileURL;
String user;
Field({
required this.timestamp,
required this.content,
required this.title,
required this.imgURL,
required this.fileURL,
required this.user,
});
String toString() {
return '{ ${this.timestamp}, ${this.content}, ${this.title}, ${this.imgURL}, ${this.fileURL}, ${this.user} }';
}}
Would recommend creating a .fromDoc method in your class, similar to how you would create a .fromJson method.
Heres an example from one of my projects, this way you can avoid encoding and decoding.
///Creates a [Patient] from the information from a single firestore doc.
factory Patient.fromDoc(doc) {
return Patient(
doc.data()['email'],
doc.data()['forename'],
doc.data()['surname'],
doc.data()['hospitalNum'].toString(),
doc.id,
);
}

Data gets lost when added to a Model

I am getting data from Firebase Database and Adding it to a List of my Model class. I tested the incoming data by printing to Console and it works fine, but once i add the data to my model class, it disappears.
Here's my Provider class where i'm loading the data.
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:local_stuffs_notification/apis/fcm.dart';
import 'package:local_stuffs_notification/models/request_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
class IncomingRequest with ChangeNotifier {
List<RequestModel> _incomingRequests = [];
IncomingRequest(this._incomingRequests);
List<RequestModel> get incomingRequest {
return [..._incomingRequests];
}
Future<void> setIncomingRequest(RequestModel requestModel) async {
try {
DatabaseReference reference =
FirebaseDatabase.instance.ref("incomingRequests");
reference.child(requestModel.id).child(Fcm.getUid()).set(
{
"name": requestModel.name.toString(),
"phone": requestModel.phone.toString(),
"email": requestModel.email.toString(),
"fcmToken": requestModel.fcmToken.toString(),
},
);
notifyListeners();
} catch (error) {
rethrow;
}
}
Future<void> loadIncomingRequests() async {
try {
SharedPreferences preferences = await SharedPreferences.getInstance();
DatabaseReference reference = FirebaseDatabase.instance
.ref('incomingRequests/${preferences.getString('userId')!}');
Stream<DatabaseEvent> stream = reference.onValue;
stream.listen((DatabaseEvent event) {
print(event.snapshot.value);
final data = event.snapshot.value as Map;
print('data: $data');
final List<RequestModel> loadedRequest = [];
data.forEach(
(key, value) {
print('requestData: ${value['name']}');
loadedRequest.add(
RequestModel(
id: key.toString(),
name: value['name'].toString(),
fcmToken: value['fcmToken'].toString(),
phone: value['phone'].toString(),
email: value['email'].toString(),
),
);
print(loadedRequest);
},
);
_incomingRequests = loadedRequest;
print('LoadedRequests: $loadedRequest');
notifyListeners();
});
// reference.onValue.listen(
// (event) {
// if (event.snapshot.value == null) {
// return;
// }
// final data = event.snapshot.value as Map;
// final List<RequestModel> loadedRequests = [];
// data.forEach(
// (key, requestData) {
// loadedRequests.add(
// RequestModel(
// id: key,
// name: requestData['name'],
// fcmToken: requestData['fcmToken'],
// phone: requestData['phone'],
// email: requestData['email'],
// ),
// );
// },
// );
// _incomingRequests = loadedRequests;
// notifyListeners();
// },
//);
} catch (error) {
rethrow;
}
}
}
Here's my Model Class
class RequestModel {
final String id;
final String name;
final String fcmToken;
final String phone;
final String email;
RequestModel({
required this.id,
required this.name,
required this.fcmToken,
required this.phone,
required this.email,
});
}
I'm getting the data until i added it to loadedRequest List
Please help, i've spent hours on this and i don't know what i'm doing wrong. When i print the loadedRequest list, i get an empty list. Thanks.
Those logs aren't showing an empty list - It says [Instance of 'RequestModel']. That means there is a value there, but Dart simply doesn't know how to convert RequestModel to a String so that it can be printed out on the console.
An empty list would be printed simply as [], and if you had two values, for example, you would see [Instance of 'RequestModel', Instance of 'RequestModel'].
To print out your values with more detail, you can override the toString() method on your class.
For example:
class RequestModel {
final String id;
final String name;
final String fcmToken;
final String phone;
final String email;
RequestModel({
required this.id,
required this.name,
required this.fcmToken,
required this.phone,
required this.email,
});
#override
String toString() =>
"RequestModel(id: $id, name: $name, fcmToken: $fcmToken, phone: $phone, email: $email)";
}
take a look at the raw data once again, it contains all the users data so you need to get the access the uid before the name
final uid = FirebaseAuth.instance.currentUser!.uid;
and then for the RequestModel:
name: data[uid]['name']

How to fix Flutter Expected a value of type 'Map<String, dynamic>', but got one of type 'List<dynamic>'

I'm developing a web app using Flutter Web and RESTful API for backend.
So, I'm trying the fetch the data from the api, serialize it by using Flutter Models, then return the result.
The Problem is, I'm getting this result
Expected a value of type 'Map<String, dynamic>', but got one of type 'List<dynamic>'
How to fix this ?
Here's my flutter codes:
models
// To parse this JSON data, do
//
// final medicalRecordsModel = medicalRecordsModelFromJson(jsonString);
import 'dart:convert';
class MedicalRecordsModel {
MedicalRecordsModel({
this.id,
this.category,
this.fileName,
this.dateTimestamp,
this.description,
this.upload,
this.patientName,
this.age,
this.address,
this.userId,
this.patientId,
this.isActive,
});
final String id;
final String category;
final String fileName;
final String dateTimestamp;
final String description;
final String upload;
final String patientName;
final String age;
final String address;
final dynamic userId;
final int patientId;
final bool isActive;
factory MedicalRecordsModel.fromJson(Map<String, dynamic> json) {
return MedicalRecordsModel(
id: json["id"],
category: json["category"],
fileName: json["fileName"],
dateTimestamp: json["dateTimestamp"],
description: json["description"],
upload: json["upload"],
patientName: json["patientName"],
age: json["age"],
address: json["address"],
userId: json["userId"],
patientId: json["patientId"],
isActive: json["isActive"],
);
}
}
API Connection
import 'dart:convert';
import 'dart:developer';
import 'dart:async';
import 'package:app/src/constants/medical_records.dart';
import 'package:app/src/models/medical_records/medical_records.dart';
import 'package:app/src/pages/Medical-Records/medical_record.dart';
import 'package:http/http.dart' as http;
class MedicalRecordsManager {
var client = http.Client();
var url = ConstantMedicalRecords.medical_records_api;
Future<MedicalRecordsModel> getRecords() async {
var url = ConstantMedicalRecords.medical_records_api;
log('$url');
try {
final response = await client.get(url);
if (response.statusCode == 200) {
return MedicalRecordsModel.fromJson(jsonDecode(response.body));
// print(recordsModel);
}
} catch (Exception) {
print(Exception);
print("Error occured");
}
}
}
Here is the JSON data I want to get
{
"id": "103",
"category": "DOCUMENT",
"fileName": "Check Up",
"dateTimestamp": "2021-02-1012:59:46",
"description": "string",
"upload": "String",
"patientName": "1",
"age": "25",
"address": "Earth",
"userId": null,
"patientId": 12,
"isActive": true
}
Please help me with this one.
you can do it like that
MedicalRecordsModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
change the getRecord as follows
Future<MedicalRecordsModel> getRecords() async {
var url = ConstantMedicalRecords.medical_records_api;
log('$url');
try {
final response = await client.get(url);
if (response.statusCode == 200) {
return MedicalRecordsModel.fromJson(jsonDecode(response.body)[0]);
// print(recordsModel);
}
} catch (Exception) {
print(Exception);
print("Error occured");
}
}
I think jsonDecode gives list of Maps therefore your json map is the first element of that list.
This code wiil work as you expected:
import 'package:json_helpers/json_helpers.dart';
void main() {
// responseBody is the same response.body
// When response is a list of objects
final list = responseBody1.jsonList((e) => MedicalRecordsModel.fromJson(e));
var obj = list[0];
print(obj.category);
print(obj.fileName);
// When response is an object
obj = responseBody2.json((e) => MedicalRecordsModel.fromJson(e));
print(obj.category);
print(obj.fileName);
}
final responseBody1 = '''
[
{
"id":"103",
"category":"DOCUMENT",
"fileName":"Check Up",
"dateTimestamp":"2021-02-1012:59:46",
"description":"string",
"upload":"String",
"patientName":"1",
"age":"25",
"address":"Earth",
"userId":null,
"patientId":12,
"isActive":true
}
]''';
final responseBody2 = '''
{
"id":"103",
"category":"DOCUMENT",
"fileName":"Check Up",
"dateTimestamp":"2021-02-1012:59:46",
"description":"string",
"upload":"String",
"patientName":"1",
"age":"25",
"address":"Earth",
"userId":null,
"patientId":12,
"isActive":true
}''';
class MedicalRecordsModel {
final String id;
final String category;
final String fileName;
final String dateTimestamp;
final String description;
final String upload;
final String patientName;
final String age;
final String address;
final dynamic userId;
final int patientId;
final bool isActive;
MedicalRecordsModel({
this.id,
this.category,
this.fileName,
this.dateTimestamp,
this.description,
this.upload,
this.patientName,
this.age,
this.address,
this.userId,
this.patientId,
this.isActive,
});
factory MedicalRecordsModel.fromJson(Map<String, dynamic> json) {
return MedicalRecordsModel(
id: json['id'] as String,
category: json['category'] as String,
fileName: json['fileName'] as String,
dateTimestamp: json['dateTimestamp'] as String,
description: json['description'] as String,
upload: json['upload'] as String,
patientName: json['patientName'] as String,
age: json['age'] as String,
address: json['address'] as String,
userId: json['userId'] as String,
patientId: json['patientId'] as int,
isActive: json['isActive'] as bool,
);
}
}
Output:
DOCUMENT
Check Up
DOCUMENT
Check Up
That is, when response is a list of objects:
final list = response.body.jsonList((e) => MedicalRecordsModel.fromJson(e));
When response is an object:
final object = response.body.json((e) => MedicalRecordsModel.fromJson(e));
If you don't know what the result is, then you can try both methods.
response.body.json((e) => Model.fromJson(e));
response.body.jsonList((e) => Model.fromJson(e));
If you have already decoded a JSON string and want to convert the result (or part of it), you can use the following methods:
If the type of the decoded value is Map:
final object = value.json((e) => Model.fromJson(e));
If the type of the decoded value is List:
final objects = value.json((e) => Model.fromJson(e));
Every response is sended and received as text, which can be converted to the
Map Format with the dart inbuilt core library import 'dart:convert';.
So the response from the request can be treated like this.
final res = await http.post(Uri.parse(url), body: json.encode({
'userId': uid,
'email': email,
}),
head body: json.encode({
'userId': uid,
'email': email,
}),
headers: {'Content-Type': 'application/json', 'token64': token});
here json.encode() is used to convert to String from Map.
now res variable contain the response which is also a string which can be convert to the Map with json.decode() like this.
final data = json.decode(res);
when working with the data sometimes we occur errors like Map is not a type of Map<String, String> etc.
Which can be solved by type casting the res, like this.
Map<String, String> notification = Map<String, String>.from(data['notification']);
I see these type casting method used in the The boring Flutter Development show in Youtube.
I faced the same kind of problem after I built an API and tried consuming it in flutter. I first extracted the data and check if the extracted data is null. When the condition is false, I made a list loadStudents that will hold the data after the loop. This is what worked out for me after a ton of stress looking for solutions online.

Filling Object with JSON result in flutter

I am returning multiple records as JSON and need to fill an object with them. How is done in Dart?
HomeCategory(0, Icons.check, Colors.blue[800], "Check In", [Task(0, "Check In", true),]),
The JSON result has all this data.
Deserialize the JSON string into a map:
import 'dart:convert';
...
Map<String, dynamic> jsonObj = json.decode(jsonString);
Then create a factory constructor for your class that converts the map into your object:
class HomeCategory {
final int id;
final String iconCode;
final String colorCode;
final String message;
final List<Task> tasks;
HomeCategory(
this.id,
this.iconCode,
this.colorCode,
this.message,
this.tasks,
);
HomeCategory.fromJson(Map<String, dynamic> jsonObj) {
int id = jsonObj['id'];
String iconCode = jsonObj['iconCode'];
String colorCode = jsonObj['colorCode'];
String message = jsonObj['message'];
List<Task> tasks = [];
var tasksObj = jsonObj['tasks'];
if (tasksObj != null && tasksObj is List) {
tasks = tasksObj.map((taskObj) => Task.fromJson(taskObj)).toList();
}
return HomeCategory(id, iconCode, colorCode, message, tasks);
}
Tailor the above code to the structure of your HomeCategory and Task classes as well as the structure of your JSON. (You're going to need to give the Task class a fromJson constructor as well, of course.)
EDIT: If your incoming JSON object is a list, you can simply change how you use the deserialized json object:
List<dynamic> jsonList = json.decode(jsonString);
List<HomeCategory> homeCategories = jsonList.map((jsonObj) => HomeCategory.fromJson(jsonObj)).toList();