Getting specific object in nested JSON - json

I have following JSON retrieved from Web service and I am able to get specific element in nested JSON by hard-coding the index in html. Below is the sample data. This is just a portion of entire JSON, I caught rest of them and they are all in same order.
Now, I would like to get "id" element in condition to Name. All names will be given, but index for Table where Names located are unknown. I need to be able to get "id" for all given names. How should proceed this?
{
"School": {
"Table": [
{
"Name": [ "Leo" ],
"id": [ "123" ],
"class": [ "A" ]
},
{
"Name": [ "Kelvin" ],
"id": [ "456" ],
"class": [ "B" ]
}
]
}
}
ngOnInit(): void {
this.appService.getData().subscribe(res =>
this.results = res,
error => console.log(error)
);
}

This might be what you're looking for:
School.Table
.filter(o => o.Name === 'condition')
.map(o => o.id)
For example:
<p *ngFor="let id of ids$ |async"> {{ id }} </p>
this.ids$ = this.service.getSchool()
.map((o: School) => o.Table
.filter(o => o.Name === 'condition')
.map(o => o.id))

it's already been said but use a data service. Once that has returned the JSON data it's much easier to transform it to exactly how you want it. I've done a bit to this recently. Here's an example of a data service that does exactly this. Once this.gearDataJSON = gearData; is populated you can easily process the data into something the easy to work with on the HTML side.
Component
import { Component, OnInit } from '#angular/core';
import { Subscription } from 'rxjs/Subscription';
import { Observable } from 'rxjs/Rx';
import { Injectable } from '#angular/core';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import 'rxjs/Rx';
import { GearDataService } from '../../services/geardata.service'
#Component({
selector: 'app-gears',
templateUrl: './gears.component.html',
styleUrls: ['./gears.component.css']
})
#Injectable()
export class GearsComponent implements OnInit {
constructor(public gearDataService : GearDataService) {}
gearDataJSON; // Holds a complete copy of gears.json data
manufacturerNames : string[]; // Bit of JSON that we want to chop off or process
ngOnInit()
{
this.gearDataService.getGearData().subscribe((gearData) => // Load in gear data and populate array for control and selection
{
this.gearDataJSON = gearData;
this.manufacturerNames = gearData.manufacturers;
});
}
DataService
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class GearDataService {
constructor(public http : Http) {}
getGearData()
{
return this.http.get("./assets/gears.json")
.map(res => res.json());
}
}

Suppose that your json was something like-
component.ts
school:any = {
Table:[
{
name: "Steve",
id:"123"
},
{
id:"456"
}
]
};
If you want the output html to look like you suggested you don't really need to match the name but can just use iteration.
component.html
<table>
<tr>
<ng-container *ngFor="let user of school.Table">
<td>{{user.name}}</td>
</ng-container>
</tr>
<tr>
<ng-container *ngFor="let user of school.Table">
<td>{{user.id}}</td>
</ng-container>
</tr>
</table>
Would that suffice?

Related

How to retrieve data from json file in angular 7

This is my doma.component.ts file:
import { Component, OnInit } from '#angular/core';
import {HttpClient} from '#angular/common/http';
#Component({
selector: 'app-doma',
templateUrl: './doma.component.html',
styleUrls: ['./doma.component.css']
})
export class DomaComponent implements OnInit {
constructor(private http:HttpClient) { }
auti=[];
dohvatiPodatke=function(){
this.http.get("http://localhost:9999/auti").subscribe(
(res:Response) => {
this.auti=res.json();
}
)
}
ngOnInit(): void {
this.dohvatiPodatke();
}
}
my doma.component.html:
<h1>Auti</h1>
<table>
<th>Marka</th>
<th>Model</th>
<th>Cijena</th>
<tr *ngFor="let auto of auti">
<td>{{auti.marka}}</td>
<td>{{auti.model}}</td>
<td>{{auti.cijena}}</td>
</tr>
</table>
and my json file:
{
"auti":[
{
"marka": "Mercedes",
"model": "AMG",
"cijena": "200000"
},
{
"marka": "Seat",
"model": "Leon",
"cijena": "150000"
}
]
}
I successfully compiled and ran the project but i only get the table structure with no data in it. Before that i started the json server on my 9999 port and i can access it via localhost/9999/auti. I really don' see what could be the problem here.
Maybe try this :
this.http.get("http://localhost:9999/auti").subscribe(res => this.auti = res)
You are trying to loop over the parent object instead of the child array. Replace this.auti=res.json(); with this.auti=res.json().auti;. So the HTTP callback would look like
this.http.get("http://localhost:9999/auti").subscribe(
(res:Response) => {
this.auti=res.json().auti;
}
)
Keep your json into assets folder
Use relative path to read it:
auti=[];
dohvatiPodatke=function(){
this.http.get("./assests/auti-jsonfile.json").subscribe(
(res:Response) => {
this.auti=res;
}
)
}

Working with data from observable in a component in Angular 6

I am not sure if I have phrased this question correctly, so I apologize for the clunky wording. I am relatively new to angular but am pretty comfortable with making HTTP requests and working with the data in other frameworks (like VueJS). I am beginning to understand the Observables that angular uses. I am trying to make a blog application, and have an express backend that has the JSON for the blog posts.
In my post.service.ts I have:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { Post } from '../post';
#Injectable({
providedIn: 'root'
})
export class PostService {
private apiUrl = 'http://localhost:8081/posts';
getPosts(): Observable<Post[]> {
return this.http.get<Post[]>(this.apiUrl);
}
constructor( private http: HttpClient,
private postService: PostService ) { }
}
And then I want to list all the posts in my post-list.component.ts:
import { Component, OnInit } from '#angular/core';
import { PostService } from '../../services/post.service'
import { Post } from '../../post';
#Component({
selector: 'app-post-list',
templateUrl: './post-list.component.html',
styleUrls: ['./post-list.component.css']
})
export class PostListComponent implements OnInit {
public posts = [];
constructor(private postService: PostService) { }
ngOnInit() {
this.postService.getPosts()
.subscribe(data => this.posts = data);
}
}
But the posts array becomes an object and i'm not sure how to use it as an array. If I try to use the *ngFor method, I get an error. The page shows [object Object] if I put {{posts}} in the html. If i do {{posts | json}} it shows the actual JSON, but I still cannot iterate through it.
This is what the json looks like:
{
"posts": [
{
"_id": "5b04b269fde3ca29b35ffc3e",
"name": "Mike",
"title": "Stuff",
"post": "This is a post about stuff"
},
{
"_id": "5b04b24dfde3ca29b35ffc3d",
"name": "OtherUser",
"title": "New Post Test",
"post": "This is a test post"
},
{
"_id": "5b02ed783aa641758c08e601",
"name": "Emerjawn",
"title": "Post"
}
]
}
Before I try to setup CRUD for this application, I want to simply figure out how to display the data which I still cannot do and it is driving me insane. Thank you in advance for the help.
Your return JSON is an object which has field posts holding your needed array data so just take posts field from your server response and render such array of posts. Something like this:
ngOnInit() {
this.postService.getPosts()
.subscribe(data => this.posts = data.posts);
}
For better typing you can always specify your variable type i.e. public posts: Post[] then you will have type checking while coding.

Angular: Parsing fetched data from firebase with 2 deep level

I'm trying to parse fetched data from firebase at Angular (Typescript).
My JSON data looks like this in firebase:
"customer" : {
"customerId1" : {
"documents" : {
"documentId1" : {
"documentName" : "file1.pdf",
"documentUrl" : "someUrl1"
},
"documentId2" : {
"documentName" : "file2.pdf",
"documentUrl" : "someUrl2"
}
},
"email" : "customet1#email.com",
"name" : "Customer 1",
},
"customerId2" : {
"documents" : {
"documentId3" : {
"documentName" : "file3.pdf",
"documentUrl" : "someUrl3"
},
"documentId4" : {
"documentName" : "file4.pdf",
"documentUrl" : "someUrl4"
}
},
"email" : "customer2#email.com",
"name" : "Customer 2",
}
}
As you can see, each customer has 3 properties, documents, email and name at the first level. At the second level, the document property has nested property documentName and documentUrl.
And for parsing customer data I used the following code.
customer.component.ts:
...
export class CustomerComponent implements OnInit {
customerObservable: Observable<any[]>;
customerList: Customer[];
constructor(db: AngularFireDatabase) {
// Listen to customer data
this.customerObservable.subscribe(data => {
this.customerList = data;
});
}
}
...
With this code I can fetch and iterate data with the ngFor directive at html with customerList variable. The question is, how can I achieve something like this?
// Variable that contains array of an array of customer's document array
documentList: Document[][];
// Or this
// Variable that holds customer's documents
customerDocuments: Document[];
// Where Document model looks like this
export class Document {
public documentName: string;
public documentUrl: string;
}
Thank you for the support.
Here is the service code:
import {Injectable} from '#angular/core';
import {AngularFireDatabase} from 'angularfire2/database';
//rxJS
import {Observable} from 'rxjs/Observable';
import 'rxjs/operator/switchMap';
#Injectable()
export class FirebaseService {
constructor(private angularFireDatabase: AngularFireDatabase) {}
onGetUserDocuments(customer: string) {
return this.angularFireDatabase.list(`customer/${customer}/documents`).valueChanges()
}
onGetUsersDocuments(){
return this.angularFireDatabase.list('customer').snapshotChanges()
.map((changes)=>{
return changes.map((data) => {
return data.payload.key
});
})
.switchMap((usersId: string[]) => {
return Observable.combineLatest( usersId.map((u)=>{
return this.onGetUserDocuments(u);
}))
})
}
}
Then in your component you can call:
import {Component, OnInit} from '#angular/core';
import {FirebaseService} from '../services/firebase.service';
#Component({
selector: 'new',
templateUrl: './new.component.html',
styleUrls: ['./new.component.css']
})
export class NewComponent implements OnInit {
constructor(private firebaseService: FirebaseService) {}
ngOnInit(){
this.firebaseService.onGetUsersDocuments().subscribe(data => console.log(data));
}
}
That will give you:
[Array(2), Array(2)]
0: Array(2)
0: {documentName: "file1.pdf", documentUrl: "someUrl1"}
1: {documentName: "file2.pdf", documentUrl: "someUrl2"}
1: Array(2)
0: {documentName: "file3.pdf", documentUrl: "someUrl3"}
1: {documentName: "file4.pdf", documentUrl: "someUrl4"}
So you can use it like so:
<div *ngFor="let docs of data">
<div *ngFor="let doc of docs">
<p>file name: {{doc.documentName}}</p>
<p>file url: {{doc.documentUrl}}</p>
</div>
</div>
Let me know if you will need any comments thought the code or will have any questions.
P.S. What you really have to now that nesting like this is not recommended by firebase, you should flaten you data. You can read about this here
new docs and here old docs

Displaying linechart using angular2-highcharts

I want to display a line chart from JSON data. I have used angular2-highcharts. The problem is that the chart is displayed without data. I think that the issue is from extracting data from JSON.
The JSON format looks like this:
[{"_id" : ObjectId("59049a7b223f1e21ee4ee23b"),"amount" : 1,"date" :
"Mon, 18 Dec 1995 18:28:35 GMT"},{"_id" :
ObjectId("59049a7b223f1e21ee4ee23b"),"amount" : 1,"date" : "Mon, 18
Dec 1995 19:28:35 GMT"}]
I need only the "amount" in the X value and the "date" in the Y value.
Here is my code
ChartistJs.service.js
import {Injectable} from '#angular/core';
import { Headers, Http, RequestOptions, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { Data } from "./Data";
import 'rxjs/add/operator/toPromise';
private Url ='http://localhost:3000/transfer/chart';
constructor (private http: Http) {}
getData(){
return this.http.get(this.Url)
.toPromise()
.then(response => response.json())
.catch(this.handleError);
}
ChartistJs.component.ts
import {Component} from '#angular/core';
import {ChartistJsService} from './chartistJs.service';
import 'style-loader!./chartistJs.scss';
import { Observable } from "rxjs/Observable";
import { ChartModule } from 'angular2-highcharts';
import 'rxjs/Rx';
import {Observer} from 'rxjs/Observer';
import {Http, Jsonp} from '#angular/http';
#Component({
selector: 'chartist-js',
template: `
<chart [options]="options"></chart>
`,
providers : [ChartistJsService]
})
export class ChartistJs {
options: Object;
constructor(private _chartistJsService:ChartistJsService) {
var chartData = this._chartistJsService.getData();
this.options = {
title : { text : 'simple chart' },
xAxis: {
type: 'category'
},
series: [{
data: chartData
}]
};
}
}
Can you help me how to deal with JSON data in Angular 2?
As Pankaj points out you are trying to pass a promise as the data, not the actual data that the promise eventually resolves to. More broadly, though, you aren't really using the tooling that Angular provides for dealing with HTTP.
In general, I would recommend that you:
Get used to dealing with observables, which is what Angular uses natively, rather than converting everything back to promises (although I think they still show this in the docs); and
Lean into the asynchronous nature of the observables, using the AsyncPipe to resolve them into your templates and the objects that RxJS provides to manipulate the data flow.
More specifically, here's one way you could implement what you're currently trying to.
Service:
#Injectable()
class DataService {
// acts as a pipe for the data that you can push new items into
private dataSubject = ReplaySubject(1);
// takes the subject and exposes the result, read-only
chartData$ = this.dataSubject.asObservable();
constructor (private http: Http) {}
getData() {
// GETs the data and pushes it into the subject
this.http.get('http://localhost:3000/transfer/chart')
.map(response => response.json())
.subscribe(data => this.dataSubject.next(data));
}
}
Component:
#Component({
... ,
// resolves the chart options asynchronously in the template
template: `
<chart [options]="chartOptions$ | async"></chart>
`
})
export class MyChartComponent implements OnInit {
chartOptions$: Observable<any>;
constructor(dataService: DataService) {
// creates a new observable of the chart options
this.chartOptions$ = this.dataService.chartData$
.map(data => this.createChartOptions(data));
}
ngOnInit() {
// triggers a fetch of the data to feed the observable
this.dataService.getData();
}
private createChartOptions(data) {
return {
title: { text: 'simple chart' },
xAxis: { type: 'category' },
series: [{ data: data }],
};
}
}
You will probably need to do more to the JSON than just pass it as the series.data, but this hopefully gives you an idea of how to leverage the stream of events an observable can provide. I've written more about this on my blog, including a follow-up article on testing.
Also note that your components shouldn't be importing anything from '#angular/http' - leave that to the services, use them as a layer of abstraction from the source of the data - and you can load providers at the module, rather than component, level.
Actually chartData variable does hold Promise returned by getData method. Where you should keep .then over the getData method calla and assign options with chartData like shown below.
It would be more better if you can do the same in ngOnInit lifecycle event.
Code
export class ChartistJs {
options: Object;
constructor(private _chartistJsService: ChartistJsService) {}
ngOnInit() {
this._chartistJsService.getData().then(
(data) => {
this.options = {
title: {
text: 'simple chart'
},
xAxis: {
type: 'category'
},
series: [{
data: data
}]
};
}
);
}
}

Output array values to template

I'm currently learning Angular 2 and have confused myself with how to output data returned from a service to my template.
My API Response :
{
"site": {
"success": true,
"title": "foo",
"description": "bar"
}
}
My Service :
import { Injectable } from '#angular/core';
import {HTTP_PROVIDERS, Http, Response, Headers, RequestOptions } from "#angular/http";
import { Observable } from 'rxjs/Rx';
#Injectable()
export class ContentService {
constructor(private _http:Http) {}
getContent() {
return this._http.get('http://localhost:8080/api/foobar-endpoint/')
.map((res:Response) => res.json())
}
}
My Component :
import { Component, OnInit } from '#angular/core';
import { ContentService } from "../../services/content/content.service";
const template = require('./home.jade');
const styles = require('./home.sass');
#Component({
selector: 'home',
templateUrl: template,
styleUrls: [styles]
})
export class HomeComponent implements OnInit {
public foo = {}
constructor(private _contentService: ContentService) {}
ngOnInit() {
this.getContent();
}
getContent() {
this._contentService.getContent()
.subscribe(
data => {this.foo = data},
err => { console.log(err) },
() => console.log()
);
}
}
My Template :
pre
p {{ foo.site.title }}
If I place {{ foo | json }} in my template I can see the returned values in a JSON format, but when I try and output a single value, such as title I get undefined errors.
How can I access the values being returned?
I think the only thing you are missing here is the ?. Basically the problem is that when the components instantiates your foo property has no site param so angular throws the error.
So what you can do is either this:
{{foo.site?.title}}
Or this:
<p *ngIf="foo.site">{{foo.site.title}}</p>
This way angular won't try to bind the title before there is a site.