I am new to json and angular. I am trying to access an API response using model. But it is giving me undefined when I try to access it.
Below is the json API returns
{
"Inventory App": {
"AnalyticsUI": "UP",
"BaseUI": "UP",
"PlanningUI": "UP",
"UploadUI": "DOWN"
}
}
My model definition is below
export class AppModel {
constructor(
public experience: AppList
) {}
}
export class AppList {
constructor(
public appName1: String,
public appName2: String,
public appName3: String,
public appName4: String,
public appName5: String
) {}
}
Below is my service call
import { AppModel } from './model/appList.model';
getAppStatus$(): Observable<AppModel> {
return this.http
.get('https://abc.xyc.com/AppController/AppsStatus')
.catch(this._handleError);
}
Below is the component where I am trying to access the API data.
export class MainComponent {
......
appList: AppModel;
.....
public _getAppStatus() {
this.appSub = this.api
.getAppStatus$()
.subscribe(
res => {
this.appList = res;
console.log(this.appList);
console.log(this.appList.experience);
},
err => {console.error(err); }
);
}
}
It is giving me undefined when I try to access this.appList.experience. Where as this.appList is printing the json result properly. Any help on this is much appreciated.
Console output :
Console output
As AJT and Khan stated, issue was property name not matching. Once I changed the property name to match the json response, I was able to get the values.
Related
I want to return this object on every response:
class Response<T> {
success: boolean
message: string
data: T
}
but built in serializer can't process it because it waits for object which is under serialization. This is my solution. I created a custom response serializer and inherit built in one and map response. It works excellent for now! Offered me better way please.
export interface PlainLiteralObject {
[key: string]: any;
}
#Injectable()
export class ResponseSerializerInterceptor extends ClassSerializerInterceptor {
public intercept(context: ExecutionContext, next: CallHandler<any>): Observable<any> {
const contextOptions = super.getContextOptions(context);
const options = {
...super.defaultOptions,
...contextOptions,
};
return next.handle().pipe(map((res: Response<PlainLiteralObject> | Response<Array<PlainLiteralObject>>) => {// data property holds object which is under serialization
const data = super.serialize(res.data, options);
res.data = data;
return res;
}));
}
}
As the title says I'm trying to access a method that is declared in one class (Post) from another class (Comments) which is following a singleton pattern. Post class is a service class which has some methods to make API calls. So I need to have access to them from inside Comments class so that I can make API calls.
This is how a simplied version of Post class looks like right now:
#Injectable({
providedIn: 'root'
})
class PostService extends AnotherService {
constructor( auth: AuthService, http: HttpClient ) {
super('string', auth, http);
}
getPost( id: string ) {
return this.http.get(`posts/${id}`);
}
}
This is how the Comments class look like:
class Comments {
private postService: PostService;
private static instance;
private constructor() {}
static createInstance() {
if ( !Comments.instance ) {
Comments.instance = new Comments();
}
return Comments.instance;
}
getComments( id ) {
// these does not even run
this.postService.getPost( id )
.then( post => {
console.log( post );
})
.catch( error => {
console.log( error );
});
}
}
How can I go about accessing it?
=========UPDATE=======
Creating an instance of Comment class in another class called ClassC.
const instance - Comments.createInstance();
instance.getComments( id );
Use a new service to save your comment object data
let say We have a service named SharedDataService.
private _comments: Array<any> =[];// or array<IComment> (a defined interface from your part)
class SharedDataService(){}
get comments():Array<any>{
return this._comments}
set comments(value:Array<any>){
this._comments = value;
}
}
You should init PostService on your Comments Constructor
private constructor(private postService: PostService,private sharedDataService :SharedDataService) {
}
getComments() {
// these does not even run
this.postService.getPost( '1' )
.then( post => {
this.sharedDataService.comments = post // if You get an array of comments here
console.log( post );
console.log(this.comments)// getter function its new value has been set
})
.catch( error => {
console.log( error );
});
get comments(){
this.sharedDataService.comments
}
}
If You want to send two http request in parallel then get their values You should use combineLatest rxjs operator.
Your post service will be like this:
getPost(id: string) {
$postDataHttpRequest = this.http.get(`posts/${id}`);
$commentsDataHttpRequest = this.http.get(`posts/${id}/comments`);
return combineLatest($postDataHttpRequest, $commentsDataHttpRequest)
}
///
This is how the Comments class look like:
private constructor(private postService: PostService) {
}
getComments() {
this.postService.getPost( '1' )
.subscribe( (posts,comments) => {
console.log(posts);
console.log(comments);
},(error)=>{console.log(error)})
}
I am having a little problem while sending data from my React app to my Spring Boot Controller, I am sending the data via a put method, but I get 400, error, and an error in eclipse pops up, so What I did is :
export const changeContratTypes = (idContrat, items, declaration) => {
const endpoint = template(CONTRAT_TYPES_CHANGE);
return instance // just an axios instance
.put(endpoint({ idContrat }), { items, declaration })
.then(values => values)
.catch(err => err.response);
};
My endpoint constant is the url, simple is that, and I send declaration which is an integer and items which is an array of object, my object structure is :
{
id: 1, // or 2, 3, ....
isSelected: true, // or false
title: "a String here"
}
To get this in Spring boot I created this method in my controller :
#CrossOrigin(origins = "*")
#ApiOperation(value = "${contrat.recuperation}", notes = "${contrat.recuperation.notes}", response = ContratDetailDto.class)
#PutMapping(value="/{idContrat}/trtype")
#ApiModelProperty(example = "4000004")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Enrigistrer Les types de contrats ") })
public ResponseEntity enrigistrerTypesDeContrat(#ApiParam(value = "${contrat.recuperation.param.id}") #PathVariable long idContrat, #RequestBody TypesConformites tcf) {
if (log.isDebugEnabled()) {
log.debug("appel de la méthode enrigistrerTypesDeContrat");
}
System.out.println("Voila "+tcf.getDeclaration());
return ResponseEntity.ok(HttpStatus.OK);
}
This controller is well mapped and other methods in it works fine, but all methods I used are Get Methods.
What I did before that is creating a class used as a RequestBody :
#Getter #Setter
public class TypesConformites {
private int declaration;
private ArrayList<Item> items;
public TypesConformites() {
}
}
and Here is my Item class :
#Getter #Setter
public class Item {
private int id;
private String title;
private boolean isSelected;
public Item() {
}
}
I get this error in Java :
Blockquote
JSON parse error: Unrecognized field "isSelected" (class com.apicil.cosy.contrat.controller.api.impl.external.Item), not marked as ignorable; nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "isSelected" (class com.apicil.cosy.contrat.controller.api.impl.external.Item), not marked as ignorable (3 known properties: "title", "id", "selected"])
at [Source: (PushbackInputStream); line: 1, column: 66] (through reference chain: com.apicil.cosy.contrat.controller.api.impl.external.TypesConformites["items"]->java.util.ArrayList[0]->com.apicil.cosy.contrat.controller.api.impl.external.Item["isSelected"])
What's wrong with that code, Any help would be much appreciated.
Generally the Item is deserialised by jackson like this :-
public void setId(String firstName) {
public void setTitle(String lastName) {
public void setSelected(boolean isActive) {
To avoid this you can just changed the mapping name in the Item and request body.. or annotated your isSelected with #JsonProperty
The data I am trying to access from the API is formatted like below:
{
“array1”:[
{"id”:1, ”someProperty”:”A"},
{"id":2, "someProperty”:”B”}
],
“array2”:[
{"id”:1, ”anotherProperty”:”foo”, ”lastProperty”:”foo2”},
{"id":2, "anotherProperty”:”bar”, ”lastProperty”:”bar2”}
]
}
The Dependencies class:
import { FirstArray } from './first-array';
import { SecondArray } from './second-array';
export class Dependencies {
constructor(
public array1: Array<FirstArray>,
public array2: Array<SecondArray>
) { }
}
The FirstArray class:
export class FirstArray {
constructor(
public id: number,
public someProperty: string
) { }
}
The SecondArray class:
export class SecondArray {
constructor(
public id: number,
public anotherProperty: string,
public lastProperty: string
) { }
}
My Dependencies service.ts file:
/** GET all Dependencies from the server */
getAllDependencies (): Observable<Dependencies[]> {
return this.http.get<Dependencies[]>(apiUrl).pipe(
tap(allDependencies => this.log('fetched allDependencies')),
catchError(this.handleError('getAllDependencies', []))
);
}
The component.ts file:
ngOnInit() {
this.getAllDependencies();
console.log("allDependencies:",this.allDependencies);
}
allDependencies: Dependencies[];
getAllDependencies(): void {
this.DependenciesService.getAllDependencies()
.subscribe(allDependencies => this.allDependencies = allDependencies);
}
When I try console.log(this.allDependencies) in the component file, the result is undefined. The data is retrieved from the API correctly- 'fetched allDependencies' is printed in the logs, and I can print the Dependencies object in the logs just fine by stringifying from the service file:
/** GET all Dependencies from the server */
getAllDependencies (): Observable<Dependencies[]> {
return this.http.get<Dependencies[]>(apiUrl).pipe(
tap(allDependencies => this.log(JSON.stringify(allDependencies))),
catchError(this.handleError('getAllDependencies', []))
);
}
My question: how can I access this data from my component file? I think I'm missing something in my data structures somewhere, or I have a Typescript-related error, but I am not sure.
The biggest issue you have is that within your component, the method that calls your service is void and doesn't return anything...
It doesn't really add any value, so remove it and access the data like this:
ngOnInit() {
this.DependenciesService.getAllDependencies()
.subscribe(allDependencies => {
this.allDependencies = allDependencies;
console.log(this.allDependencies); // multi-line with log.
});
}
Updated as per your comment:
Change your method from getAllDependencies(): void to getAllDependencies(): Observable<Dependencies[]> and call within ngOnOnit
getAllDependencies(): Observable<Dependencies[]> {
return this.DependenciesService.getAllDependencies();
}
ngOnInit() {
this.getAllDependencies().subscribe(.....);
}
I have the following method in a service I've created:
getPost(nid: string): Observable<Post[]>{
let url = "http://test.co.uk/api/v1/basic/" + nid;
return this.http.get(url, {headers: this.headers}).map(res => res.json() as Post).catch(err => {
return Observable.throw(err);
});
}
And this is the class of my component:
export class PostDetailComponent implements OnInit {
posts: Post[] = [];
post: Post = new Post();
constructor(
private route: ActivatedRoute,
private postService: PostService
) { }
ngOnInit() {
this.route.params.switchMap((params: Params) => {
let nid = params ['nid'];
return this.postService.getPost(nid); }).subscribe(res => {
console.log(res)
this.post = res as Post;
}, err =>{
console.log(err);
});
}
}
The JSON feed looks like this(yes one object in the array):
[
{
"nid":"3",
"title":"When Unity meets Vuforia",
"body":"<p>Unless you have been living under a rock in the past 7 - ...",
"uid":"admin",
"path":"\/node\/3",
"field_article_image":"http:\/\/test.co.uk\/sites\/default\/files\/when-unity-meets-vuforia_0.jpg?itok=BGYaotay"
}
]
So in my template, if I print {{post}} I get [object Object] on the screen.
If I print {{post | json}} I get the row JSON feed.
And finally, if I print {{post.title}} or {{post?.title}} I don't get anything.
I also have a class Post that is looking like this:
export class Post{
constructor(
public nid?: string,
public title?: string,
public body?: string
public image?: string
){
}
}
Any hints?
You are assigning an array into what should be a single object. Copy the first element of the array into the post variable
this.post = res[0] as Post
Side note: It's incorrect to assign a raw object to a class instance. In this case, your this.post.constructor won't exist and this.post instanceof Post == false.
You could do Object.assign(this.post, res[0]) but you may need to clear existing properties if not all properties are always present.
I prefer to define object shapes as interfaces instead, then you would not have that problem because all the interface information is removed at runtime, whereas a class does emit some code instead of just doing static type checks at compilation time