Angular 2 - Return of Observable - json

I have problem with my Observable in my service.
I need to fetch data for 3 players. My subscription sign data from service to local variable and push it into array. Fine, but when i return data from if statement i have bug. I can see only one of 3 players. How can i store all data for whole life time of my app?
Regards.
Service:
getData(query): Observable<any> {
if(this.dataFromDb)
{
return Observable.of(this.dataFromDb);
}
return this.http.get(query)
.map(res => res.json())
.do(res => this.dataFromDb = res)
.catch(err => Observable.throw(err.json() || 'Błąd');
}
}
Component:
export class FriendsComponent implements OnInit {
myDataFromDb: any[] = [];
constructor(public dataService: DataService) {
}
private getDataFromDb(query) {
this.dataService.getData(query).subscribe((data) =>
{
this.myDataFromDb.push(data);
console.log(data);
});
}
ngOnInit() {
for (let i of this.dataService.friends) {
this.dataService.query = `${this.dataService.apiUrl}${i.nick}${this.dataService.apikey}`;
this.getDataFromDb(this.dataService.query);
}
console.log(this.myDataFromDb);
}
}
And some photo of problem:
Data on start
Data after route change.

You must use a object to "cache" the response. Personally I'll choose send to my function the nick and the apiKey, but as you send query, you can do
dataFromDb:any={};
getData(query): Observable<any> {
if(this.dataFromDb[query])
{
return Observable.of(this.dataFromDb[query]);
}
return this.http.get(query)
.map(res => res.json())
.do(res => this.dataFromDb[query] = res)
.catch(err => Observable.throw(err.json() || 'Błąd');
}
}

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);
});
}

Using a service in angular 4 guards

Please assist with angular guards, I have the following angular Guard below :
export class RoleGuard implements CanActivate {
private role: any;
constructor(private router: Router, private accountService: AccountService)
{}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
this.accountService.getUserRole().subscribe(res => this.role = res);
if (this.role === 'admin') {
return true;
}
return false;
}
}
in the service:
getUserRole(): Observable<Response> {
const options = this.headers();
return this.http.get(`${environment.ApiUrl}/Roles/getRole`,options)
.map(res => res.json())
.catch(res => Observable.throw(res.json()));
}
I am trying to subscribe to the getUserRole() function, then assign the response to this.role but that is not happening, role is always undefined. when i do a ...subscribe(res => console.log(res)) i see the response data.
You have to wait the result of the async HTTP Request before check if can activate that route or not.
Try returning a new Observable instead:
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
return new Observable(observer => {
//
this.accountService.getUserRole().subscribe(role => {
//
if (role === 'admin') {
observer.next(true); // Allowing route activation
} else {
observer.next(false); // Denying route activation
}
}, err => observer.next(false));
});
}

Ionic 2 - Passing ID from json to child (details) page

I have a provider service that calls get requests from my API. I then have a listing page whereby you can scroll though many recipes. What I am struggling with is taking the ID of each recipe and passing it to the details page as this needs to be included within.
My service request is for the listing is
loadCategory1() {
var url = "http://api.yummly.com/v1/api/recipes?_app_id=////&_app_key=////";
if (this.Category1) {
return Promise.resolve(this.Category1);
}
return new Promise(resolve => {
this.http.get(url + "&allowedAllergy[]=396^Dairy-Free&allowedAllergy[]=393^Gluten-Free&maxResult=50&start=10")
.map(res => res.json())
.subscribe(data => {
console.log(data);
this.Category1 = data.matches;
resolve(this.Category1);
});
});
}
and I currently have a separate one for my details as well
loadDetails() {
if (this.details) {
return Promise.resolve(this.details);
}
return new Promise(resolve => {
this.http.get('http://api.yummly.com/v1/api/recipe/French-Onion-Soup-The-Pioneer-Woman-Cooks-_-Ree-Drummond-41364?_app_id=//////&_app_key=//////')
.map(res => res.json())
.subscribe(data => {
console.log(data);
this.details = data;
resolve(this.details);
});
});
}
As you can see in the details request i have French-Onion-Soup-The-Pioneer-Woman-Cooks-_-Ree-Drummond-41364 This needs to be dynamic by taking the ID from each recipe. Example is below.
Within each .ts file I have the following
loadRecipes(){
this.apiAuthentication.loadCategory1()
.then(data => {
this.api = data;
});
}
This allows me to call the request.
I'm at the point now where I have no clue what to do so some help would be great.
Your DetailsService can be something like this:
loadDetails(detailsId: string) {
return new Promise(resolve => {
this.http.get('http://api.yummly.com/v1/api/recipe/'+detailsId+'?_app_id=//////&_app_key=//////')
.map(res => res.json())
.subscribe(data => {
console.log(data);
this.details = data;
resolve(this.details);
});
});
}
Navigate to DetailsPage with arguments:
this.navCtrl.push(DetailsPage,{
recipe: recipe
});
And you can call DetailsService inside DetailsPage by using code like this:
loadDetails(){
this.apiAuthentication.loadDetails(this.recipe.id)
.then(data => {
this.details = data;
});
}

Angular 2:Not able to get a token in another component which is stored in local storege

I have one application which include login and home component,
login.service.ts
let body = JSON.stringify(data);
console.log("logged in user",body);
return this._http.post('http://localhost:8080/api/user/authenticate', body, { headers: contentHeaders })
.map(res => res.json())
.map((res) => {
var token1:any = res;
console.log(token1);
if (token1.success) {
localStorage.setItem('auth_token', token1.token);
this.LoggedIn = true;
}
return res.success;
});
}
isLoggedIn() {
return this.LoggedIn;
}
in this service i am getting token in variable token1 and isLogged method contain
constructor(private _http: Http) {
this.LoggedIn = !!localStorage.getItem('auth_token'); }
Login.component.ts
login(event, username, password)
{
this.loginService.login(username, password)
.subscribe(
response => {
this.router.navigate(['/home']);
alert("login successfull");
},
error => {
alert(error.text());
console.log(error.text());
}
);
From this login i can able to authenticate and and its routing to home component,
Home.serice.ts
getClientList()
{
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let authToken = localStorage.getItem('auth_token');
headers.append('X-auth-Token', 'authToken')
return this._http.get('http://localhost:8080/api/v1/client/list?isClient=Y', {headers})
.map(res => res.json())
}
Home.component.ts
onTestGet()
{
this._httpService.getClientList()
.subscribe(
data => this.getData = JSON.stringify(data),
error => alert(error),
() => console.log("finished")
);
}
now question is how can i access that token in home component which is in token1 varible(login) i have tired to getitem token.but i am getting token null.please anybody help me.
thanks in advance
localStorage.getItem('auth_token')
This should work, but you are getting null, because lifecycle of the data different.
I suggest you to use Subject construction for this purpose, especially you already have service with data.
Example:
loginInfo$ = new Subject();
private _logininfo = null;
getLoginData () {
if(!_logininfo) {
this.http..... { this._loginInfo = data;
this.loginInfo$.next(data); }
return this.loginInfo$.first()
}
else return Observable.of(this._logininfo);
}
So now, your service at the same time storage of data and handler for missing login.

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