showing by console.log an observable array in angular 8 - arrays

I am trying to show response from an observable on console that comes from a service in my angular project. But it appears to be undefined. When I try with a loop, the error in console says it is not iterable while the observable is supposed to return an array. Why could this be happening?
Component
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
constructor(private heroService: HeroService, private messageService: MessageService) { }
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(data => this.heroes = data);
}
ngOnInit() {
this.getHeroes();
// for(let hero of this.heroes){
// console.log(hero);
// }
console.log(this.heroes);
}
}
Service
#Injectable({
providedIn: 'root'
})
export class HeroService {
private heroesUrl = 'api/heroes';
constructor(
private messageService: MessageService,
private http: HttpClient
) { }
httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
getHeroes(): Observable<Hero[]> {
return this.http.get<Hero[]>(this.heroesUrl)
.pipe(
tap(_ => this.log('fetched heroes')),
catchError(this.handleError<Hero[]>('getHeroes', []))
);
}
private log(message: string) {
this.messageService.add(`HeroService: ${message}`);
}
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(error);
this.log(`${operation} failed: ${error.message}`);
return of(result as T);
};
}
}

That is happening because the request is asynchronous, that means the execution of the program continues while the request is resolved.
In other you should use the result of the request when it is resolved. In your example that would be after you are assigning the returned value of the request to heroes property.
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(data => {
this.heroes = data; // <- after this point you have the result
console.log(this.heroes);
});
}

Related

Passing google calendar data from service to component

Array not passing from service to component:
In the test() function on the service.ts page, google calendar data is successfully being read and pushed to an array called response. All the data logs.
When lesson-summary.component.ts calls on the test() function, the response array data does not show up in the lesson-summary.component.html
Thanks for any help!
google-calendar.service.ts
import { Injectable, Directive } from "#angular/core";
import * as moment from "moment-timezone";
declare var gapi: any;
#Injectable({
providedIn: "root"
})
export class GoogleCalendarService {
private response = [];
constructor() { }
test() {
gapi.load("client", () => {
gapi.client.init({
apiKey: "API string here",
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"]
}).then(() => {
var month = moment().month();
const firstOfMonth = moment().startOf("month").format("YYYY-MM-DD hh:mm");
const lastOfMonth = moment().endOf("month").format("YYYY-MM-DD hh:mm");
var firstOfMonthUTC = moment.tz(firstOfMonth, "America/Toronto").format();
var lastOfMonthUTC = moment.tz(lastOfMonth, "America/Toronto").format();
return gapi.client.calendar.events.list({
calendarId: "calendar id here",
timeMax: lastOfMonthUTC,
timeMin: firstOfMonthUTC,
singleEvents: true
});
})//end of .then
.then((data) => {
this.response.push.apply(this.response, data.result.items);
console.log(data.result.items, "data.result.items");
return this.response;
});//end of .then
});//end of .load
}//end of test
}//end of export
lesson-summary.component.ts
import { Component, OnInit } from "#angular/core";
import { Observable } from "rxjs";
import { GoogleCalendarService } from "../google-calendar.service";
declare var gapi: any;
#Component({
selector: "app-lesson-summary",
templateUrl: "./lesson-summary.component.html",
styleUrls: ["./lesson-summary.component.css"]
})
export class LessonSummaryComponent implements OnInit {
private response;
constructor(
private calendarService: GoogleCalendarService) {
this.response = this.calendarService.test();
}
ngOnInit() {
}
}
lesson-summary.component.html
<ul>
<li *ngFor = "let item of response">
{{ item.summary }}
</li>
</ul>
That's because you're mixing promises and sync functions in an incorrect way, so the test() function will not return anything.
Try adding a promise to your test():
test() {
return new Promise(resolve => { // <-- now test func return promise
gapi.load("client", () => {
gapi.client.init({
apiKey: "API string here",
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"]
}).then(() => {
// code...
}).then((data) => {
// code...
resolve(this.response); // <-- when we have the response, we are resolving the promise
});
});
});
}
And then use this promise in the component:
this.calendarService.test().then(data => this.response = data);
Learn more about promises on MDN

How to return back the data value from service providers to components | Angular 4 | Ionic

I want to return back the geolocation latitude, and longitude value from my service provider file.
Code shown below.
component or pages 'home.ts'
import { WeatherProvider } from '../../providers/weather/weather';
constructor(public navCtrl: NavController,private weatherProvider: WeatherProvider) {
console.log(this.weatherProvider.getGeoLocation()+'kkk');
}
provider file 'weather.ts'
import { Geolocation } from '#ionic-native/geolocation';
....
....
constructor(public http: Http, private geolocation: Geolocation) { }
getGeoLocation() {
this.geolocation.getCurrentPosition().then((resp) => {
// console.log(resp.coords.latitude)
// console.log(resp.coords.longitude)
return resp;
}).catch((error) => {
console.log('Error getting location', error);
});
}
I'am getting result as undefined. I'am newbie in typescript, sorry for the silly question. Thanks to all
You need to return the promise from your service and chain in your component.
getGeoLocation() {
//return the promise
return this.geolocation.getCurrentPosition().then((resp) => {
// console.log(resp.coords.latitude)
// console.log(resp.coords.longitude)
return resp;
}).catch((error) => {
console.log('Error getting location', error);
});
}
In your component, call Promise.then() to access the resp returned from the promise,
this.weatherProvider.getGeoLocation()
then(loc => {
console.log(loc);
});
You should add return before call this.geolocation.getCurrentPosition because it is a promise.
constructor(public http: Http, private geolocation: Geolocation) { }
getGeoLocation() {
return this.geolocation.getCurrentPosition().then((resp) => {
// console.log(resp.coords.latitude)
// console.log(resp.coords.longitude)
return resp;
}).catch((error) => {
console.log('Error getting location', error);
});
Add this code your service 'weather.ts'
import { Geolocation } from '#ionic-native/geolocation';
....
....
constructor(public http: Http, private geolocation: Geolocation) { }
getGeoLocation() {
return new Promise((resolve, reject) => {
this.geolocation.getCurrentPosition()
.then((resp) => {
resolve(resp.json());
}).catch((error) => {
console.log('Error getting location', error);
reject(error);
});
});
}
And your component file:
import { WeatherProvider } from '../../providers/weather/weather';
constructor(public navCtrl: NavController,private weatherProvider: WeatherProvider){
this.weatherProvider.getGeoLocation()
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
}

Binding ID in HTTP REQUEST in angular 2

I am learning a tutorial and an assignment on how to bind id's to http request. This is what i am currently trying to do. I want to bind the id captured in my url and when i trigger the function, it submits the id captured from the url to my service. I am have been able to capture the url but the function to send the captured id to the service is where i am having the issues. The id in the function parameter is Unused.
//Food Component
export class FoodComponent implements OnInit {
private food_id;
constructor(private httpService: HttpService, private route: ActivatedRoute) {
}
ngOnInit() {
this.route.params.subscribe(params => {
if (params['id']) {
this.food_id = params['id'];
}
})
}
//food model
foodModel = {
type: "",
location: ""
};
sendFood() {
this.httpService.send(this.food_id)
.subscribe(data => {
console.log(data);
})
}
//service
send(food: any) {
const body = JSON.stringify(food.value);
const headers = new Headers();
return this.http.post('http://localhost:8000/api/luncheons/v1/location/' + food.id + '/type', body, {
headers: headers
})
.map((data: Response) => data.json());
}
Try this,
import { foodModel } from './foodModel';
export class FoodComponent implements OnInit {
private model: foodModel; /// Make a new variable of foodModel.
ngOnInit() {
this.model = new foodModel(); // Initialize the Model
this.route.params.subscribe(params => {
if (params['id']) {
this.model.id = params['id']; ///set the parameter id to model.id
}
})
}
/// Removed the parameter food_id
sendFood() {
this.httpService.send(this.foodModel)
.subscribe(data => {
console.log(data);
})
}
//service
send(food: any) {
const body = JSON.stringify(food);
const headers = new Headers();
return this.http.post('http://localhost:8000/api/luncheons/v1/location/' + food.id + '/type', body, {
headers: headers
})
.map((data: Response) => data.json());
}
}
// Make a class file foodModel.ts and import foodModel in your component.
export class foodModel {
type: any;
location: any;
id: number = 0; /// new variable added
};

Getting an object array from an Angular service

I am new to Angular (and Javascript for that matter). I've written an Angular service which returns an array of users. The data is retrieved from an HTTP call which returns the data in JSON format. When logging the JSON data returned from the HTTP call, I can see that this call is successful and the correct data is returned. I have a component which calls the service to get the users and an HTML page which displays the users. I cannot get the data from the service to the component. I suspect I am using the Observable incorrectly. Maybe I'm using subscribe incorrectly as well. If I comment out the getUsers call in the ngInit function and uncomment the getUsersMock call, everything works fine and I see the data displayed in the listbox in the HTML page. I'd like to convert the JSON data to an array or list of Users in the service, rather then returning JSON from the service and having the component convert it.
Data returned from HTTP call to get users:
[
{
"firstName": "Jane",
"lastName": "Doe"
},
{
"firstName": "John",
"lastName": "Doe"
}
]
user.ts
export class User {
firstName: string;
lastName: string;
}
user-service.ts
...
#Injectable
export class UserService {
private USERS: User[] = [
{
firstName: 'Jane',
lastName: 'Doe'
},
{
firstName: 'John',
lastName: 'Doe'
}
];
constructor (private http: Http) {}
getUsersMock(): User[] {
return this.USERS;
}
getUsers(): Observable<User[]> {
return Observable.create(observer => {
this.http.get('http://users.org').map(response => response.json();
})
}
...
user.component.ts
...
export class UserComponent implements OnInit {
users: User[] = {};
constructor(private userService: UserService) {}
ngOnInit(): void {
this.getUsers();
//this.getUsersMock();
}
getUsers(): void {
var userObservable = this.userService.getUsers();
this.userObservable.subscribe(users => { this.users = users });
}
getUsersMock(): void {
this.users = this.userService.getUsersMock();
}
}
...
user.component.html
...
<select disabled="disabled" name="Users" size="20">
<option *ngFor="let user of users">
{{user.firstName}}, {{user.lastName}}
</option>
</select>
...
!!! UPDATE !!!
I had been reading the "heroes" tutorial, but wasn't working for me so I went off and tried other things. I've re-implemented my code the way the heroes tutorial describes. However, when I log the value of this.users, it reports undefined.
Here is my revised user-service.ts
...
#Injectable
export class UserService {
private USERS: User[] = [
{
firstName: 'Jane',
lastName: 'Doe'
},
{
firstName: 'John',
lastName: 'Doe'
}
];
constructor (private http: Http) {}
getUsersMock(): User[] {
return this.USERS;
}
getUsers(): Promise<User[]> {
return this.http.get('http://users.org')
.toPromise()
.then(response => response.json().data as User[])
.catch(this.handleError);
}
...
Here is my revised user.component.ts
...
export class UserComponent implements OnInit {
users: User[] = {};
constructor(private userService: UserService) {}
ngOnInit(): void {
this.getUsers();
//this.getUsersMock();
}
getUsers(): void {
this.userService.getUsers()
.then(users => this.users = users);
console.log('this.users=' + this.users); // logs undefined
}
getUsersMock(): void {
this.users = this.userService.getUsersMock();
}
}
...
!!!!!!!!!! FINAL WORKING SOLUTION !!!!!!!!!!
This is all the files for the final working solution:
user.ts
export class User {
public firstName: string;
}
user.service.ts
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';
import { User } from './user';
#Injectable()
export class UserService {
// Returns this JSON data:
// [{"firstName":"Jane"},{"firstName":"John"}]
private URL = 'http://users.org';
constructor (private http: Http) {}
getUsers(): Observable<User[]> {
return this.http.get(this.URL)
.map((response:Response) => response.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
}
user.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { User } from './user';
import { UserService } from './user.service';
#Component({
moduleId: module.id,
selector: 'users-list',
template: `
<select size="5">
<option *ngFor="let user of users">{{user.firstName}}</option>
</select>
`
})
export class UserComponent implements OnInit{
users: User[];
title = 'List Users';
constructor(private userService: UserService) {}
getUsers(): void {
this.userService.getUsers()
.subscribe(
users => {
this.users = users;
console.log('this.users=' + this.users);
console.log('this.users.length=' + this.users.length);
console.log('this.users[0].firstName=' + this.users[0].firstName);
}, //Bind to view
err => {
// Log errors if any
console.log(err);
})
}
ngOnInit(): void {
this.getUsers();
}
}
Take a look at your code :
getUsers(): Observable<User[]> {
return Observable.create(observer => {
this.http.get('http://users.org').map(response => response.json();
})
}
and code from https://angular.io/docs/ts/latest/tutorial/toh-pt6.html
(BTW. really good tutorial, you should check it out)
getHeroes(): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json().data as Hero[])
.catch(this.handleError);
}
The HttpService inside Angular2 already returns an observable, sou don't need to wrap another Observable around like you did here:
return Observable.create(observer => {
this.http.get('http://users.org').map(response => response.json()
Try to follow the guide in link that I provided. You should be just fine when you study it carefully.
---EDIT----
First of all WHERE you log the this.users variable? JavaScript isn't working that way. Your variable is undefined and it's fine, becuase of the code execution order!
Try to do it like this:
getUsers(): void {
this.userService.getUsers()
.then(users => {
this.users = users
console.log('this.users=' + this.users);
});
}
See where the console.log(...) is!
Try to resign from toPromise() it's seems to be just for ppl with no RxJs background.
Catch another link: https://scotch.io/tutorials/angular-2-http-requests-with-observables Build your service once again with RxJs observables.

TypeScript - I can't call my json with http get using Angular 2

I want to develop a file configuration of json and it is called with http get the constructor and return the value I want the config file to another component. But when return gives me value undefined.
My Config.json
[ {"urlServer": "http://localhost:56877"}]
My Config.Service
export class configService
{
url: string;
constructor(public _http: Http)
{
let injector = Injector.resolveAndCreate([loggerService]);
let logger = injector.get(loggerService);
try {
return this._http.get('/app/config.json',
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <configModel>res.json();
this.url = data.urlServer;
JSON.stringify(this.url);
});
}
catch (ex) {
logger.registarErros('configService', ex);
}
}
returnConfig()
{
return this.url;
}
Now my other Component
constructor(public _http: Http, public config: configService)
{
this.token = sessionStorage.getItem('token');
this.username = sessionStorage.getItem('username');
}
login(username: String, password: String)
{
let injector = Injector.resolveAndCreate([loggerService]);
let logger = injector.get(loggerService);
try
{
alert(this.config.url);
return this._http.post('http://localhost:56877/api/Login/EfectuaLogin', JSON.stringify({ username, password }),
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <authLoginModel>res.json();
this.token = data.token;
this.username = data.nome;
sessionStorage.setItem('token', this.token);
sessionStorage.setItem('username', this.username);
return Observable.of('authObservable');
});
}
catch (ex) {
logger.registarErros('authentication', ex);
}
}
I no longer know how to solve the problem, I need your help, I'm not very experienced with Angular 2.
Thanks very much.
The problem here is that the config is load asynchronously. You could use something like that leveraging the flatMap operator:
#Injectable()
export class ConfigService {
urlServer:string;
constructor(public _http: Http) {
}
getConfig() {
if (this.urlServer) {
return Observable.of(this.urlServer);
}
return this._http.get('/app/config.json', {
headers: contentHeaders
})
.map((res: any) => {
let data = <configModel>res.json();
return data.urlServer;
}).do(urlServer => {
this.urlServer = urlServer;
});
}
}
and in your component:
login(username: String, password: String) {
return this.configService.getConfig().flatMap(urlServer => {
this._http.post('http://localhost:56877/api/Login/EfectuaLogin',
JSON.stringify({ username, password }),
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <authLoginModel>res.json();
this.token = data.token;
this.username = data.nome;
sessionStorage.setItem('token', this.token);
sessionStorage.setItem('username', this.username);
return data; // or something else
});
}
});
}
Another approach would be boostrap asynchronously after having loaded the configuration:
var app = platform(BROWSER_PROVIDERS)
.application([BROWSER_APP_PROVIDERS, appProviders]);
service.getConfig().flatMap((url) => {
var configProvider = new Provider('urlServer', { useValue: urlServer});
return app.bootstrap(appComponentType, [ configProvider ]);
}).toPromise();
See this question for the second approach:
angular2 bootstrap with data from ajax call(s)
You can go further by mixing the last approach with a CustomRequestOptions:
import {BaseRequestOptions, RequestOptions, RequestOptionsArgs} from 'angular2/http';
export class CustomRequestOptions extends BaseRequestOptions {
merge(options?:RequestOptionsArgs):RequestOptions {
options.url = 'http://10.7.18.21:8080/api' + options.url;
return super.merge(options);
}
}
See this question:
Angular 2 - global variable for all components

Resources