How to load this JSON data into Angular2 - javascript

Im new to Angular2, I want to load this Json data and display in a page, Im not sure how to do..? From all sources I learnt I made a code and attached it below, But its not running because of some errors, can anyone help in fixing or writing a new code for me so that i can learn from it..
Thanks in advance for the help.
My code file - student.json
[
{
"name": "John",
"id_number": "12",
"attendance": "276 days",
"grade": "A"
},
],
this is my students.service.ts code
import {Injectable} from '#angular/core';
import { Http, Response } from '#angular/http';
#Injectable()
export class StudentsService {
constructor(private http:Http)
{
}
getStudents() {
return this.http.get('./students.json')
.map((response: Response) => {
console.log("mock data" + response.json());
return response.json();
}
}
and, this is my students.component.ts file
import {Component} from '#angular/core';
import { Http, Response } from '#angular/http';
import {StudentsService} from './students.service';
import 'rxjs/add/operator/map'
import 'rxjs/Rx';
#Component({
selector: 'students',
templateUrl: 'students.html',
styleUrls: ['./students.scss']
})
export class students {
public students;
constructor( private _studentsService:StudentsService, private http:Http)
{
this.students = this._studentsService.getStudents();
}
ngOnInit() {
this._load();
}
private _load() {
this.students = this._studentsService.getStudents();
}
}

You can write a service to load your html from json file and available all over your application like below.
#Injectable()
export class ConfigService {
public config: any;
private configObs: Observable<any>;
constructor(private http: Http) {
}
public load(filename: string): Observable<any> {
if ( this.config ) {
return Observable.of(this.config);
} else {
this.configObs = this.http.get(filename).map((res) => {
this.config = this.config || res.json() || {};
return this.config;
});
}
return this.configObs;
}
}
You can also put your data in typescript class format if that option is available referance answer

If you have JSON data and you want to show it in page.
Use Data Table to show It.
Here is the example you can see how to show on page.
Please click Here

Assign our json to a varible
myData = [{
"name": "John",
"id_number": "12",
"attendance": "276 days",
"grade": "A"
},
...
...
],
In your Html
<ul>
<li *ngFor="let data of myData">
<div>{{data.name}}</div>
<div>{{data.id_number}}</div>
<div>{{data.attendance}}</div>
<div>{{data.grade}}</div>
</li>
</ul>
Hope it helps

What you are dealing with is an Observable students, either you need to manually subscribe to that observable, or use the async pipe in the template which handles the subscribing for your.
Also you are now performing the request twice, in the constructor and in your OnInit. Remove one of those, I'd remove the one in the constructor, since I like to keep everything away from the constructor, that does not need to be there, like mentioned here: https://stackoverflow.com/a/35763811/6294072
Back to the subscribing... either do:
this.students = this._studentsService.getStudents();
<div *ngFor="let student of students | async">
<p>{{student.name}}</p>
<!-- ... -->
</div>
or:
this._studentsService.getStudents()
.subscribe(students => {
this.students = students;
})
<div *ngFor="let student of students">
<p>{{student.name}}</p>
<!-- ... -->
</div>

Related

angular *ngFor from json

I am new to angular. Let me first give an overview of what i am trying to achieve because this is a long code I am showing the relevant part.
I have a list display component.
And I have (lets say 2) components animals, zone.
Lets say :
zone has 2 columns zone name and zone code,
animals has 3 columns animal code, animal name, animal zone
and so on (lets say for 10 other components)
each component will generate JSON and send it to display list component.
display list will parse the JSON and display it with ngFor
in short :
each component will make JSON and send it to service , which has behavior subject
service has behavior subject, that will receive that JSON
display component will get the latest json from service's behavior subject
finally display component will parse json and will display them using ngfor
My generating and sending JSON to display list component is ok.
For example, I will show you the JSON of zone component that is send to display component.
I need your help to process the JSON so that I can display it using ngFor on display component html.
Code:
data.service.ts:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class DataService {
private messageSource = new BehaviorSubject(null);
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: any) {
console.log('changed');
console.log(message);
this.messageSource.next(message);
}
}
for zone (zone.component.ts) : [car.component.ts is as same as zone.component.ts don't get confused]
import { Component, OnInit } from '#angular/core';
import { DataService } from "../../services/data.service";
import { Router } from '#angular/router';
#Component({
selector: 'app-cars',
templateUrl: './cars.component.html',
styleUrls: ['./cars.component.css']
})
export class CarsComponent implements OnInit {
jsonData: any;
data: any;
constructor(private router: Router, private dataService: DataService) {
}
dd() {
this.setData(this.jsonData);
}
ngOnInit(): void {
this.setJsonData();
}
async getJsonData() {
const myurl: string = "http://localhost:3000/zone/get/all";
const response = await fetch(myurl, { headers: { 'Content-Type': 'application/json' } });
return await response.json();
}
async setJsonData() {
this.jsonData = await this.getJsonData();
}
setData(newJsonData: any) {
this.data = Object.entries(newJsonData);
}
navigateToDisplayList(){
this.router.navigateByUrl('display-list');
}
newMessage() {
this.dataService.changeMessage(this.jsonData);
// console.log(this.jsonData);
// console.log(this.data);
this.navigateToDisplayList();
}
}
for display : display-list.component.ts :
import { Component, OnInit } from '#angular/core';
import { DataService } from "../../services/data.service";
#Component({
selector: 'app-display-list',
templateUrl: './display-list.component.html',
styleUrls: ['./display-list.component.css']
})
export class DisplayListComponent implements OnInit {
data: any;
constructor(private dataService: DataService) { }
ngOnInit(): void {
this.dataService.currentMessage.subscribe(message => this.data = message);
}
dd(){
console.log(this.data);
document.body.innerText = this.data.toString();
}
}
A special note :
Please don't think I haven't researched it yet just because I am not posting the display-list.html
LOOK MY ALGORITHM IS SIMPLE :
OUTER LOOP FOR EACH ROW
INNER LOOP FOR EACH COLUMN
THAT IS IT. I DON'T NEED ANYTHING ELSE IN HTML
I have tried this approach :
<tr *ngFor="let x of data">
<td *ngFor="let y of x">
{{y}}
</td>
</tr>
Each time I am getting error: ngFor is not a known property
(which is funny: If I just comment the ngfor error is gone
or
If I just ngfor on a static array like 1,2,3,4,5 no error there )
Some other time : data can not be iterated
(another funny thing: clearly my JSON can be iterated and no quotation or bracket is missing)
I simply don't get it why angular can't iterate this thing
JSON for zone list :
[
{
"zonecode":3,
"zonename":"d"
},
{
"zonecode":4,
"zonename":"d"
},
{
"zonecode":15,
"zonename":"kk"
}
]
Another very special note :
You don't need to post an answer or comment if you are suggesting capture the JSON in a variable then just loop on console.log(object.zonename) .
Because I have no control over JSON, I have lets say 30 other components where no zonename is there. I have to display in HTML directly from JSON
updating my answer based on comments....I understand that you want to access the key value pairs inside the object and this can be done as below
<tr *ngFor="let x of data">
<td *ngFor="let y of x | keyvalue">
{{y.key}}:{{y.value}}
</td>
</tr>

Making ajax call from a component to a service and access response from another component

I am learning Angular2 by creating an example where I want to have a button click on Component1 that makes an ajax call to a Service and the response of the ajax should be used and displayed in another component.
I am able to create the Component1 and able to get the response by making ajax call in Service class. Now how can I display the result in another component
This is my first component:
import { Component } from '#angular/core';
import { ProfileService } from '../shared/index';
#Component({
selector: 'home-page',
template: `
<div>
<button (click)="loadUser()">Load profile</button>
{{ profile | json }}
</div>
`
})
export class ProfileComponent {
constructor(private profileService: ProfileService) {}
profile = {};
loadUser() {
this.profileService.getUser().subscribe(data => this.profile = data);
}
}
This is my service class:
import { Injectable } from '#angular/core';
import { HttpClient, Response } from '#angular/common/http';
import 'rxjs/add/operator/map';
#Injectable()
export class ProfileService {
constructor (
private http: HttpClient
) {}
getUser() {
return this.http.get(`https://conduit.productionready.io/api/profiles/eric`)
.map(res => res );
}
}
This is my second component where I want to see the result:
import { Component } from '#angular/core';
#Component({
selector: 'result-page',
template: `
<div>Result Page :
{{ profile | json }}
</div>
`
})
export class ResultComponent {
constructor(private profileService: ProfileService) {}
profile = {};
username = "";
bio = "";
}
Basically the ajax response is a Json content, I want to store whole json in profile file. This json contains fields for username and bio, I want to store them in my variables username and bio of my result component.
I am stuck how to build my result component, can you please help me.
I am want to communicate between components, don't want to use any routers here.
The json response is :
{
"profile": {
"username": "eric",
"bio": "Cofounder of Thinkster.io, kinda looks like Peeta from the Hunger Games",
"image": "http://i.imgur.com/S66L2XZ.jpg",
"following": false
}
}
Edit: If the component you are trying to pass the data to is the child of that component you can use the #Input decorator to pass the data to it. The #Input will automatically register the changes and update the template. If you need to do any update functions when this input changes you can use ngOnChanges, but if you are simple displaying the changes you can just use the #Input and it will update the view accordingly.
If the two components are both children of a shared parent you can use the #Ouput decorator on the component1 to output the data to the parent and set the variable that is being passed into the Input of the other.
in results component
export class ResultComponent implements OnChanges {
#Input results: any;
constructor(private profileService: ProfileService) {}
ngOnChanges(changes: SimpleChanges) {
if(changes['profile'] && changes['profile'].currentValue){
// do any update functions here if needed
}
}
profile = {};
username = "";
bio = "";
}
and in the profile template
<results-page [profile]="profile"></results-page>
in component1 if that component is also a child
export class ProfileComponent {
#Ouput() emitProfile = new EventEmitter<any>()
constructor(private profileService: ProfileService) {}
profile = {};
loadUser() {
this.profileService.getUser().subscribe(data => this.profile = data);
}
}
and then in the parent you would handle the data emit like so:
handleEmitProfile(profile) { this.profile = profile }
option 2 - add another function in the service.
#Injectable()
export class ProfileService {
constructor (
private http: HttpClient
) {}
private profile$ = new Subject();
getUser() {
return this.http.get(`https://conduit.productionready.io/api/profiles/eric`) .map(res => res );
}
returnProfile() {
return this.profile$;
}
updateProfileObject(event) {
this.profile$.next(event);
}
}
in your results component add this:
this.profileService.returnProfile().subscribe(event => this.profile = event}
and in your profile component
this.profileService.updateProfileObject(this.profile);
and that function will update the profile$ variable in the service calling the function in the results component.

Format httpclient response for *ngFor?

Hi I was wondering if anyone could help me solve a small problem.
I am received data from my rest api which is returned as an array with objects inside.
Once I get it to my service I try to transform the data and push it to a subject so that it can inform my component that the data is here or updated.
When i console.log the data I get
0:{code: "AUH", name: "Abu Dhabi"}
1:{code: "ALY", name: "Alexandria"}
2:{code: "LTS", name: "Altus"}
3:{code: "ANK", name: "Ankara"}
4:{code: "AIY", name: "Atlantic City"}
5:{code: "BAK", name: "Baku"}
6:{code: "BKK", name: "Bangkok"}
7:{code: "EAP", name: "Basel"}
8:{code: "BJS", name: "Beijing"}
So when I try and use my *ngFor I get [object]p[Object]
How can I format this to work with *ngFor?
city-list.component.html
import { CityService } from "./services/city-list.service";
import { Component, OnInit, OnDestroy } from "#angular/core";
import { City } from "../cities/models/city";
import { Subscription } from "rxjs";
#Component({
selector: "<app-cities></app-cities>",
templateUrl: "./city-list.component.html"
})
export class CityListComponent implements OnInit, OnDestroy {
cities: City[];
private citiesSub: Subscription; // so as to unsubscribe if page changes/ memory leak
constructor(public cityService: CityService) {}
ngOnInit() {
this.cityService.getCities();
this.citiesSub = this.cityService
.getCityUpdateListener()
.subscribe((cities) => {
this.cities = cities;
});
// 1st value: when data emit 2nd value: error emit, 3rd value function for when no more data is available
}
ngOnDestroy() {
this.citiesSub.unsubscribe();
}
}
// subject is an observable but you can call next on them to emit a change when you want
"service"
import { Subject } from 'rxjs';
import {Injectable} from '#angular/core';
import {HttpClient} from '#angular/common/http';
import { map } from "rxjs/operators";
import {City} from '../models/city';
#Injectable()
export class CityService {
cities: City[] = [];
private updatedCities = new Subject<City[]>();
constructor(private http: HttpClient) {}
getCities() {
this.http.get<{message: string; cities: City[]}>('http://localhost:3000/cities')
.pipe(
map((cityData)=>{
return cityData.cities.map(city=>{
return{
code: city.code,
name: city.name
};
});
})
)
.subscribe((transCity) => {
this.cities = transCity;
console.log(this.cities);
this.updatedCities.next([...this.cities]);
});
}
getCityUpdateListener() {
return this.updatedCities.asObservable();
}
}
You can just use the json pipe:
<div *ngFor="let item of response">{{ item | json }}</div>
If you want to display it in "pretty" instead of as json, you need to access the individual fields of the item and format it in the desired way.
try as below , first get keys form reponse object you are receiving from http call and then go through each key in html , might resole your issue
in ts file
//response is data you received after making http call, list of cities in your case
keys = Object.keys(response);
in html file
<div *ngFor="let key of keys">
{{response[key].code }} {{response[key].name }}
</div>
this should work based on response you are getting from server
It looks like the issue here is that you're not actually returning an array of City, instead you're returning a dictionary or Map<City>. You'll probably want to iterate over your response and map it to the correct type.
this.citiesSub = this.cityService
.getCityUpdateListener()
.subscribe((cityMap) => {
this.cities = [ ...cityMap.values() ]
});
Asuming you are using httpClient(new released in angular5) then there is no need of the map() and pipe() functions, results are mapped to json by default you just have to subscribe to the service
this is how it would look your new service class
import { Subject } from 'rxjs';
import {Injectable} from '#angular/core';
import {HttpClient} from '#angular/common/http';
import { map } from "rxjs/operators";
import {City} from '../models/city';
#Injectable()
export class CityService {
cities: City[] = [];
private updatedCities = new Subject<City[]>();
constructor(private http: HttpClient) {}
getCities() {
return this.http.get<City[]>('http://localhost:3000/cities')//http.get<any> also work but for type safety i am asuming City[] array have the same structure.
}
getCityUpdateListener() {
return this.updatedCities.asObservable();
}
}
Then in your component you would have to subscrive to that service and use it
constructor(public cityService: CityService) {
this.cityService.getCities().subscribe(cities => {
this.cities = cities;
console.log(cities);
}, error=> {console.log(error)});//handling errors
}
ngOnInit() { } // just moved the service call to the constructor of the component
I hope this solve your problem,
Thanks

getting json data into an array angular2

I am not sure what i am missing from my code but currently i am not presented with any errors when i run it but i am also not seeing the results that i am expecting. I have a json file that i am loading into an array and would like to loop through that array and display parts of its data onto the page.
Here is what i have so far:
Service file
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
#Injectable()
export class AddressDataService{
addressData: Array<any>;
constructor(private http:Http){ }
getAddressData(){
return this.http.get('./api/addressData.json')
.map((res:Response) => res.json());
}
}
JSON File
[{
"type": "home",
"id": 1
}, {
"type": "apartment",
"id": 2
}, {
"type": "homeless",
"id": 3
}]
Component File
import { Http } from '#angular/http';
import { AddressDataService } from './address.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
#Component({
selector: 'my-app',
templateUrl: '....',
styleUrls: ['./styles.css'],
providers: [AddressDataService]
})
constructor(private addressDataService: AddressDataService) {}
addressData = [];
getAddressData() {
this.addressDataService.getAddressData()
.subscribe(data => this.addressData = data);
}
HTML File
<div *ngFor="let addressDetail of addressData">
{{addressDetail.type}}
</div>
Am i doing this the right way?
You need to call your getAddressData for example in your OnInit, I assume you want to fetch the data when navigated to page.
So:
ngOnInit() {
this.getAddressData();
}
When this is handled, you will face another issue. Http-requests don't allow relative paths, so
return this.http.get('./api/addressData.json')
will cause an error, you need to replace the dot in your "url" with the actual complete path for the json file, starting from the top level folder.
In your component file:
.subscribe(
data => {
const helperArray = [];
for (let key in data) {
helperArray.push(data[key]);
}
}
);
Something in your component class needs to call your getAddressData method. Either the constructor, or a better option is to implement OnInit and call it from there.

Angular 2 *ngFor doesn't display data

I'm working on an application using Ionic 2 together with Angular 2. Now I'm trying to the data from an API and display this on a page.
I can log the data and I think it's correct, but for some reason nothing is being displayed on the page itself:
The API where I'm receiving the data from is located here: http://peerligthart.com/grotekerk/v1/api.php/zerken?transform=1
*ngFor on my view
<ion-content padding>
<h1 *ngFor="let z of zerken">
{{ z.naam }}
</h1>
</ion-content>
Controller
import { Component } from '#angular/core';
import { NavController, PopoverController } from 'ionic-angular';
import { PopoverPage } from '../popover/popover';
import { ZerkenProvider } from '../../providers/zerken';
#Component({
selector: 'page-lijst',
templateUrl: 'lijst.html',
providers: [ZerkenProvider]
})
export class LijstPage {
zerken: Array<any>;
constructor(public navCtrl: NavController, public popoverCtrl: PopoverController, public zerkenProvider: ZerkenProvider) {
this.zerkenProvider.getZerken().subscribe(
data => {
console.log(data.zerken);
this.zerken = data.zerken.results;
}
)
}
openPopover(event) {
let popover = this.popoverCtrl.create(PopoverPage);
popover.present({
ev: event
});
}
}
And last, the provider
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class ZerkenProvider {
static get parameters() {
return [[Http]];
}
constructor(public http: Http) {
}
getZerken() {
var url = "http://peerligthart.com/grotekerk/v1/api.php/zerken?transform=1";
var response = this.http.get(url).map(res => res.json());
    
return response;
}
}
So, what the page is displaying itself:
As you can see.. nothing. I hope someone has a solution, kind regards!
-------------EDIT-------------
I changed this.zerken = data.zerken.results to this.zerken. After doing this it's giving me an error:
Your zerken in your response doesn't seem to have an results object, so
this.zerken = data.zerken.results;
should be:
this.zerken = data.zerken;
Remember to initialize the array in your component:
zerken: Array<any> = [];
so that you won't get an error that zerken is undefined, since view is usually rendered before data has been received. Having it initialized will prevent that.
You need an *ngIf encapsulating the *ngFor since zerken is obtained at a later point of time.
Try:
<ion-content padding>
<div *ngIf="zerken">
<h1 *ngFor="let z of zerken">
{{ z.naam }}
</h1>
</div>
</ion-content>
Also you need to set zerken = data.zerken; as mentioned in the other answer by #AJT_82.

Categories

Resources