Error rendering json file in ngFor - json

I am looping through a json file to display data in panels. But i am having some trouble controlling how to display the data appropriately.
This is my json data that is returned from the services:
Object {Group1: Object,
Group2: Object}
The json file data sample:
{
"Group1": {
"name": "Group1List",
"dataFields": [..],
"dataQuery": {..},
"id": 1,
"title": "Group1",
"content": {..}
},
}
This is my services:
getGroupsData(){
return this._http.get('...')
.map((res:Response) => res.json())
}
Component.ts:
groups: Array<any> = [];
getGroups(){
this.groupService.getGroupsData().subscribe(
data => this.groups = data;
}
HTML:
<div dnd-sortable-container [sortableData]="groups" [dropZones]="['container-dropZone']">
<div class="col-sm3" *ngFor="let group of groups; let i = index" dnd-sortable [sortableIndex]="i" [dragEnabled]="dragOperation">
<div class="panel panel-primary" dnd-sortable-container [dropZones]="['widget-dropZone']">
<div class="panel-heading"></div>
<div class="panel-body"></div>
</div>
</div>
</div>
when i render the code i get an error in the console stating: Error trying to diff '[object Object]' in the heading i would like to add Group1 and then in the body i will display different parts from the json.
What is the source of the problem?

*ngFor requires an array, but it looks like you are passing it an object.
If you cannot change the JSON response, and you know the names of the groups beforehand, you can place the objects in an array:
this.groups = [data.Group1, data.Group2, // etc]

*ngFor requires an array [], and you are passing an object
Your sample has unnecessary nested level, flat is always better
Your json should look like this
[
{
"name": "Group1List",
"dataFields": [..],
"dataQuery": {..},
"id": 1,
"title": "Group1",
"content": {..}
},
{
"name": "Group2List",
"dataFields": [..],
"dataQuery": {..},
"id": 2,
"title": "Group2",
"content": {..}
},
// ....
]
Update:
If you have no control over your json scheme, try to flatten it here
getGroupsData(){
return this._http.get('...')
.map((res:Response) => res.json())
.map((obj) => Object.keys(obj).map((key)=>{ return obj[key]})
}
or implement a pipe that iterate over object properties
import { PipeTransform, Pipe } from '#angular/core';
#Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (let key in value) {
keys.push(key);
}
return keys;
}
}
and use it like this
<div *ngFor="let group of groups | keys; let i = index">
</div>

Change your component to:
groups: Array<any> = [];
getGroups(){
this.groupService.getGroupsData().subscribe(
data => this.groups = data.Group1.dataFields;
}
Why?
Because, you want your groups component property to be an array.
So, in your subscribe handler, data will refer to the entire JSON object, and you only care about the Group1 property of your results.

Related

Angular try from local json file find by id

I have local json file (Kitchen types), i create KitchenTypesService there are 2 inside function GET AND FIND(ID), GET function its work, but not working find function, have error "ERROR TypeError: Unable to lift unknown Observable type", i try with find function get kitchen with id. Tell me what's the problem
Service
export class KitchenTypesService {
private _jsonURL = 'assets/data/kitchenTypes.json';
constructor(private http: HttpClient) {
this.get().subscribe((data) => data);
}
public get(): Observable<any> {
return this.http.get(this._jsonURL);
}
public find(id: number) {
this.get().subscribe(find((data: any) => data.id == id));
}
}
Component
export class KitchenDimensionComponent implements OnInit {
title: string = 'VirtuvÄ—s matmenys';
step: number = 2;
selectedKitchenId: number;
kitchen: any;
constructor(
private persistenceService: PersistenceService,
private httpKitchenTypes: KitchenTypesService
) {}
ngOnInit(): void {
this.initialSelectedKitchenId();
console.log(this.httpKitchenTypes.find(1));
}
initialSelectedKitchenId(): void {
this.selectedKitchenId = this.persistenceService.get('selectedKitchenId');
}
}
Local KitcehTypes.json
[
{
"id": 1,
"title": "Standartine",
"src": "/assets/images/kitchen-types/one-well.png",
},
{
"id": 2,
"title": "L forma",
"src": "/assets/images/kitchen-types/L-shaped.png",
},
{
"id": 3,
"title": "U forma",
"src": "/assets/images/kitchen-types/U-shaped.png",
},
{
"id": 4,
"title": "G forma",
"src": "/assets/images/kitchen-types/G-shaped.png",
}
]
Error Message
[
So there are a few ways to tackle this. You're right, HttpClient does cause the error you mentioned, but there is a way around this. May be this can help you.
Directly importing the JSON file using resolveJsonModuleTo work with this, you'll need to add the following in your tsconfig.json file
"resolveJsonModule": true Then you can simply import your data by adding this in your service:
import * as data from './kitchenTypes.json'
Note that your will need to update the file path accordingly
Once this is done, you can now access the JSON file data. You can view, and search the contents of the JSON file as per your need.
data: any = (data as any).default;

How to iterate over JSON returned by HttpClient

I have a simple Angular HttpClient, which is correctly returning JSON. I am attempting to cast the results to enforce type safety (not sure if this is correct).
But how do I actually access the returned JSON to copy it into an array?
The httpClient get() request is (and seems to be working fine):
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<Symbols[]>(this.REST_API_SERVER);
}
The Symbols interface is
export interface Symbols {
code: string
desc: string
}
I have a component which calls the data service and is getting a response. However the code below returns an error when attempting to map the JSON into a string array
ERROR TypeError: syms.map is not a function
listOfOption: Array<{ value: string; label: string }> = []
this.dataService.sendGetRequest().subscribe((syms: Symbols[]) => {
console.log('return value ' + JSON.stringify(syms))
// console output shows the returned JSON and it looks correct
//this does not work, how do I copy the results to a string array??
this.listOfOption = syms.map(results => {
return {
value: results.code,
label: results.code,
}
})
})
The JSON data structure is:
{
"results": [
{
"code": "code1",
"desc": "Long description of code 1"
},
{
"code": "code2",
"desc": "Long description of code 2"
},
{
"code": "code3",
"desc": "Long description of code 3"
},
{
"code": "code4",
"desc": "Long description of code 4"
}
]
}
This is driving me crazy
Model a new interface called responseData to support response type.
export interface responseData{
results: Symbols[]
}
export interface Symbols {
code: string
desc: string
}
Update the same in service
public sendGetRequest(): Observable<responseData> {
return this.httpClient.get<responseData>(this.REST_API_SERVER);
}
You can now retrieve the results using array.map()
listOfOption: Array<{ value: string; label: string }> = []
this.dataService.sendGetRequest().subscribe((syms: responseData) => {
console.log('return value ' + syms)
this.listOfOption = syms.results.map(result => {
return {
value: result.code,
label: result.code,
}
})
})
The response data has an object root, but you're trying to parse it as an array root. I think the simplest solution would be something like this:
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<{results: Symbols[]}>(this.REST_API_SERVER)
.pipe(pluck('results'));
}
Which specifies that the response data is an object with a field named results which holds an array of Symbols.
Alternatively you could also extract the response type to a separate definition:
interface ApiResponse {
results: Symbols[]
}
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<ApiResponse>(this.REST_API_SERVER)
.pipe(pluck('results'));
}

map empty json array to object

I have an api call that returns a json message. One of the variables in the message is an object array, sometimes that array is empty but the data in that array is needed so that it can be 2-way data-bound to angular material elements in the HTML Code. I need a work around for when that object array is empty, the DOM elements don't error out because the array is undefined. It should just leave those angular material elements blank.
(I would like to do this without using nfIf on the elements since they should still be displayed.)
The way the code is currently set up the name variable is not 2-way data bound to the variable because it does not get updated.
I have already attempted using elvis operators but those do not work with [(ngModel)]. I can one way bind with [ngModel]="array?.value" but not update. Adding (ngModelChange) = "datasource?.value? = $event" , is not working because the '?' is an unexpected token.
Is there anything I can do on the JSON mapping side?
service.ts
GetData(identificationNum: string): Observable<DATA_OBJECT>{
return this.http.get<DATA_OBJECT>(this.service.apiAddress + 'api/GetData/' + identificationNum)
.pipe(
map(
jsonObj => Object.assign(new DATA_OBJECT(), jsonObj)
)
);
}
datastructuresmodels.ts
export class DATA_OBJECT
{
public header: Object ;
public identificationNum: string ;
public infoArray: Array<Info> ;
}
export class Info
{
public name: string;
public address: string ;
public gender: string ;
}
component.ts
data: DATA_OBJECT;
dataSource: Info[];
ngOnInit() {
this.service.GetStowData(this.number).subscribe(
(data: DATA_OBJECT) => (this.data = data),
error => console.log(error),
() => {
this.dataSource = this.data.infoArray;
}
);
}
component.html
<div class="col">
<p class="subheading">Name: </p>
<mat-form-field>
<input matInput placeholder="Name"
[ngModel]="datasource?.name">
</mat-form-field>
</div>
JSON Example of problem:
{ "header": { "messageCode": 00, "status": 0,}, "identificationNum": 123, "infoArray": [] }
JSON Example Populated (functions as desired because the info is there):
{ "header": { "messageCode": 00, "status": 0,}, "identificationNum": 123, "infoArray": [{"name":"string"}, {"address":"string"}, {"gender":"string"}] }
The expected results are empty angular material elements even when the api responds with the empty array.

TypeError: Cannot read property 'reduce' of undefined in react

I have a form in which I am asking the user to input field values for a couple of fields, storing the field values in an state and displaying the state values in a customised format.
So, I have a couple of input fields and a submit button:
<button onClick={this.handleSubmit}>Submit</button>
{
this.state.credentials &&
//<Credentials value={this.state}/>
<Credentials value={JSON.stringify(this.state, undefined, 2)} />
}
The Credentials function convert the state of the component in JSON format:
const Credentials = ({value} ) => {
return <pre>{formatState(value)}</pre>;
}
The formatState function will basically manipulate the state values and display them in the way I want:
function formatState(state) {
console.log("hi")
console.log(state);
const output = state.groups.reduce((final, s)=> {
console.log(output)
const values = Object.keys(s).reduce((out, o)=> {
out[o] = s[o].map(k => Object.values(k))
return out;
}, {})
final = {...final, ...values}
return final;
}, {})
console.log(output)
}
The state looks like this:
{
"groups": [
{
"typeA": [
{
"name": "abc"
},
{
"number": "13,14"
}
],
"typeB": [
{
"country": "xyz"
},
{
"date1": "2019-05-14"
}
]
}
]
}
But I want the output like this:
groups: {
"typeA": [[abc],[13,14]],
"typeB": [[2019-05-14],[xyz]]
}
SO, reduce function is used to convert the state into the following output. But I getting the error :
"TypeError: Cannot read property 'reduce' of undefined"
Please can anybody tell me why this is happening.
Error is here <Credentials value={JSON.stringify(this.state, undefined, 2)} />. JSON.stringify produces string representaion of some object (this.state in your case). Argument state of formatState has type of string. It seems that you want to have state arguemnt to be object. So you should do
<Credentials value={this.state} />

How to Map array Of Json Object Into another Plain json Object in TypeScript Angular 2

Response Body;
[
{
"professionalId": {
"cib_code": "30003",
"thirdPartyId": "RS30004"
},
"nationalIdentifier": "984538926",
"nationalIdType": "SIREN"
},
{
"professionalId": {
"cib_code": "30003",
"thirdPartyId": "RS30008"
},
"nationalIdentifier": "944316926",
"nationalIdType": "SIREN"
}
]
By Using Rest Calling from DB getting json Response:
this.thirdpartyServices.getThirdparties().subscribe(data=>this.thirdpartyapis$=data);
Getting Given Above Json Array Response in **thirdpartyapis** object
but i wanted another object which can contain this data in simple format like
[
{
"cib_code": "30003",
"thirdPartyId": "RS30004"
"nationalIdentifier": "984538926",
"nationalIdType": "SIREN"
},
{
"cib_code": "30003",
"thirdPartyId": "RS30008"
"nationalIdentifier": "944316926",
"nationalIdType": "SIREN"
}
]
want to map my data in Typscript so that that same object can be use in Html to Display data in Grid table
Kindly Suggest in angular 2 Typescript
Maybe you could use destructuring,
this.thirdpartyServices.getThirdparties()
.map(each => {
let { nationalIdentifier, nationalIdType } = each;
return {
...each.professionalId,
nationalIdentifier,
nationalIdType
};
})
.subscribe(data => {
this.thirdpartyapis$ = data;
});
You may also import 'map' from,
import 'rxjs/add/operator/map';