Load JSON date to Dart DateTime - json

I have a Rails server that is delivering a MySQL date. My class is set up based upon the AngularDart tutorial. It doesn't seem to load correctly.
My artist_service. dart method:
Future<List<Record>> getArtistsRecords(int id) async {
String url = 'http://catbox.loc/artists/${id.toString()}/records'; // Rails: artists/:id/records
try {
HttpRequest response = await HttpRequest.request(
url, requestHeaders: headers);
List data = JSON.decode(response.responseText);
final records = data
.map((value) => new Record.fromJson(value))
.toList();
return records;
}
catch (e) {
throw _handleError(e);
}
}
My artist.dart factory method:
factory Record.fromJson(Map<String, dynamic> record) =>
new Record(_toInt(record['id']),
record['title'],
record['catalog'],
record['artist_id'],
record['label_id'],
record['style_id'],
record['alternate_catalog'],
record['recording_date'],
record['notes'],
record['penguin'],
record['category']
);
The offending element is recording_date, which is declared as DateTime. When I include in html as {{recording_date}} I get 1958-03-09 for example. If I try {{ recording_date | date}} it errors out as an invalid format. I suspect I'm not setting up the DateTime object correctly. Is it possible to do so with the factory method?

change
record['recording_date'],
to
DateTime.parse(record['recording_date']),

Related

Flutter Can't Convert String To Double

Hello everyone i have a simple function that will receive double from my server and then it should parse this decimal to double and add it to the total amount variable
for (int i = 0; i < purchase.length; i++){
currentTotalPrice = currentTotalPrice + purchase[i]['total_price'];
}
the thing is i am receiving the total price which is a decimal in the database in a String format and when i try to do something like (purchase[i]['total_price']).toDouble(); the compiler throws
Class 'String' has no instance method 'toDouble'.
Receiver: "15.00"
Tried calling: toDouble()
i don't know why in other parts of my code it worked correctly
this is how i am receiving the data
Future<List> _fetchPurchases() async {
final prefs = await SharedPreferences.getInstance();
String accessToken = prefs.getString("accessToken");
final response = await http.get(
'$webSiteUrl/api/admin/purchases/${article['id']}/$_billNumber',
headers: <String, String>{
'Content-Type': 'application/json;',
'Authorization': 'Bearer $accessToken',
},
);
if(response.statusCode == 200){
List purchases = json.decode(response.body);
return purchases;
}else{
return showErrorMessage(context);
}
}
Note: I am Aware of the Constructor solution where you create a class and then factory the data to custom dart object but for some circumstances i can't do that unless i refactor a very large part of the code so if there is a direct way like toDouble() method it would be the best solution
Indeed toDouble does not exist in the String class, but if you must use it, you can create an extension and import it, something like this
extension NumberParsing on String {
double toDouble() {
return double.parse(this);
}
}
check this gist https://gist.github.com/fcontreras/d5095da7daa0ce24e0f3cb157b91e97f

Angular HttpClient returns string data instead of parsed JSON

I've been in the process of migrating a code base from Angular 4.x to 5.x, and I'm running into a strange issue. I have a service function, that is intended to return a list of objects to the front end, which I then massage into a specific data format. I know I'll need to keep the mapping, but I'm a little miffed that it's returning just plain string data.
The original function is this: (using Http from #angular/http just renamed to HttpClient)
public GetVendors(showAll = true, screenArea: number = 0): Observable<Array<SelectModel>> {
let link = AppSettings.API_COMMON_VENDORS;
let params: URLSearchParams = new URLSearchParams();
params.set('showAll', showAll.toString());
params.set('screenArea', screenArea.toString());
let requestOptions = new RequestOptions();
requestOptions.search = params;
return this.httpClient.get(link, requestOptions).map(response => {
let result = JSON.parse(response.json());
let list = new Array<SelectModel>();
let vendors: Array<any> = result;
vendors.forEach(vendor => {
list.push(this.CreateSelectModel(vendor));
});
return list;
});
}
and after ripping out ALL of the Http code, here's the function again using HttpClient from #angular/common/http
public GetVendors(showAll = true, screenArea: number = 0): Observable<Array<SelectModel>> {
let link = AppSettings.API_COMMON_VENDORS;
let params: HttpParams = new HttpParams()
.set('showAll', showAll.toString())
.set('screenArea', screenArea.toString());
return this.httpClient.get<Array<any>>(link, {params}).map(response => {
let list = new Array<SelectModel>();
response.forEach(vendor => {
list.push(this.CreateSelectModel(vendor));
});
return list;
});
}
The issue with this is it kind of defeats the purpose of the new client parsing json for me. The response object is a string representing the JSON of the data I requested, but it's still in a string form, and not the type defined in the get<>() call.
What am I doing wrong here? shouldn't it be parsed already?
Sample Response Data A'la Network Tools in Chrome Dev Tools:
Sample Response Body:
Dev Tools Screenshot with Value of response
The backend (C#) responds with this:
[HttpGet]
public JsonResult Vendors(bool showAll = false, int screenArea = 0)
{
var vendors = _commonBL.GetVendorsSlimForUser(UserModel, UserModel.CustomerId, showAll, screenArea);
return GetJson(vendors);
}
this is how it worked before the Http => HttpClient migration, and it worked with ONE JSON.parse() The data in the return line is simply a standard List<T>
This is what the raw response for your data should look like:
[{"Id":1234,"Name":"Chris Rutherford"}]
But this is what it actually looks like:
"[{\"Id\":1234,\"Name\":\"Chris Rutherford\"}]"
So somewhere in your server code, you have applied JSON encoding twice. Once you correct that, HttpClient will do the right thing.
I'd quote an answer from this thread. Hope it will shed some light on how things work, read it thoroughly it enlightened me tough its not easy to find.
TypeScript only verifies the object interface at compile time. Any object that the code fetches at runtime cannot be verified by
TypeScript.
If this is the case, then things like HttpClient.Get should not
return Observable of type T. It should return Observable of type Object because
that's what is actually returned. Trying to state that it returns T
when it returns Object is misleading.
In the documentation the client's return section says this:
#return an Observable of the body as
type T.
In reality, the documentation should say:
#return an Observable of the body which
might be T. You do not get T back. If you got T back, it would
actually be T, but it's not.

Why is string/json sent in post request to .netcore web api resulting in null?

I have an array that I'm converting to JSON using JSON.stringify
const arrayOfUpdatesAsJSON = JSON.stringify(this.ArrayOfTextUpdates);
This outputs some valid JSON.
[{"key":"AgentName","value":"Joe Blogs"},{"key":"AgentEmail","value":"Joe#test.com"}]
As I'm going to be sending JSON to the server I set the content type to application/json
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
};
When a button is pressed I make the request with the url, body and header.
try {
this.httpservice
.post(
url,
arrayOfUpdatesAsJSON,
httpOptions
)
.subscribe(result => {
console.log("Post success: ", result);
});
} catch (error) {
console.log(error);
}
This works fine and hits the method I'm expecting inside the api.
[HttpPost("{id:length(24)}", Name = "UpdateLoan")]
public IActionResult Update(string id, string jsonString)
{
Console.WriteLine(jsonString);
... and some other stuff
}
The ID is populated inside the url builder which populates ok. I would then expect the contents of my variable jsonString inside the api to be populated with the json of my request however it is always null. What am I missing?
Firstly you need to mark jsonString with [FromBody] to tell model binder bind the parameter from posted json. And because you are expecting plain string value you need to pass valid json string (not object) so you need to call additional JSON.stringify in javascript
const jsonArray = JSON.stringify(this.ArrayOfTextUpdates);
const arrayOfUpdatesAsJSON = JSON.stringify(jsonArray);
this.httpservice
.post(
url,
arrayOfUpdatesAsJSON,
httpOptions
)
Controller
[HttpPost("{id:length(24)}", Name = "UpdateLoan")]
public IActionResult Update(string id, [FromBody] string jsonString)

Argument of type 'Response' is not assignable to parameter of type 'string'

I have this project I am working on.
the idea is to retrieve books from google book API, using angular 4
I am struggling to understand how to read the JSON response, I am still learning Angular.
I was searching the internet and found this source code on GitHub
google bookstore
I am getting the following error
Argument of type 'Response' is not assignable to parameter of type 'string'.
for this line
let bookResponse = JSON.parse(body);
I am not sure if I am doing it the correct way.
appreciate your help
below is my method for send HTTP request.
getBooks(searchparam: any){
let par = new HttpParams();
par.set('q', searchparam);
return this.httpClient.get('https://www.googleapis.com/books/v1/volumes', {
params : new HttpParams().set('q',searchparam)
}).map(
(response: Response) => {
let data = response;
return data;
}
);
}
below is the method to get data from HTTP request and read JSON response
getBook() {
const dataArrya = this.searchForm.get('param').value;
console.log(dataArrya);
this.requestService.getBooks(dataArrya)
.subscribe(
response => {
this.printData(response)
// console.log(this.bookData);
},
(error) => console.log(error)
);
}
private printData(res: Response) {
let body = res;
let books: Array<Book> = new Array<Book>();
let bookResponse = JSON.parse(body);
console.log(bookResponse);
console.dir(bookResponse);
for (let book of bookResponse.items) {
books.push({
title:book.volumeInfo.title,
subTitle: book.volumeInfo.subTitle,
categories: book.volumeInfo.categories,
authors: book.volumeInfo.authors,
rating: book.volumeInfo.rating,
pageCount: book.volumeInfo.pageCount,
image: book.volumeInfo.imageLinks === undefined ? '' : book.volumeInfo.imageLinks.thumbnail,
description: book.volumeInfo.description,
isbn: book.volumeInfo.industryIdentifiers,
previewLink: book.volumeInfo.previewLink
});
}
}
JSON.parse takes a string, but you're passing it an Angular Response, which is an object (not a string). In order to convert an Angular Response to a string, you can call toString on it, like this:
let bookResponse = JSON.parse(body.toString());
As the reference states,
The responseType value determines how a successful response body will be parsed. If responseType is the default json, a type interface for the resulting object may be passed as a type parameter to request().
HttpClient get already parses the response with JSON.parse by default and there is no need to call it twice.
The result is plain object, not Response (it belongs to Http API and can be confused with Response global when not being imported).
The mentioned repository uses Angular 2 and Http, and the code from there isn't suitable here. HttpClient is newer API that was introduced in Angular 4. The main practical difference between Http and HttpClient is that the latter doesn't require to add .map(response: Response => response.json()) to the request.

Angular: Typescript casting JSON response as object model not working

I have an issue while I try to cast a json response to object, all the properties of my object are string is that normal ?
Here is my ajax request :
public getSingle = (keys: any[]): Observable<Badge> => {
return this._http.get(this.actionUrl + this.getKeysUrl(keys))
.map((response: Response) => response.json() as Badge )
.catch(this.handleError);
}
Here is my badge model :
export interface Badge {
badgeNumber: number;
authorizationLevel: number;
endOfValidity: Date;
}
And here is where I call the service function and I'm facing the issue :
this._badgeService.getSingle(this.ids).subscribe(
(badge: Badge) => {
console.log(typeof(badge.endOfValidity)); // <-- returning string and not Date
},
error => console.log(error);
});
Thats kinda tricky to explain:
Date is a class, this means that values of type Date need to be created through a constructor call. In other words, create a class instance with new Date(...).
The Response.json method will only return an object in JSON format, and such doesnt contain an instance of any class, only maps of key:property.
So what you need to do, is to manually convert the value returned from .json() to a Base object. This can be done as follows:
public getSingle = (keys: any[]): Observable<Badge> => {
return this._http.get(this.actionUrl + this.getKeysUrl(keys))
.map(r => r.json())
.map(v => <Badge>{
badgeNumber: v.badgeNumber,
authorizationLevel: v.authorizationLevel,
endOfValidity: new Date(v.endOfValidity)
// preferably this string should be in ISO-8601 format
})
//the mapping step can be done in other ways most likely
.catch(this.handleError);
}