I have two classes defined as follows,
export class Cycle {
lock_id: number;
bicycle_id: number;
qr_code: number;
latitude: number;
longitude: number;
status: number;
battery_level: number;
is_locked: number;
is_active: boolean;
last_date_updated_on: Date;
last_location_updated_on: Date;
constructor () {
}
}
And another class is,
import { Cycle } from './Cycle';
export class ParkingLocation {
parking_id: number;
latitude: number;
longitude: number;
parking_radius: number;
max_cycle_limit: number;
cycles: Cycle[];
available_parking_space: number;
available_cycles: number;
address: string;
area_id: number;
constructor () {}
}
I am getting a JSON object from http get method which is called as follows,
return this.http.get(this.serverUrl + this.getParkingAreaUrl + '?parkingArea=' + this.myWebLocation.id, httpOptions)
.subscribe( (data: ParkingLocation[]) => {
// console.log(data);
this.location = data;
console.log(this.location);
for ( let obj of this.location) {
console.log(obj.parking_id);
console.log(obj.address);
console.log(obj.latitude);
console.log(obj.cycles);
}
},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
console.log('Client-side error occured.');
} else {
console.log('Server-side error occured.');
console.log( err );
}
}
);
}
And here is JSON output from the method,
[
{
"parkingId": 1,
"latitude": 12.958042,
"longitude": 77.716313,
"parkingRadius": 1,
"maxCycleLimit": 5,
"cycles": [
{
"lockId": "123654789123655",
"bicycleId": 0,
"latitude": 12.955596,
"longitude": 77.714446,
"status": 3,
"batteryLevel": 500,
"parking": {
"parkingId": 1,
"latitude": 12.958042,
"longitude": 77.716313,
"parkingRadius": 1,
"maxCycleLimit": 5,
"cycles": null,
"avilableParkingSpace": 0,
"availableCycles": 0,
"address": "HyperCity Market"
},
"qrCode": "1123",
"lastDataUpdatedOn": null,
"lastLocationUpdatedOn": null,
"active": true,
"locked": false
}
],
"avilableParkingSpace": 0,
"availableCycles": 0,
"address": "HyperCity Market",
"areaId": 1
}
]
But when i ran the application, the console statements written while calling http method is giving output
Undefined
For attributes like parking_id, cycles, but the correct output is given for other 2 attributes i.e for address and latitude.
Please correct me where I am wrong, the JSON output is mapping correctly to location object? If not, where I am going wrong, Please suggest me some articles to read for the problem.
NOTE: I am unable to follow, what .map(),.subscribe() function will do to the http.get() method in angular4.
What you are doing now, is not creating instances of you class, with
.subscribe( (data: ParkingLocation[]) => {
you are just saying that what you expect is a response that matches your class. You need to explicitly map your response to your class. There are several ways to do that. You could do it longhand..
// assuming you are using HttpClient:
.map(response => response.map(x => new ParkingLocation(x.parkingId /** ....**/))
But it would be easier to create some kind of serializer or create a class constructor. Here are some ideas for that: How do I cast a JSON object to a typescript class and this answer.
Related
I'm trying to create an object out of my json (from a http request) but it's a plain string.
Interfaces:
export interface CeleryTask {
uuid: string,
state: string,
received: string,
result: Chat,
}
export interface Chat {
id: number;
chatTitle: string;
chatId: string;
users: User[];
archived: boolean,
}
GET Request in my service:
loadAllSuccessTasksFromFlower(): Observable<CeleryTask[]> {
return this.http.get<CeleryTask[]>("http://localhost:5566/api/tasks?state=SUCCESS")
.pipe(map(response => Object.entries(response)
.map(entry => ({
uuid: entry[0],
state: entry[1].state,
received: entry[1].received,
result: entry[1].result
}))))
}
HTTP Response:
{
"67fe1783-4451-4fa5-838e-b78279fd5c07":{
"uuid":"67fe1783-4451-4fa5-838e-b78279fd5c07",
"name":"upload.tasks.importWorkTask",
"state":"SUCCESS",
"received":1668285215.4455156,
"sent":null,
"started":1668285219.4739492,
"rejected":null,
"succeeded":1668285419.1474545,
"failed":null,
"retried":null,
"revoked":null,
"args":"('C:\\Users\\xx\\AppData\\Local\\Temp\\xxx', 'xx.pdf')",
"kwargs":"{}",
"eta":null,
"expires":null,
"retries":0,
"result":"{'id': 9, 'chatTitle': 'My Chat'}",
"exception":null,
"timestamp":1668285419.1474545,
"runtime":199.67199999999866,
"traceback":null,
"exchange":null,
"routing_key":null,
"clock":599,
"client":null,
"root":"67fe1783-4451-4fa5-838e-b78279fd5c07",
"root_id":"67fe1783-4451-4fa5-838e-b78279fd5c07",
"parent":null,
"parent_id":null,
"children":[
],
"worker":"celery#xxx"
}
When I console.log the result:
{
"uuid": "67fe1783-4451-4fa5-838e-b78279fd5c07",
"state": "SUCCESS",
"received": 1668285215.4455156,
"result": "{'id': 9, 'chatTitle': 'My Chat'}"
}
The id & chatTitle is not a chat object, it's an plain string. So it's not possible to access object.result.chatTitle
Any idea how to solve this problem?
One way to get the object from the received string would be
result: JSON.parse(entry[1].result);
Build a type guard to let typescript understand that you really have a Chat object
function isChat(o: any): o is Chat {
// check whatever is necessary to be a Chat object
return "id" in o && "chatTitle" in o
}
Use the typeguard like this
const parsed = JSON.parse(jsonString);
if (isChat(parsed)) {
// do something with now correctly typed object
} else {
// error handling; invalid JSON format
}
See https://stackoverflow.com/a/62438143/7869582 for more info on that
So i have following JSON:
.json
"type": [ {
"id": 2,
"secondid": "1",
"name": "f",
"positionX": 0,
"positionY": 0
}]
and following Service:
public updateposition(Model: typemodel): Observable<any> {
return this.http.post(this.apiEndPoint + '/type' + '/' + typemodel.id , typemodel);
}
and following TS:
.ts
x: number;
y: number;
updateposition()
{
}
So the goal is to update the json object "type" by clicking a button with html. The html part is no problem. But i don't know how to update the json object with the two new positions x and y which are declared in ts. I want to have the process in the function updateposition(). Do you have any suggestions :) ?
You would have to use Dependency Injection to obtain a reference to the Service in your component and use it to retrieve and store the JSON object. Then update it like you would any other object in JS when the button is clicked, and make the API call. Be sure to subscribe to the result or the API call will not go through.
// ...
export class MyComponent {
public jsonObject: TypeModel = { ... };
public constructor(private service: Service) { }
// ...
public function updateposition() {
this.jsonObject[0].positionX = 52;
this.jsonObject[0].positionY = 42;
this.jsonObject = this.service.updateposition(this.jsonObject).subscribe(
result => {
console.log("The API call returned", result);
}
);
}
}
I have the following json:
{
"AssetId": "Asset1",
"Currency": "USD",
"Rating": "BBB",
"Dur": 0.557519237
}
and the class:
export class Constituent {
AssetId?: string;
Currency?: string;
Rating?: string;
Dur?: number;
public get maturityBucket(): string {
const dur = this.Dur || 0;
if (dur < 0.5) {
return '0-6m';
}
if (dur < 1) {
return '6m-1y';
}
if (dur < 2) {
return '1y-2y';
}
if (dur < 5) {
return '2y-5y';
} else {
return '5y+';
}
}
}
However, when I read the JSON in like so:
loadConstituentData(): void {
const url = './src/data/assets.json';
this.http.get(url)
.subscribe(response => {
this.data.next(<Constituent[]>response.json());
}, this.handleError);
}
The maturityBucket read-only property disappears.
How can I fix this?
Here is a Plunker of the code: https://plnkr.co/edit/3oRl9zIlG23jBUvUqaw6?p=preview
When you trying to cast an object to particular class or interface you do not change this object you just tell Typescript complier that this object has particular type for further type checking. In this case you do have all properties on your object but does not have a method (getter property which is actually the method), so doing this casting you just misleading compiler and yourself. To get this readonly property work you must add it to the object.
Yo can achieve desired behaviour by creating new instance of Constituent and assigning properties from your object. For example:
export class Constituent {
AssetId?: string;
Currency?: string;
Rating?: string;
Dur?: number;
static createFromJsonObject(jsonObject: any): Constituent {
let constituent = new Constituent();
return Object.assign(constituent, jsonObject);
}
...
}
and usage is:
this.http.get(url)
.subscribe(response => {
this.data.next(response.json().map(item => Constituent.createFromJsonObject(item)));
}, this.handleError);
Angular2 two way data binding is working for json object.
but i want to bind with object which is returned by method call inside the model object.
My JSON data as follows,
{
"partyId": "1001",
"partyName": "Lifecare Pharmaceuticals",
"partyShortName": null,
"partySecondaryName": null,
"partySecondaryShortName": null,
"sortingName": "Lifecare Pharma",
"mailingName": null,
"address": [{
"type": "Personal",
"addressLine1": "",
"addressLine2": "",
"addressLine3": "",
"phone":""
},
{
"type": "Office",
"addressLine1": "",
"addressLine2": "",
"addressLine3": "",
"phone":"9876543210"
}]}
And blow is my typescript model class,
export class Party {
partyId: string;
partyName: string;
partyShortName: string;
partySecondaryName: string;
partySecondaryShortName: string;
sortingName: string;
mailingName: string;
address: Array<Address>;
getOfficeAddress(): Address {
if(!address) {
this.address = [];
this.address.push(new Address());
}
let address ;
this.saleReturnLineItemSet.forEach(addr => {
if(addr.type == 'Office') {
address = addr;
}
});
return address;
}
}
export class Address {
type: string;
addressLine1: string;
addressLine2: string;
addressLine3: string;
phone: string;
}
And this is how am trying to bind it in input tag.
<input name="phoneNo" [(ngModel)]="party.getOfficeAddress().phone" >
Will it possible to bind like this?
or Please suggest a way to do such bindings.
It's not possible, as a two-way-binding dictates that you can read and write to the property you are binding to.
You can use a get and set method for the phone instead.
get phone(): string {
if(!this.address) {
this.address = [];
this.address.push(new Address());
}
let address ;
this.saleReturnLineItemSet.forEach(addr => {
if(addr.type == 'Office') {
address = addr;
}
});
return address.phone;
}
set phone(num: string) { //set the phone number }
And in your template, bind to the phone directly
<input name="phoneNo" [(ngModel)]="phone" >
This will cause an error `Expression has changed since it was last checked.
Binding to methods that return a new instance of a value every time they are called won't work.
If you cache the created instance and return this cached instance as long as it's content doesn't actually need to be changed, then it will work fine.
I have a set of classes with a fairly straightforward set of fields:
interface IQuiz {
name: string;
questions: Question[];
score(): number;
}
export class Quiz implements IQuiz {
name: string;
questions: Question[];
score(): number {
var theScore: number = 0;
this.questions.forEach(question => (theScore += question.value));
return theScore;
}
}
interface IQuestion {
text: string;
value: number;
}
export class Question {
text: string;
value: number;
}
Then I have some JSON which represents some instances of those objects. This JSON includes values for Quiz.name, an array of Quiz.questions each with values for their text and value fields.
Somewhere else, I have a reference to this Quiz class that has been created from JSON.parse(json) like the code below:
var json = '{"name": "quizA", "questions": [{"text": "Question A", "value": 0 }, ... ]}'
var quiz = <IQuiz>JSON.parse(json);
// Some other stuff happens which assigns values to each question
var score = quiz.score(); // quiz.score is not a function
It seems the deserialized object is not actually an implementation of the interface provided.
How do I get a reference to an instance of the correct interface, so that I can call quiz.score() and it actually call the method?
There is no need of interfaces, it will add twice the work for maintaining your model's properties. Add a constructor in your Quiz class so that it extends your json object.
export class Quiz {
constructor( json: any )
{
$.extend(this, json);
// the same principle applies to questions:
if (json.questions)
this.questions = $.map( json.questions, (q) => { return new Question( q ); } );
}
name: string;
questions: Question[];
score(): number { ... }
}
In your ajax callback, create the Quiz object from your json Object:
let newQuiz = new Quiz( jsonQuiz );
let score = newQuiz.score();
I detailed the solution in that post.