How do i handle JSON Data in Angular 2? - json

Hi I am new to Angular and I have been trying to learn Angular 2 so be gentle :).
I have been trying to use WordPress as my data API using WP API plugin. And have so far been able to get posts from WordPress. And below is my code for the data service.
import {Injectable} from "angular2/core";
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Rx';
import {PostInterface} from './data.interface';
import {Headers} from "angular2/http";
import {RequestOptions} from "angular2/http";
#Injectable()
export class DataService{
private _dataURL : string = 'http://localhost/wordpress/?rest_route=/wp/v2/posts';
posts : PostInterface [];
post : PostInterface;
errorMessage : string;
constructor(private http:Http){}
getPosts():Observable<any[]>{
//return this.http.get(this._dataURL).map((res:Response) => res.json());
return this.http.get(this._dataURL)
.map(res=>res.json())
//.do(data => console.log(data)) // eyeball results in the console
.catch(this.handleError);
}
//todo fix search
getPost(filterid:number):Observable<any[]>{
//filterid is the id of a specific post
this._dataURL = this._dataURL + '/' + filterid;
return this.http.get(this._dataURL)
.map(res => res.json())
.catch(this.handleError);
}
private handleError (error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
In the code I get all the post data using the getPosts() method but I also have a getPost() method to fetch specific post.
I was wondering if I could use the JSON data fetched by getPosts() and use it again in getPost() method. Currently what the getPost() does is call the http.get again I do not want to make http.get request again and again.
I want the getPosts() to make one request, fetch the data and store is somewhere so that other methods can use the data and do their specific manipulations.
Thanks

Yes you can firstly fetch your all data and save into one variable or another methods is where you subscribing your data perform for loop and match with your filterId where the process matches store that data into array and implement your manipulation according to need. here is example assuming your data is in array form..
import {Injectable} from "angular2/core";
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Rx';
import {PostInterface} from './data.interface';
import {Headers} from "angular2/http";
import {RequestOptions} from "angular2/http";
#Injectable()
export class DataService{
private _dataURL : string = 'http://localhost/wordpress/?rest_route=/wp/v2/posts';
posts : PostInterface [];
post : PostInterface;
errorMessage : string;
constructor(private http:Http){}
getPosts():Observable<any[]>{
//return this.http.get(this._dataURL).map((res:Response) => res.json());
return this.http.get(this._dataURL)
.map(res=>{
if(res.json()){
return res.json()
}
});
//.do(data => console.log(data)) // eyeball results in the console
.catch(this.handleError);
}
// Method in any file where you want to subscribe your data and wanna fetch specific post //
singlePost: Array<any>= [];
methodName(filterid:number){
service.getPosts()
.subscribe(res=>{
console.log(res) // Here you data whihc is coming from .map i.e getPosts methods using Http
for(let i=0; i< res.length ; i++){ // I am asuming your data is in array from so performing length functionality
if(filterid == res[i].filterid){
this.singlePost = res[i];
break;
}
}
console.log(this.singlePost) // This will return your single Specific POst without using `Http` again and again
})
}

You could try something like that using the do operator to save the data into your service when the getPosts result is received:
#Injectable()
export class DataService{
private _dataURL : string = 'http://localhost/wordpress/?rest_route=/wp/v2/posts';
posts : PostInterface [];
post : PostInterface;
errorMessage : string;
constructor(private http:Http){}
getPosts():Observable<any[]>{
//return this.http.get(this._dataURL).map((res:Response) => res.json());
return this.http.get(this._dataURL)
.map(res=>res.json())
.do(data => this.posts = data) // <--------
.catch(this.handleError);
}
findPostById(id) {
if (this.posts != null) {
return this.posts.find(((element, index, array) {
return (element.id = id);
});
} else {
return null;
}
}
getPost(filterid:number):Observable<any[]>{
var post = findPostById(filterid);
if (post != null) { // <--------
return post;
} else {
this._dataURL = this._dataURL + '/' + filterid;
return this.http.get(this._dataURL)
.map(res => res.json())
.catch(this.handleError);
}
}
Feel free to adapt this code to your needs.

Related

Angular 2: Error while accessing JSON from HTTP

I am creating an application in angular 2. I am trying to access the json data via http in a service. But i am getting an error saying that
**GET http://localhost:4200/data/products.json 404 (Not Found)**
I have the data in the specified folder but i am unable to access it.
My service code is as follows.
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';
import { Item } from './item';
#Injectable()
export class ItemService {
observableItems: Observable<Item[]>
allItems: Item[] = [];
selectedItems: Item[] = [];
errorMessage: string;
url = "http://localhost:4200/data/products.json";
constructor(private http:Http) {
this.observableItems = this.http.get(this.url).map((res: Response) => res.json());
this.observableItems.subscribe(
data => this.allItems = data,
error => this.errorMessage = <any>error);
}
getItems(): Observable<Item[]> {
return this.observableItems;
}
getSelectedItems(): Item[] {
return this.selectedItems;
}
addItem(id:number): void {
let item = this.allItems.find(ob => ob.id === id);
if (this.selectedItems.indexOf(item) < 0) {
this.selectedItems.push(item);
}
}
removeItem(id:number): void {
let item = this.selectedItems.find(ob => ob.id === id);
let itemIndex = this.selectedItems.indexOf(item);
this.selectedItems.splice(itemIndex, 1);
}
}
My html files are in
"Project/src/app/..."
So to access JSON File I need to come back from tabs folder and app folder to reach the base directory for both code and images. I used ../ to come back from a folder.
From this my url in the service will be as follows:
url = "../../assets/data/products.json";
Try using direct path to the file from the location of your service file. For example:
url = "data/products.json";
It will work.

Angular 2 method is not subscribing to the observable

I'm trying to get JSON data using a Service class.
Service class
import { Injectable }     from '#angular/core';
import { Http, HttpModule, Response } from '#angular/http';
import { GeneralTab }     from './generalTab';
import 'rxjs/Rx';
import { Observable }     from 'rxjs/Observable';
#Injectable()
export class GeneralTabService {
     constructor(private _http : Http) {
        console.log("Http call");
    }
getStatus(): Observable<any> {
    return this._http.get('http://samd.server.lan.at/taskmanagement/rest/taskconfigs/IND?language=EN&access_token=200')
         .map((res:Response) => <GeneralTab[]>res.json())
         .do(data => console.log("All: " +  JSON.stringify(data)))
.catch(this.handleError);
}
private handleError (error: any) {
    
    let errMsg = (error.message) ? error.message :
        error.status ? `${error.status} - ${error.statusText}` : 'Server error';
        return Observable.throw(errMsg);
}
}
Component class
import { Component, OnInit } from '#angular/core';
import {GeneralTab} from "./generalTab";
import {GeneralTabService} from "./generalTab.service";
import { Observable } from 'rxjs/Observable';
#Component({
    selector: 'general-tab',
    templateUrl: '/general.component.html',
    providers : [GeneralTabService]
})
export class GeneralComponent implements OnInit{
    title = 'Serving data from General Component';
    errorMessage: any;
    status: GeneralTab [];
    mode = 'Observable';
    constructor (private generalService: GeneralTabService) {
        this.status = [];
    }
    ngOnInit() {
        console.log("Started");
        this.generalService.getStatus().subscribe(
            (status: any) => this.status = status,
            (error: any) =>  this.errorMessage = error
        );
        console.log(this.status);
    }
}
GeneralTab class
export class GeneralTab {
    constructor(public recipientId : string,
    public recipientName: string,
    public recipientFullname: string,
    public ouId:String,
    public ouName:String,
    public institute:number,
    public shortName:String,
    public status:String)
    {
    }
}
I see in the console that .do(data => console.log("All:" +  JSON.stringify(data))) is getting me JSON data like
{"subjectsConfig":[{"subject":"Client Data Maintenance","preselected":false,"initialDueDate":"2016-11-24","actionConfigs":[{"action":"SEND","recipients":[{"user":{"recipientId":"BD27A4F5923FCA13","recipientName":"ABTABT","recipientFullname":"ABTABT","ouId":"BD27A4F5923FCA13","ouName":"0015",....
Subscribe is not assigning any data to status array and I'm getting blank "status" array. I want this data as an array in status variable for testing purpose. How do I get?
If you log the response like
console.log("Started");
this.generalService.getStatus().subscribe(
(status: any) => this.status = status,
(error: any) => this.errorMessage = error
);
console.log(this.status);
Of course you will see a blank status since the above code(getStatus().subscribe) is async. Meaning you are making a request then you are waiting for the response inside subscribe and when it comes, you will assign status to this.status. While waiting you are already logging(this.status) which is initially blank.
Instead try this and check the log,
console.log("Started");
this.generalService.getStatus().subscribe(
(status: any) => {
this.status = status;
console.log(this.status);
},
(error: any) => this.errorMessage = error
);

Accessing JSON in Angular2

I'm having a tough time understanding how to access different aspects of an JSON object in Angular2. Particularly, I have a web API that I built that returns the following JSON object regarding the hard drive details on my server:
The image is a screenshot of my console in Chrome after using an httpService and Observable to push it to the console but understanding how to get to a specific piece of info is getting lost on me.
If someone could point me in the right direction, it would be greatly appreciated.
After having subscribed to the http Observable you have already got the actual object.
Assuming your http get request looks like this:
this.httpService.get(this.apiUrl);
you can use the power of rxjs Observables, for example map over the object like this:
this.httpService.get(this.apiUrl)
.map(res => res.json())
.map(body => body.Data)
.map(data => data[0].AvailableSpace)
which after subscribing to would return the AvailableSpace.
.subscribe(availablespace => console.log(availablespace);
Watch out for accessing arrays like this, this is just to give you an example on how to access and manipulate objects in observables.
Check this site out for more information on different observable
operators, other than map.
https://www.learnrxjs.io/
Let me try my luck. Hope it will help people understand better. Particularly, I will talk about how to perform get request in Angular 2. It is always better to have a get and post request in a separate file called service.ts as mentioned in the official documentation.
We will have three files, namely example.component.ts, example.service.ts and Model file examplemodel.ts
example.component.ts
import {OnInit, Component} from "#angular/core";
import {ExampleService} from "./example.service"; // import service
import {ResponseFromGet, ErrorMessage} from "./examplemodel"; // import your model
#Component({
providers: [ExampleService], // add your service here in order to use in component file
templateUrl: './example.template.html'
})
export class ExampleComponent implements OnInit{
//Specify Url for Get request
Private _getRequestUrl = "http://entergetrequesturlhere";
// Make variable for stroing get method reponse which can be used in ur template file
responseFromGetMethod: ResponseFromGet; // this can be ur model file which represnts ur JSON model
// For storing Error
errorMessage: ErrorMessage;
//use Constructor to inject your service in component file
constructor(private _exampleService: ExampleService){}
// Since we implemented OnInit we need to override its method ngOnInit
// this method is called when page is loaded
ngOnInit(): any{
this.callGetMethod(this._getRequestUrl);
}
// callGetMethod outside OnInit but inside class ExampleComponent
callGetMethod(getUrl: string){
this._exampleService.getMethodName(getUrl)
.subscribe(
responseFromGetMethod => {
this.responseFromGetMethod = responseFromGetMethod; // Store response from getmethod in your local variable
},
error => this.errorMessage = <any>error // Store error message receiver from server
);
}
}
example.service.ts
import {Http, Response} from "#angular/http";
import {Injectable} from "#angular/core";
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import {ResponseFromGet} from "./examplemodel";
#Injectable()
export class ExampleService{
constructor(private _http: Http) { }
// GET request To access data and specify observable type from model
getMethodName(getUrl): Observable<ResponseFromGet>{
return this._http.get(getUrl)
.map(this.extractData) // to check for the status code
.catch(this.handleError); // to check error
}
// Extracts from response
private extractData(res: Response) {
if (res.status < 200 || res.status >= 300) {
throw new Error('Bad response status: ' + res.status);
}
let response = res.json();
return response || {};
}
// To handle Error
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json() || 'Server error');
}
}
examplemodel.ts
export interface ResponseFromGet{
id: number;
name: string;
}
export interface ErrorMessage{
message: string;
}
And finally the HTML file
example.template.html
<div>
<h2>{{responseFromGetMethod?.name}}</h2> // this will print the name from the json file
<h3>{{errorMessage?.message}}</h3> // this will print the error if any
</div>
Lastly, this is the model of my JSON file
{
"id": 789;
"name": "Angular2";
}

Angular 2 http service

I'm learning Ang2. I ran the Hero tutorial successfully. to practice, I just added a link in the main page to a get a new component. there is a json file with a list of Radio Station. the following are my service, and the Component:
import { Radio } from '../models/radio';
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/Rx';
#Injectable()
export /**
* RadioService
*/
class RadioService {
radios: Radio[] = [];
len: Number = 0;
http: Http;
constructor(http: Http) {
this.http = http;
}
getRadios() {
console.log('Radios Service is being called');
this.http.get('app/mock/FranceRadioJSON.json')
.map((res: Response) => res.json())
.subscribe((rad: Radio[]) => { // Succes
console.log('Radios Service Success');
this.radios = rad;
this.len = rad.length;
}
, err => {// Failure
console.log('Radio Services Failure');
console.error(err);
}
, // complete
() => {
console.log('Get Radios Complete');
console.log('Records NB: ' + this.len);
console.log('radios nb: ' + this.radios.length)
}
)
;
return this.radios;
}
and the Component is:
import { Component, OnInit } from '#angular/core';
import { RouteParams } from '#angular/router-deprecated';
import { Radio } from '../../models/radio';
import { RadioService } from '../../services/radio.service';
#Component({
selector: 'radio'
, templateUrl: 'app/html/radio.component.html'
, providers: [RadioService]
})
export /**
* RadioComponent
*/
class RadioComponent {
radios: Radio[] = [];
constructor(
private radioservice: RadioService) {
}
getRadios() {
this.radios = this.radioservice.getRadios();
console.log('radio component NB: ' + this.radios.length);
}
ngOnInit() {
this.getRadios()
}
}
the problem is the call of service is coming first, and no Radio is return while when the service is called with console.log I see that's is successful and get all records from JSON file. Any help would be greatly appreciated.
You can't get data this way from async calls (which is when you use Promise or Observable). Http returns and Observable. You need to subscribe() and in the callback you pass to subscribe(...) you get the data and can assign it to local properties.
And example how you can solve this:
In getRadios we don't call subscribe() and use map() instead. map() returns an Observable which allows the caller to get the data. subscribe() returns a Subscription and doesn't allow to get the response data, it only allows to cancel the subscription (which is also often handy, but not now ;-) ).
getRadios() {
console.log('Radios Service is being called');
return this.http.get('app/mock/FranceRadioJSON.json')
.map((res: Response) => res.json())
.map((rad: Radio[]) => { // Succes
console.log('Radios Service Success');
this.radios = rad;
this.len = rad.length;
});
}
We subscribe in getRadios because here we want to get the data. When we subscribe, the map() calls in getRadios are executed as well. subscribe() makes the Observable actually do its work:
getRadios() {
this.radios = this.radioservice.getRadios()
.subscribe((radios) => {
this.radios = radios;
} , err => {// Failure
console.log('Radio Services Failure');
console.error(err);
} , // complete
() => {
console.log('Get Radios Complete');
console.log('Records NB: ' + this.len);
console.log('radios nb: ' + this.radios.length)
});
// executed before the HTTP get call to the server
// console.log('radio component NB: ' + this.radios.length);
}
Because data is not returned immediately but only when the callback passed to subscribe(...) is executed you can get errors for bindings like
<div>{{radios.xxx}}</div>
when radios is still null when Angular2 already resolves the bindings in the template. To avoid errors you can use the safe-navigation (Elvis) operator
<div>{{radios?.xxx}}</div>
Angular2 doesn't try to access .xxx while radios is null.
The problem is that you are subscribing to your observable from within your service. Your service should return an Observable and then you Subscribe to it from your component.
So your service should be:
getRadios() : Observable<Radio[]> {
return this.http.get('app/mock/FranceRadioJSON.json')
.map((res: Response) => <Radio[]>res.json())
}
And your component:
getRadios() {
this.radios = this.radioservice.getRadios().subscribe(
r => {
this.radios = r;
}
...
);
}

Accessing data within a view passed from model - Aurelia

Yes another Aurelia question, apologies!
So I'm trying to access data within my view passed from a model, whilst I can see the data within the response, I cannot seem to get it to display on the view. Any help greatly appreciated.
I've tried a few things but I guess being new to Aurelia,ES6 and promises, it's throwing me out a little or I've been staring at to long.
//EDIT Data Access Component
import {inject} from "aurelia-framework";
import {HttpClient} from "aurelia-http-client";
let baseUrl = "/FormDesigner";
#inject(HttpClient)
export class FormData{
constructor(httpClient)
{
this.http = httpClient;
}
GetFormById(formId)
{
return this.http.get(`${baseUrl}/GetFormById/${formId}`)
.then(f => f.content);
};
}
Model:
activate(params)
{
return this.form.GetFormById(params.formId)
.then(f => this.form = f);
}
The View:
<p class="navbar-text navbar-left">
${form.name}
</p>
The Response:
{"Id":"x","OrganisationId":"x","OrganisationDepartmentId":null,"ScheduleId":null,"DefinitionTypeId":"x","ReferenceNumber":11171,"Name":"New Form Test External Access","Description":"","IsTemplate":true,"IsActive":true,"IsSingleFormTemplate":false,"MinimumInstances":null,"MaximumInstances":null,"IsAdhocCreationEnabled":false,"HasCalculation":false,"Calculation":null,"Recalculate":true,"IsHidden":false}
So again I don't see the data appearing on the view and I feel I'm missing something rather simple.
//EDITS
So after a little digging I made a little change to my API returning a JSON array rather than a JSON object and also switched Aurelia to use Fetch... So now I can access the data in my data component but not my model - rather frustrating!
import {inject} from "aurelia-framework";
//import {HttpClient} from "aurelia-http-client";
//import 'fetch';
import {HttpClient} from 'aurelia-fetch-client';
let baseUrl = "/FormDesigner";
#inject(HttpClient)
export class FormData{
constructor(httpClient)
{
httpClient.configure(config => {
config
.withBaseUrl('/FormDesigner')
.withDefaults({
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'Fetch'
}
})
.withInterceptor({
request(request) {
console.log(`Requesting ${request.method} ${request.url}`);
return request;
},
response(response) {
console.log(`Received ${response.status} ${response.url}`);
return response;
}
});
});
this.http = httpClient;
}
GetFormById(formId)
{
return this.http.fetch(`/GetFormById/${formId}`)
.then(response => response.json())
.then(data => {
//Log here, to check incoming data
console.log("From component: " + data.Name);
//This WORKS
});
};
}
Again I've created an abstraction where as my model does not need to know about calls to the server.
import {inject} from "aurelia-framework";
import {FormData} from "form/formData";
#inject(FormData)
export class Form
{
constructor(formData)
{
this.form = formData;
}
activate(params)
{
if(params.formId != null)
{
return this.form.GetFormById(params.formId)
.then(data =>
{
this.form = data
console.log(this.form.Name);
//This does not work!!
});
}
else
{
//Show message that param does not exist or redirect to no form page
console.log("No Id");
}
}
}
Any help greatly appreciated,
Most likely you need to deserialize the JSON response into a Javascript object using JSON.parse.
GetFormById(formId)
{
return this.http.get(`${baseUrl}/GetFormById/${formId}`)
.then(response => JSON.parse(response.content));
};