Angular 2 this.data is undefined - json

I'm trying to read the content of my JSON file through my "GetJsonService".
app.component.ts:
data: any;
constructor(private jsonService: GetJsonService) {}
ngOnInit() {
this.getRecords();
console.log(this.data);
}
getRecords() {
this.jsonService.getRecords().subscribe(data => {
this.data = data;
}, err => {
console.log(err);
});
}
get-json.service.ts
constructor(private http: Http) { }
data: any;
getRecords() {
return this.http.get('assets/standorte.json').map(data => {
this.data = data.json();
return data.json();
}, err => {
if (err) {
return err.json();
}
});
}
I want to put the content of data.json() into this.data to use it.
But when I log this.data it is "undefined".
I'm completely new to Angular 2 and Typescript, so I really would be thankful when someone helps me.
Greetings

#MauricioSipmann solved my problem.
The problem was that the code runs asynchronously in a request.
I actually knew that but Typescript confused me a little bit.
Thank you to all responders!

Just modify your method getRecords()
Use it as below :
getRecords() {
this.jsonService.getRecords().subscribe(data => {
this.data = data;
console.log(this.data);
}, err => {
console.log(err);
});
}
Instead of logging after calling method you should do inside success of service.
This is common issue which every developer face at initiate stage of Angular 2+.
It is an async call. So the issue is you console.log() statement is executing before your service assign value this.data = data; to the variable.
With your code if you display data in HTML it will probably work fine. Just it will not log properly where you got confused.

If you are using angular 6, no need to convert to json. Just return the request.
getRecords() {
return this.http.get('assets/standorte.json')
}

another problem is your not re throw the async state ..try this:
ngOnInit() {
this.getRecords().then((resp)=>{
console.log(resp);
});
}
getRecords() {
return new Promise<>((resolve,reject)
=> {
this.jsonService.getRecords().subscribe(data => {
this.data = data;
resolve(data);
}, err => {
console.log(err);
reject(err);
});
})
}

Related

Call json file from url

I'm trying to call json file from url and get data. But no error and nothing working. I don't have any idea how to solve it.
service
export class JsonService {
public getMenuData(): Observable<any> {
return new Observable((observer) => {
this.http.get('https://demored.ddns.net:50443/demored/path_image/menu.json').subscribe((response)=> {
observer.next(response);
observer.complete();
});
});
}
Component
ngOnInit() {
this.getJson();
}
getJson(){
this.jsonService.getMenuData().toPromise().then(data => {
this.menuJson = data;
console.log("Menu from json file ",this.menuJson);
}).catch((err) => {
console.log('error in fetching data',err);
});
}
You make the GET request on the service, where you convert the request into a promise with toPromise(). From there in any component you can call the method for the service declared in the constructor this.serviceJson() and resolve the promise with a .then () or .catch ()
export class JsonService {
getMenuData(): Promise<any> {
return this.http.get<any>('https://demored.ddns.net:50443/demored/path_image/menu.json').toPromise()
}
component
ngOnInit() {
this.getJson();
}
async getJson(){
await this.jsonService.getMenuData().then(data => {
this.menuJson = data;
console.log("Menu from json file ",this.menuJson);
}).catch((err) => {
console.log('error in fetching data',err);
});
}

TextDecoder failing in ES6 Promise recursion

I'm attempting to query an API which responds with a ReadableStream of XML.
The code below uses a recursive Promise. Recursive because it sometimes doesn't decode the stream in a singular iteration and this is whats causing my headache.
While I'm successfully fetching the data, for some reason the decoding stage doesn't complete sometimes, which leads me to believe it's when the stream is too large for a single iteration.
componentDidMount() {
fetch("http://thecatapi.com/api/images/get?format=xml&size=med&results_per_page=9")
.then((response) => {
console.log('fetch complete');
this.untangleCats(response);
})
.catch(error => {
this.state.somethingWrong = true;
console.error(error);
});
}
untangleCats({body}) {
let reader = body.getReader(),
string = "",
read;
reader.read().then(read = (result) => {
if(result.done) {
console.log('untangling complete'); // Sometimes not reaching here
this.herdingCats(string);
return;
}
string += new TextDecoder("utf-8").decode(result.value);
}).then(reader.read().then(read));
}
I think that the next iteration was sometimes being called before the current iteration had completed, leading to incorrectly concatenation of the decoded XML.
I converted the function from sync to async and as a regular recursive method of the component rather than a recursive promise with a method.
constructor({mode}) {
super();
this.state = {
mode,
string: "",
cats: [],
somethingWrong: false
};
}
componentDidMount() {
fetch("http://thecatapi.com/api/images/get?format=xml&size=med&results_per_page=9")
.then( response => this.untangleCats( response.body.getReader() ) )
.catch(error => {
this.setState({somethingWrong: true});
console.error(error);
});
}
async untangleCats(reader) {
const {value, done} = await reader.read();
if (done) {
this.herdingCats();
return;
}
this.setState({
string: this.state.string += new TextDecoder("utf-8").decode(value)
});
return this.untangleCats(reader);
}

How to execute promise of super class in ES6

I've a promise in Parent class, whenever I call the promise from child class, it is returning the undefined, instead of executing the promise and returning the resul.
import {newsApiKey as APIKEY, newUrl as APIURL} from "./secretToken";
class News{
constructor(){
this.token = APIKEY;
this.url = APIURL;
this.source = 'bbc-news&';
}
topNews(){
const bbcNews = fetch(`${this.url}?source=${this.source}&sortBy=top&apiKey=${this.token}`);
bbcNews.then(response => {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json()
})
.then(json => {
console.log(json.articles);
return json.articles;
})
.catch((err) => {
return err.message;
});
}
}
export { News as default};
CHILD CLASS
import News from "./news";
class StickyNote extends News{
displayNews(){
let bbcNews = super.topNews(); // It is returning only undefined
if (typeof bbcNews != 'undefined') {
console.log(bbcNews); //
}
}
}
topNews never returns anything, so the result of calling it is undefined.
You probably wanted a return here:
topNews() {
const bbcNews = fetch(`${this.url}?source=${this.source}&sortBy=top&apiKey=${this.token}`);
return bbcNews.then(response => {
// ^^^^^^
if (!response.ok) {
throw Error(response.statusText);
}
return response.json()
})
.then(json => {
console.log(json.articles);
return json.articles;
})
.catch((err) => {
return err.message;
});
}
Also note that displayNews will need to use the promise it receives:
displayNews(){
super.topNews().then(articles => {
// ...use articles
});
}
(Normally you'd also have a catch there at the endpoint of consumption, but as you've converted rejections into resolutions...)
Note: That code has a bit of an anti-pattern in it: It converts a rejection into a resolution with an error message. Anything using the promise will never see a rejection, only resolutions with varying return types (whatever json.articles is or a string). In general, it's better to allow rejections to propagate, and handle them at the ultimate point of consumption of the entire chain (displayNews, I believe, in your example). You might transform their content, but not convert them from a rejection into a resolution.
FWIW, I'd probably rewrite that like so:
topNews() {
return fetch(`${this.url}?source=${this.source}&sortBy=top&apiKey=${this.token}`)
.catch(_ => {
throw new Error("network error");
})
.then(response => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json();
})
.then(data => { // "data", not "json" -- it's not JSON anymore
return data.articles;
});
}
...which ensures that the caller either gets a resolution with the articles, or a rejection with an Error, so:
displayNews(){
super.topNews()
.then(articles => {
// ...use articles
})
.catch(err => {
// ...show error
});
}

How to handle Promise in nodejs

I'm trying to execute a callback function in nodejs, using expressjs and angular 2 (i don't know if the angular2 part it's relevant).
What I do is:
I have a formular in angular2, with that I send a get request to my API route, then I send the text field in the formular to the URL via get, then I do an MYSQL query to look into a phonebook database, and I'm expecting to get a complete user with his details, from the phonebook.
Formular:
<div class="container">
<div class="col-md-4">
<h1>Addressbook</h1>
<form [formGroup]="searchForm" (ngSubmit)="doSearch($event)">
<input formControlName="searchString" type="text" placeholder="Name">
<button type="submit">Search</button>
</form>
</div>
</div>
First function, doSearch:
doSearch(event) {
let formData = this.searchForm.value;
var searchString = this.searchForm.value.searchString;
this.http.get('/phonebook/search/'+searchString, function(req, res){}).subscribe(
function(response) {
console.log("Success Response");
},
function(error) { console.log("Error happened" + error)},
function() { console.log("the subscription is completed")}
);
}
This calls to the route sending a parameter, so not so hard.
Now the create router gets into the game:
public static create(router: Router, basePath: string) {
console.log("[SearchRoute::create] Creating routes for /search.");
// call the function for retrieving the address book results
router.get(basePath + "/search/:searchString", (req: Request, res: Response, next: NextFunction) => {
console.log("## [SearchRoute] Called GET /search.");
var object = searchUser(req);
console.log(object);
});
}
And finally, the function searchUser gets called:
function searchUser(req: Request) {
console.log("searchUser Function executed.");
var searchString = req.params.searchString;
var query = p_query('SELECT XXXX')
.then(function (results) {
console.log("query executed and all okay");
return (results);
})
.catch(function (error) {
console.error("Wooopsi", error);
});
console.log("query result: "+query);
}
Additionally, I post here the new query function that I build to be able to handle promises (which I don't know if it was the best choice):
function p_query(q) {
return new Promise(function (resolve, reject) {
// The Promise constructor should catch any errors thrown on
// this tick. Alternately, try/catch and reject(err) on catch.
myMYSQL.db.query(
q,
function (error, results) {
if (error)
reject(error);
resolve(results);
});
})
};
So, what I actually want to do, what's my issue?
I want to send the result of the query back to the client (the angular2 formular), and I was not being able to do it...
So after this really long post, I really appreciate if you read til here, and sorry for the complicated question!
PS: I know i explain myself really bad :(
Regards,
Daniel
In this official angular 2 documentation on the http client they propose to put the http logic into a separate service. I've setup it similar to the example just for a search.service.ts:
import { Injectable } from '#angular/core';
import { Http, Response,Headers, RequestOptions,URLSearchParams }
from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
#Injectable()
export class SearchService {
constructor(private http: Http) {
}
getSearchResult(searchString) : Observable<any> {
return this.http.get('/phonebook/search/'+searchString)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body;
}
private handleError (error: Response | any) {
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
return Observable.throw(errMsg);
}
}
In your component import the service and do the code snippets:
// don't forget to put the service in the app.modul or the component providers!
constructur(public mySearchService : SearchService) {}
// in your doSearch of your component:
doSearch(event) {
let formData = this.searchForm.value;
var searchString = this.searchForm.value.searchString;
mySearchService.getSearchResult(searchString).subscribe(
data => mylist.data, // or which datastructure I want to write to.
error => console.error(error) // or how I log the errors..
);
}
EDIT: The search_user in your database model:
function searchUser(searchString) {
console.log("searchUser Function executed.");
return myMYSQL.db.select('phonebookentry', {
pbe_lastname: searchString, pbe_syncstate: 'new'
}) // returning the promise/observable to the main function...
} // Currently I don't know, how the returned data looks like.
On the node/express side in the router send it with res.json EDIT: use asynchronous call to searchUser:
router.get(basePath + "/search/:searchString",
(req: Request, res: Response, next: NextFunction) => {
console.log("## [SearchRoute] Called GET /search.");
searchUser(req)
.then( data => res.json(data);console.log(data) )
.catch (error => console.log(error));
});
You should go with recursive callback with each query results try to enjoy the beauty of async platform.
Send data to client via
res.send(data);
Your answer it's completely perfect, i understand everything! The only problem that i'm facing now, its this one:
I'm calling the function searchUser, and it doesn't return anything, just an undefined object, so i quess i'm not doing the return correctly.
That's my searchUser function:
function searchUser(searchString) {
console.log("searchUser Function executed.");
myMYSQL.db.select('phonebookentry', {
pbe_lastname: searchString,
pbe_syncstate: 'new'
}).then(function (user) {
console.log("user before: "+user);
return (user);
}).catch(function (err) {
console.log(err);
})}
Thank you so much for your useful answer! I'm almost finished here

Combining api request

I am new to Angular2 and just started to work with Http request and observables.
Previously I worked with .NET and MySql, and I am now trying to learn the best practice working with data from API’s.
I am used to join tables, and I would like to find the best way to combine json data.
In this example I want the user to fill a form and type his phone number.
The prefix of the phone number is a dropdownlist with country code and prefix f.ex. Germany +49
Therefor I need an object: { “Germany”:”49”, Cambodia:"855" ….}
I make 2 http request to country.io:
http://country.io/phone.json // e.g. DE: “Germany”
http://country.io/names.json // e.g. DE: “49”
From these 2 request I used the code below to make my new json object : myPhonePrefixObject
I think the code is too long, and that it must be possible to do it in a better way.
country-service.ts:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/Rx';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class CountryService {
constructor( private _http:Http) { }
getCountryCode(): Observable<any> {
return this._http.get('http://crossorigin.me/http://country.io/phone.json')
.map(countryCodes => countryCodes.json());
}
getPhonePrefix(): Observable<any> {
return this._http.get('http://crossorigin.me/http://country.io/names.json')
.map(phonePrefix => phonePrefix.json());
}
}
Code inside userform.component in where I import the CountryService
myPhonePrefixObject;
this.countryPhonePrefix()
.then((pp) => {
myPhonePrefixObject = pp;
})
.catch((err) => {
console.log(err);
});
private getCountryCode() {
return new Promise((resolve) => {
this._countryService.getCountryCode()
.subscribe(
res => resolve(res)
);
});
}
private getPhonePrefix() {
return new Promise((resolve, reject) => {
return this._countryService.getPhonePrefix()
.subscribe(
res => resolve(res),
error => reject(error)
);
});
}
private countryPhonePrefix() {
return new Promise((resolve, reject) => {
let cc: Object;
this.getCountryCode()
.then((cCode) => {
cc = cCode;
return this.getPhonePrefix()
})
.then((pPrefix) => {
let pp: Object = {};
Object.keys(cc).forEach((key, index) => {
pp[cc[key]] = pPrefix[key];
});
resolve(pp);
})
.catch((err) => {
reject(err);
});
});
}
.NET developer here too!
To deal with multiple streams, you will need aggregation methods. In this case, you want to yield the object based on the result of 2 streams (HTTP requests), the aggregation method you are looking for is combineLatest. It combines the 2 streams and let you define the output data based on 2 sources:
getCombinedData(): Observable<Data> {
return this.getCountryPhones().combineLatest(this.getCountryNames(),
(phoneData, nameData) => {
var resultData = {};
Object.keys(nameData).forEach((key) => {
resultData[nameData[key]] = phoneData[key];
});
return resultData;
});
}
Plunker: http://plnkr.co/edit/agUPNujG3NnbKI6J3ZVJ?p=preview