This question already has answers here:
How do I initialize a TypeScript Object with a JSON-Object?
(18 answers)
Closed 6 years ago.
I've been following the Angular2 getting started documentation to get my own app off the ground, I've been successful in retrieving JSON objects from a local file and displaying them in angular2 templates. However currently it relies on the angular classes exactly matching the structure of the objects in my JSON file.
Eventually I'll need my app to work with JSON-LD, which has property names such as "#id". I've done some googling and it seems that RxJS might have the functionality I'm looking for but I'm not sure where to start to interupt the automatic binding from some JSON data straight into my angular2 classes, and instead be able to look up something that's labeled as "#id" in the json and set the value of SomeClass.id
Current code that automatically produces an array of a Person class:
getPeople(){
return this._http.get(this._peopleUrl)
.map(response => <Person[]> response.json().data)
.do(data => console.log(data)) //debug to console
.catch(this.handleError);
}
Fine for JSON like this:
[
{
"id":"1",
"name":"tessa"
},
{
"id":"2",
"name":"jacob"
}
]
But it would obviously fail for JSON like this:
[
{
"#id":"1",
"name":"tessa"
},
{
"#id":"2",
"name":"jacob"
}
]
My class is simple (at the moment :-) )
export class Person {
constructor(
public id:number,
public name:string,
){}
}
Can anyone point me in the right direction for some documentation/examples of mapping complex/tricky json to the classes in angular2?
I found the answer in Option 4 of the answer given here: How do I initialize a typescript object with a JSON object
Hope this helps if anyone lands on this page looking for the same thing!
Related
I have started working on angular again after almost 2 years and i thought i could grasp from my previous knowledge but i am kind of stuck over here and cannot really understand what i can do.
I am using efc for getting data and in services i have the following method
shared-service.ts
getHotelDetails(val:any){
return this.http.get<any>(this.APIUrl+'Hotels/GetHotel/',val);
}
In ts i am getting the correct data by using the below code
mycomponent.ts
hotel$!:Observable<HttpEvent<any[]>>;
constructor(private service:SharedService, private _route:ActivatedRoute) {
}
ngOnInit(): void {
var Id = this._route.snapshot.params['id'];
this.hotel$ = this.service.getHotelDetails(Id);
console.log(this.hotel$);
}
mycomponent.html
I am trying to use the hotel object in html but cannot iterate or find the attributes inside. The api call is giving a json like the below for api:
https://localhost:44372/api/Hotels/GetHotel/1
{
"hotelId": 1,
"name": "pizza",
"addresses": [],
"comments": [],
"hotelFoods": []
}
I just need the code in which i can fetch the name from hotel$ attribute.
I tried ngfor and directly accessing hotel$.id
What you get back from the service is an Observable, you need to subscribe to it in order to access the data. The easiest way to do this in a html template is to use the async pipe.
You need something like this:
{{ (this.hotel$ | async).hotelId }}
I am using ngx-translate for translation.
In my typescript file I have a array of objects. how can I use a i18n key in this array?
shortcutList: Shortcut[] = [];
constructor(private translate: TranslateService){}
this.shortcutList = [
{ text: this.translate.get('shortcuts.some-key'), icon: 'fa-calendar-alt'},
{ text: this.translate.get('shortcuts.some-key2'), icon: 'fa-users'},
{ text: this.translate.get('shortcuts.some-key3'), icon:'fa-archway'}
];
I need a simple answer. I can make separate variables and return the value with a observable but I think that's overkill. Is there a another solution?
also get will return a object iso a string.
I can use .instant but than i will get the key and not the translation
json:
{
"shortcuts": {
"some-key": "some-value",
"some-key2": "some-value2",
"some-key3": "some-value3"
}
}
Update:
I created an resolver.
Answer for this you can find here:
ngx-translate .instant returns key instead of value
Now you can use:
{ text: this.translate.instant('shortcuts.some-key'), icon: 'fa-calendar-alt'},
But now only the first item will be translated.
How can I fix this issue?
Update:
I had a typo in my i18n file everything works now.
The solution for my issue was create a resolver so that the file is loaded before loading the page so I can load the translations in a simple way in the object-array.
I'm using Angular 4 to develop an app which is mainly about displaying data from DB and CRUD.
Long story short I found that in Angular 4 the component html doesn't like displaying loosely typed object (leaving the space blank while displaying other things like normal with no warning or error given in console) even if it can be easily displayed in console.log output, as shown in a string.
So I made a function in the service file to cast the values into a set structure indicating they're strings.
So now something like this works:
HTML
...
<div>{{something.value}}</div>
...
Component.ts
...
ngOnInit() {
this.route.params.subscribe(params => {
this.pkey = params['pkey'];
this.service.getSomethingById(this.pkey)
.then(
something => {
this.something = this.service.convertToStructure(something);
},
error => this.errorMessage = <any>error);
});
}
...
Code of the function convertToStructure(something)
convertToStructure(someArr: myStructure): myStructure {
let something: myStructure = new myStructure();
something.value = someArr[0].value;
return something;
}
But as I dig into other files for copy and paste and learn skills from what my partner worked (we're both new to Angular) I found that he did NOT cast the said values into a fixed structure.
He thought my problem on not being able to display the values (before I solved the problem) was because of me not realizing it was not a plain JSON object {...} but an array with a single element containing the object [{...}] .
He only solved half of my problem, cause adding [0] in html/component.ts was not able to make it work.
Component.ts when it did NOT work
...
ngOnInit() {
this.route.params.subscribe(params => {
this.pkey = params['pkey'];
this.service.getSomethingById(this.pkey)
.then(
something => {
console.log(something[0].value); //"the value"
this.something = something[0]; //html can't find its value
},
error => this.errorMessage = <any>error);
});
}
...
HTML when it did NOT work
...
<div>{{something[0].value}}</div> <!--Gives error on the debug console saying can't find 'value' of undefined-->
...
And of course when I'm using the failed HTML I only used this.something = something instead of putting in the [0], and vice versa.
So I looked into his code in some other page that display similar data, and I found that he used *ngFor in html to extract the data and what surprised me is that his html WORKED even if both of our original data from the promise is identical (using the same service to get the same object from sever).
Here's what he did in html:
...
<div *ngFor="let obj of objArr" ... >
{{obj.value}}
</div>
...
His html worked.
I'm not sure what happened, both of us are using a raw response from the same service promise but using for loop in html makes it automatically treat the value as strings while me trying to simply inject the value fails even if console.log shows a double quoted string.
What's the difference between having the for loop and not having any for loop but injecting the variable into html directly?
Why didn't he have to tell Angular to use the set structure indicating the values are strings while me having to do all the trouble to let html knows it's but a string?
The difference here is as you said that your JSON is not simple object , its JSON Array and to display data from JSON array you need loop. So, that is why your friends code worked and yours did not. And please also add JSON as well.
So I am coming from a background of C# where I can do things in a dynamic and reflective way and I am trying to apply that to a TypeScript class I am working on writing.
Some background, I am converting an application to a web app and the backend developer doesn't want to change the backend at all to accommodate Json very well. So he is going to be sending me back Json that looks like so:
{
Columns: [
{
"ColumnName": "ClientPK",
"Label": "Client",
"DataType": "int",
"Length": 0,
"AllowNull": true,
"Format": "",
"IsReadOnly": true,
"IsDateOnly": null
}
],
Rows:[
0
]
}
I am looking to write an Angular class that extends Response that will have a special method called JsonMinimal which will understand this data and return an object for me.
import { Response } from "#angular/http";
export class ServerSource
{
SourceName: string;
MoreItems: boolean;
Error: string;
ExtendedProperties: ExtendedProperty[];
Columns: Column[];
}
export class ServerSourceResponse extends Response
{
JsonMinimal() : any
{
return null; //Something that will be a blank any type that when returned I can perform `object as FinalObject` syntax
}
}
I know StackOverflow isn't for asking for complete solutions to problems so I am only asking what is one example taking this example data and creating a dynamic response that TypeScript isn't going to yell at me for. I don't know what to do here, this developer has thousands of server-side methods and all of them return strings, in the form of a JSON or XML output. I am basically looking for a way to take his column data and combine it with the proper row data and then have a bigger object that holds a bunch of these combined object.
A usage case here after that data has been mapped to a basic object would be something like this.
Example:
var data = result.JsonMinimal() as LoginResponse; <-- Which will map to this object correctly if all the data is there in a base object.
var pk = data.ClientPK.Value;
I'm not exactly sure I understand, but you may want to try a simple approach first. Angular's http get method returns an observable that can automatically map the response to an object or an array of objects. It is also powerful enough to perform some custom mapping/transformation. You may want to look at that first.
Here is an example:
getProducts(): Observable<IProduct[]> {
return this._http.get(this._productUrl)
.map((response: Response) => <IProduct[]> response.json())
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError);
}
Here I'm mapping a json response to an array of Product objects I've defined with an IProduct interface. Since this is just a "lambda" type function, I could add any amount of code here to transform data.
I've been searching for ways to do this, but I'm missing something.
I have a custom JSON object, which can basically have any structure, and I want to use this with jsTree. I've found a corresponding plugin here, that claims to have a _parse_json function to transform a custom JSON object to the format that jsTree requires, but for the life of me I can't figure out how to call that plugin. It seems to be included in the version of jsTree that I'm using (1.0rc3).
There is a usage of UIMTreeProcessor I've found, that consists of parsing the XML and calling jsTree like so:
$.jstree._themes = "Content/jstreethemes/";
this.treeEl.jstree({
"json_data" : {
"data":data,
"progressive_render":"true"
},
"plugins" : [ "themes", "ui", "json_data" ],
"core": { "animation": 0 }
});
Now, instead of UIMTreeProcessor parsing the XML and populating data, I want to call $.json_data._parse_json(), but I keep getting errors that this function doesn't exist.
Can anyone show me an example? Thank you kindly.