I am trying to retrieve a JSON from a URL link. The JSON data consist of both English and Burmese language. However, when I retrieve the data, the app shows a bunch of Burmese words converted into "áá". Any solutions?
class _GetJsonResultState extends State<GetJsonResult> {
#override
Widget build(BuildContext context) {
var jsonFileName = "assets/resultlist/resultlist.json";
fetchData() async {
final response =
await http.get('https://jsonkeeper.com/b/47QP');
if (response.statusCode == 200) {
return(response.body);
}
}
return FutureBuilder(
future: fetchData(),
builder: (context, snapshot) {
List myData = json.decode(snapshot.data.toString());
if (myData == null) {
return Scaffold(
body: Center(
// Loads upon null
child: CircularProgressIndicator(),
),
);
} else {
return Home(myData: myData);
}
},
);
}
}
This is what I'm supposed to get
Change your fetchData() function as below
fetchData() async {
final response = await http.get('https://jsonkeeper.com/b/47QP',
headers: {"charset": "utf-8", "Accept-Charset": "utf-8"});
if (response.statusCode == 200) {
return (utf8.decode(response.bodyBytes));
}
}
Its a decoding issue. Just to clarify what is happening in background
The Dart http API defines (as mentioned below) two ways of interacting with the response data:
body → String
The body of the response as a string. This is converted from bodyBytes using the charset parameter of the Content-Type header field, if available. If it's unavailable or if the encoding name is unknown, latin1 is used by default, as per RFC 2616.
bodyBytes → Uint8List
The bytes comprising the body of this response.
More details at https://github.com/dart-lang/http/issues/175#issuecomment-415721621
So in such cases where you know encoding before hand and think its going to mess use request encoding and a decode from byte
fetchData() async {
final response = await http.get('https://jsonkeeper.com/b/47QP',
headers: {"charset": "utf-8", "Accept-Charset": "utf-8"});
if (response.statusCode == 200) {
return (utf8.decode(response.bodyBytes));
}
}
Related
I have the following problem, I'm new in Dart, and I'm using a Future to construct a list view from a JSON response of an API, once I do this request, I receive the following response:
REQUEST:
Future<List<Job>> _fetchJobs() async {
final response = await http.get(
Uri.parse('http://10.10.10.254/httpapi.asp?command=wlanGetApListEx'));
if (response.statusCode == 200) {
final List jsonResponse = json.decode(response.body)['aplist'] as List;
print(jsonResponse);
return jsonResponse.map((job) => new Job.fromJson(job)).toList();
} else {
throw Exception('Failed to load jobs from API');
}
}
[
{
"ssid":444A446F626C65615F322E34,
"bssid":"80":"3f":"5d":"ed":"cd":f9,
"rssi":42,
"channel":8,
"auth":WPA2PSK,
"encry":"AES",
"extch":0
},
{
"ssid":426172696369632D322E3447,
"bssid":"b0":"76":"1b":"f4":"55":80,
"rssi":18,
"channel":1,
"auth":WPA2PSK,
"encry":"AES",
"extch":0
},
{
"ssid":46616D696C69615F65737061727A61,
"bssid":"60":"32":"b1":"71":"ce":46,
"rssi":0,
"channel":5,
"auth":WPA2PSK,
"encry":"AES",
"extch":0
},
{
"ssid":43617361204C756369616E61,
"bssid":"20":"ab":"48":"86":"17":58,
"rssi":0,
"channel":11,
"auth":WPA2PSK,
"encry":"AES",
"extch":0
}
]
As you can see, the SSID values are in HEX and I need it in UTF-16 or UTF-8
I was trying to implement the hex package, but I can not find how to implement it on a JSON array like this.
The hex codex is in the convert package (not to be confused with the dart built in convert library).
If you need to convert the string you have to its ascii/utf8 form use both convert libraries like this:
import 'dart:convert';
import 'package:convert/convert.dart';
void main() {
final h = '444A446F626C65615F322E34';
final u = utf8.decode(hex.decode(h));
print(u); // prints DJDoblea_2.4
}
The more troubling issue seems to be that the data excerpt you provide is not valid JSON, so you cannot, of course, decode it with json.decode.
Try the following code:
import 'dart:convert';
import 'package:convert/convert.dart';
class Job {
Job({required this.ssid, required this.auth, required this.encry});
final String ssid;
final String auth;
final String encry;
factory Job.fromJson(Map<String, dynamic> json) {
return Job(
ssid: utf8.decode(hex.decode(json['ssid'])),
auth: json['auth'],
encry: json['encry'],
);
}
Map<String, dynamic> toMap() {
return {
'ssid': ssid,
'auth': auth,
'encry': encry,
};
}
}
final List<Map<String, dynamic>> jsonResponse = (json.decode(response.body)['aplist'] as List).map((e) => Job.fromJson(e)).map((e) => e.toMap()).toList();
Flutter does not output all the results during a post request. Out of about 260 comes to the list, 113 are saved.
...............................................................................................................................................................................................................
Future<List<NewChatModel>> getAllChats({#required String userId}) async {
final response = await http.post(
Uri.parse(URL),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, int>{
'first_user_id': int.parse(userId),
}),
);
if (response.statusCode == 200) {
List<NewChatModel> returnList = [];
for (var i in jsonDecode(response.body)) {
returnList.add(NewChatModel.fromJson(i));
}
print(returnList.length);
return returnList;
} else {
return null;
}
}
class NewChatModel {
String id;
String chatId;
String messageId;
String message;
String messageDate;
String schoolId;
String fullName;
String phone;
String email;
String urlProfileImage;
String birthday;
String roleId;
String lastActivity;
String isOnline;
NewChatModel(
{this.id,
this.chatId,
this.messageId,
this.message,
this.messageDate,
this.schoolId,
this.fullName,
this.phone,
this.email,
this.urlProfileImage,
this.birthday,
this.roleId,
this.lastActivity,
this.isOnline});
factory NewChatModel.fromJson(dynamic json) {
return NewChatModel(
id: json['id'].toString(),
chatId: json['chat_id'].toString(),
messageId: json['message_id'].toString(),
message: json['message'].toString(),
messageDate: json['message_date'].toString(),
schoolId: json['school_id'].toString(),
fullName: json['full_name'].toString(),
phone: json['phone'].toString(),
email: json['email'].toString(),
urlProfileImage: json['urlProfileImage'].toString(),
birthday: json['birthday'].toString(),
roleId: json['role_id'].toString(),
lastActivity: json['last_activity'].toString(),
isOnline: json['is_online'].toString(),
);
}
}
Edit: added NewChatModel code
But I don`t think that its help solve problem
I think problem in String limit, idk
If at all it helps you, I have a list of chat conversations in my app, too. I collect them with a Stream and display them with a StreamBuilder(). This is a very resource efficient way to do it, without the need to actually collect all the conversations at once! The StreamBuilder() widget makes sure it collects only the conversations that are currently visible on the screen (plus some).
This is what it looks like:
import 'package:my_giggz/firebase_labels.dart';
import 'package:my_giggz/my_firebase.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class MyMessagesScreen extends StatefulWidget {
#override
_MyMessagesScreenState createState() {
return _MyMessagesScreenState();
}
}
class _MyMessagesScreenState extends State<MyMessagesScreen> {
String myUid = MyFirebase.authObject.currentUser!.uid;
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<QuerySnapshot>(
// Stream of all the conversations in the database that contain my uid:
stream: MyFirebase.storeObject.collection(kCollectionConversations).where(kFieldParticipantsArray, arrayContains: myUid).orderBy(kFieldLastTimeStamp, descending: true).snapshots(),
builder: (context, asyncSnapshot) {
List<Widget> convCards = [];
QuerySnapshot? foundConversations = asyncSnapshot.data;
if (foundConversations != null) {
//It always wants to be null at first, and then I get errors for calling on null.
for (QueryDocumentSnapshot conv in foundConversations.docs) {
Map<String, dynamic> convData = conv.data() as Map<String, dynamic>;
convCards.add(
ConvCard(convData) // A homemade widget that takes a Map argument to display some data from the conversation
);
// i++;
}
} else {
// For as long as the found conversations are null, a spinner will be shown:
return Center(child: CircularProgressIndicator());
}
// This part will only be reached if conversations were found:
return ListView.builder(
padding: EdgeInsets.all(0),
itemCount: convCards.length,
itemBuilder: (context, index) {
return convCards[index];
},
);
},
),
);
}
}
If you have any questions on that, I'm happy to answer.
I do not know why this is so, but here is the answer to my question :)
For some reason, he doesn't want to show the entire length of the list, but he filled it out absolutely correctly)
i can't access to a key of a json response from a restful web service.
{"_body":"{\"values\": {\"user_id\":\"1\",\"name\":\"fred test\",\"email\":\"fred#test.test\",\"username\":\"fredtest\",\"token\":\"d5f66a06ec809d70d0c52842df8dc0011d7d1ad0f2d56f50d3123da17a2489fe\"}}","status":200,"ok":true,"statusText":"OK","headers":{"pragma":["no-cache"],"content-type":["text/html;charset=UTF-8"],"cache-control":["no-store"," no-cache"," must-revalidate"],"expires":["Thu"," 19 Nov 1981 08:52:00 GMT"]},"type":2,"url":"http://localhost/PHP-Slim-Restful/api/login"}
I would like to acces to 'values' in this function: (this.responseData.values)
login(){
console.log('login'+ this.userData);
// Your app login API web service call triggers
this.authService.postData(this.userData,'login').then((result) => {
this.responseData = result;
console.log('userdata : '+ temp);
if(this.responseData.values){
console.log('response: ' + this.responseData);
localStorage.setItem('userData', JSON.stringify(this.responseData));
this.navCtrl.push(TabsPage);
}
else{
this.showToastWithCloseButton()
}
}, (err) => {
console.log('erreur : '+err);
});
}
I have an error undifined!
Can you help me?
I have used Observable to return json data and using the subscribe function in my method and using response.json() to convert the JSON reponse from RESTful webservices.
My component method,
import {Http, Headers, Response, RequestOptions} from '#angular/http';
import {Observable} from 'rxjs/Rx';
var response = this.service.post('deleteUserDetails/'+this.selectedUserId, null);
response.subscribe((res) => {
var response = res.json();
});
Service Post method,
post(url: string, data : any): Observable<any> {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers});
return this.http.post(url, data,{headers: headers});
}
I think this might be helpful for your query.
You can make a for in your JSON and access the return values of your post. Something like that.
"this.responseData = result.json();" -> Return JSON. Make a for.
Example:
public postData(data, url: string) {
this.http.post(url, data).toPromise().then(res => {
let responseData = res.json();
if (responseData) {
for (var item of responseData) {
//Implments
}
}
}, (err) => {
});
}
I am trying pass an object which consists of different data type. I am always getting null value for orderDetails in Web API.
However if do this,
purchaseOrder.Attachments = null,
in the client then orderDetails is no longer null and I have other informations like "SendEmail" and PurchaseOrderNumber.
It looks I might not be correctly set the parameter in the client (angular 2).
However testing the same Web Api method from Console app works fine and I am not getting a null value.
Do I need to separate the JSON data and byte array?
regards,
-Alan-
Models
public class Attachments
{
public int AttachmentId { get; set; }
public string FileName { get; set ;}
public byte[] FileData { get; set ;}
}
public class UpdatePurchaseOrderViewModel
{
public bool SendEmail { get; set; }
public int PurchaseOrderNumber { get; set; }
public Attachments Attachments { get; set;
}
Here is my Web API put method definition
[HttpPut("AddPurchaseOrderNumber/{purchaseOrderId}")]
public StatusCodeResult AddPurchaseOrderNumber(int purchaseOrderId, [FromBody] UpdatePurchaseOrderViewModel orderDetails)
{
try
{
var status = _service.AddPurchaseOrderNumber(purchaseOrderId, orderDetails);
if (status == 200)
_unitOfWorkAsync.SaveChanges();
else return StatusCode(status);//No Data
}
catch
{
return StatusCode(400); // Bad Request
}
return StatusCode(200);//OK
}
Typescript snippet
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept','application/json');
let options = new RequestOptions({ headers: headers });
var body = JSON.stringify(
purchaseOrder
);
var uri = 'http://localhost:33907/api/purchaseorder/addpurchaseordernumber/' + purchaseOrderId;
return this._http.put(uri, body , options)
.map((response: Response) => {
let data = response.json();
if (data) {
return true;
}
else {
return false;
}
})
Update
The orderDetails is created as below
let file = Observable.create((observer) => {
let fr = new FileReader();
let data = new Blob([this.attachment]);
fr.readAsArrayBuffer(data);
fr.onloadend = () => {
observer.next(fr.result);
observer.complete();
};
fr.onerror = (err) => {
observer.error(err);
}
fr.onabort = () => {
observer.error("aborted");
}
});
file.map((fileData) => {
//build the attachment object which will be sent to Web API
let attachment: Attachments = {
AttachmentId: '0',
FileName: this.form.controls["attachmentName"].value,
FileData: fileData
}
//build the purchase order object
let order: UpdatePurchaseOrder = {
SendEmail: true,
PurchaseOrderNumber:this.form.controls["purchaseOrderNumber"].value * 1, //for casting purpose
Attachments: attachment
}
console.log("Loading completed");
return order;
})
When sending objects that have byte arrays as a property back and forth between a client to a WebAPI endpoint, I typically use a DTO that stores the property to explicitly define it as a Base64 string. On the server side I map the DTO to my entity by converting the Base64 string to / from the byte array for server side operations and storing in the database.
The serializer will do something like this automatically but the format passed from JavaScript may not match what the WebAPI JSON serializer is expecting (which is why it's working from your C# Console App).
You didn't include how you are creating the purchaseOrder object in your JavaScript so I can't comment on how that object is being setup - which may be where your issue is.
I'm trying to upload a csv file using ng-file-upoad. Here is my code snippet:
Upload.upload({
url: baseUrl + '/file-upload',
data: {
file: file
}
})
.then(function(res) {
console.log('success: ===> ', res);
}, function(err) {
console.log('erroir: ===> ', err);
}, function() {
console.log('progress: ', arguments);
});
And in node environment I'm parsing the file and inserting the data in database. I don't want to close the connection. That's why I used "response.write". Here is my code snippet:
var path = req.files.file.path,
currentIndex = 0;
fs.readFile(path, 'utf8', function(err, data) {
if(err) {
// handle error
} else {
// making array (dataArray) from data
dataArray.forEach(function(eachData){
newEntry = new app.db.models.SomeCollection(eachData);
newEntry.save(function(err, data) {
if (currentIndex === dataArray.length) {
res.end('DONE!');
} else {
currentIndex++;
res.write(JSON.stringify({
total: dataArray.length,
done: currentIndex
}));
}
});
})
}
});
My question is how I will get the data I'm passing in "res.write"? I don't want to use socket for only this purpose. Am I missing something?
As already explained here:
response.send(msg) is equal to response.write(msg);response.end();
Which means, send can only be called once, write can be called many times, but you must call end yourself.
You are probably not receiving the response because response.end() is missing.
Once you end() your response you should be able to access the response data in your angular controller in the Upload.upload promise that is returned.
It's not like close a connection as you said. This is not a socket-ish like implementation (such as ws or socket.io). Once a request is made it should have a response even if it is to provide error details about that request (i.e. status 401, 403, 404, etc).
in your angular component:
...
constructor(private incrementalService: IncrementalService) {}
incrementalTest() { //activate with a button or whatnot
this.incrementalService.increment().subscribe( (result:any) => {
if (result.partialText) {
console.log(partialText); //do whatever you need to do with your partial results here!
}
})
}
your angular service:
import { HttpClient, HttpHeaders } from '#angular/common/http';
public class IncrementalService {
constructor(private http: HttpClient) {}
increment(): Observable<ArrayBuffer> {
const options = {
reportProgress: true,
responseType: 'text',
observe: 'events'
}
return this.http.request('get', 'http://someURL', { ...this.addRawHeaderOptions(), ...options});
}
private addRawHeaderOptions() {
const authHeaders = new HttpHeaders({
'Content-Type': 'application/json',
//authorization, Cache-Control: 'no-cache, Pragma:'no-cache', et al. }
return { headers: authHeaders }
}
}
Finally, your back-end service (this is express, but should work similarly for raw node):
async function(request, response) {
const increments = [ 1,2,3,4 ];
response.set('Content-Type', 'text/html');
for (const value of increments) { //contains async call - not switch-outable for a forEach.
response.write(`increment - ${value} `);
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
await delay(1000)
}
response.status(200).end()
}
browser console output when run:
increment - 1
increment - 1 increment - 2
increment - 1 increment - 2 increment - 3
increment - 1 increment - 2 increment - 3 increment - 4
!!Sorry for any typos - i had to transcribe this from a locked-down machine.