Problems with Angular 2 Http GET - json

I'm struggling to do a http get request with Angular 2. I've made a file with the JSON information that I want to "get" with my TeacherInfo class and use it to display information by the account component which is used in a routing.
If I click in the routerLink for this element nothing is displayed and if I switch to another routerLink there is neither ( there was before, all routerLinks worked just fine )
file: TeacherInfo.service.ts
import {Injectable, OnInit} from '#angular/core';
import { Http, Response , Headers} from '#angular/http';
import { account } from '../components/account.component';
import {Observable} from "rxjs";
#Injectable()
export class TeacherInfo {
constructor ( private http : Http) {}
private url = '../test.json';
getInfo(){
return this.http.get(this.url)
.toPromise()
.then(response => response.json().data as account );
}
}
file: account.component.ts
import {Component, OnInit} from '#angular/core';
import { TeacherInfo } from '../services/TecherInfo.service';
#Component({
template:`
<h2>This is not ready jet!</h2>
<p>
Willkommen {{name}}! <br/>
E-mail: {{email}}<br/>
</p>
`
})
export class account implements OnInit{
public id : number;
public name : string;
public email: string;
private acc : account;
constructor(private accountinfoservice : TeacherInfo) {
}
getInfo() {
this.accountinfoservice.getInfo()
.then(( info : account ) => this.acc = info );
}
ngOnInit () {
this.getInfo();
if ( this.acc != null ) {
this.id = this.acc.id;
this.name = this.acc.name;
this.email = this.acc.email;
}else {
console.log("there is no data! ");
}
}
and finally test.json :
{
"id" : "1",
"name": "testname",
"email": "testemail"
}
I'm using the latest versions of node and npm and I get no compilation errors and just unrelated errors in the browser console ( other SPA's parts which aren't ready yet). The observable implementations are there because at first I tried to do it that way and came to the conclusion it's easier at first to use a promise.

I subscribe for simple json gets
Calling code
ngOnInit(): void {
this._officerService.getOfficers()
.subscribe(officers => this.officers = officers),
error => this.errorMessage = <any> error;
}
And service code
import { Injectable } from 'angular2/core';
import { Http, Response } from 'angular2/http';
import { Observable } from 'rxjs/Observable';
import { Officer } from '../shared/officer';
#Injectable()
export class OfficerService{
private _officerUrl = 'api/officers.json';
constructor(private _http: Http){ }
getOfficers() : Observable<Officer[]>{
return this._http.get(this._officerUrl)
.map((response: Response) => <Officer[]>response.json())
.catch(this.handleError);
}
private handleError(error: Response){
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
That is returning the data as an array and casting it to the correct type though you can also use any and return [0] if you just expect one.
Hope that helps

Related

Angular 5 "map is not defined"

I have .Net 4.6.2 VS 2017 Mvc application, with Angular 5, "rxjs": "^5.5.10"
I am trying to get data for Kendo UI grid through controller. The controller is returning data which I can see, but in the service class at code .map(response => response.json()), it says illegal return statement.(Please see attached image)
err img2
Here is vto.service.ts
import { Injectable } from '#angular/core';
import { VTO } from './vto';
import { Http, HttpModule, Headers, Response } from '#angular/http';
import { HttpClientModule, HttpClient, HttpHeaders} from '#angular/common/http';
import { Location, LocationStrategy, PathLocationStrategy } from '#angular/common';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
import {
toDataSourceRequestString,
translateDataSourceResultGroups,
translateAggregateResults,
DataResult,
DataSourceRequestState
} from '#progress/kendo-data-query';
import 'rxjs/add/operator/map';
import { GridDataResult, DataStateChangeEvent } from '#progress/kendo-angular-grid';
#Injectable()
export class Vtos {
// private vtoUrl = location.href.replace(location.hash, '') + '/home/GetVtos';
private vtoUrl = 'http://localhost:63213/Home/GetVtos';
constructor(private http: Http) { }
public getVtos(state: DataSourceRequestState): Observable<DataResult> {
const queryStr = `${toDataSourceRequestString(state)}`; //serialize the state
const hasGroups = state.group && state.group.length;
return this.http
.get(`${this.vtoUrl}?${queryStr}`) //send the state to the server
.map(response => response.json())
.map(({ data, total/*, aggregateResults*/ }) => // process the response
(<GridDataResult>{
//if there are groups convert them to compatible format
data: hasGroups ? translateDataSourceResultGroups(data) : data,
total: total,
// convert the aggregates if such exists
//aggregateResult: translateAggregateResults(aggregateResults)
}))
}
}
HomeController call to GetVots
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using VTO.DTO;
using VTO.DAL;
using Kendo.Mvc.UI;
using Kendo.Mvc.Extensions;
namespace VTO.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpGet]
public JsonResult GetVtos([DataSourceRequest]DataSourceRequest request)
{
return new JsonResult
{
ContentType = "application/json",
Data = Vto.GetVtos().ToDataSourceResult(request),
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
MaxJsonLength = int.MaxValue
};
}
}
A couple of observations here, this module is deprecated. See details here. Remove it from your app.
import { Http, HttpModule, Headers, Response } from '#angular/http';
You should use HttpClientModule,
import { HttpClient, HttpHeaders} from '#angular/common/http';
Keep it mind you have to import HttpClientModule on your app.module.ts (or any other module you have a dependency for it)
import { HttpClientModule } from '#angular/common/http';
Since HttpClientModule came into play. You not longer need for response.json(). Now HttpClient.get() returns an Observable of typed HttpResponse rather than just the JSON data. See docs. (vto.service.ts)
Remove,
.map(response => response.json())
Then you have,
constructor(private http: HttpClient) { }
public getVtos(state: DataSourceRequestState): Observable<DataResult> {
...
return this.http
.get(`${this.vtoUrl}?${queryStr}`)
.map(({ data, total/*, aggregateResults*/ }) =>
(<GridDataResult>{
data: hasGroups ? translateDataSourceResultGroups(data) : data,
total: total,
translateAggregateResults(aggregateResults)
}))
}
Sharing what worked for me. As Luillyfe mentioned Http is now deprecated, HttpClient is to be used. The returned response is already in Json, so no longer need to use .Json method.
constructor(private http: HttpClient) { }
public getVtos(state: DataSourceRequestState): Observable<DataResult> {
const queryStr = `${toDataSourceRequestString(state)}`; //serialize the state
const hasGroups = state.group && state.group.length;
return this.http
.get(`${this.vtoUrl}?${queryStr}`) //send the state to the server
.pipe(
map(<DataResult>({ Data, Total/*, aggregateResults*/ }) => {// process the response
console.log(Data);
return (<GridDataResult>{
data: hasGroups ? translateDataSourceResultGroups(Data) : Data.map(item => {
item.ReportDate = new Date(item.ReportDate); // convert to actual JavaScript date object
return item;
}),
total: Total
})
})
)
}

Response is undefined

I've followed the Heroes tutorial and I am now attempting to retrieve my hero data from an MVC web api rest service. I have modified the GetHeroes() method in my hero.service:
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Rx';
import { HttpClient } from '#angular/common/http';
export class Hero {
constructor(public Id: number, public HeroName: string, public Location: string) { }
}
#Injectable()
export class HeroService {
constructor(private http: HttpClient) { }
results: Observable<string[]>;
private location: string;
getHeroes(): Observable<Hero[]> {
return this.http.get('http://localhost:50125/api/heroes')
.map((response: Response): Hero[] => JSON.parse(response['_body']))
.catch(error => Observable.throw(error));
}
getHero(id: number | string) {
return this.getHeroes()
// (+) before `id` turns the string into a number
.map(heroes => heroes.find(hero => hero.Id === +id));
}
}
I am calling the service method from my component:
import 'rxjs/add/operator/switchMap';
import { Observable } from 'rxjs/Observable';
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, ParamMap } from '#angular/router';
import { Hero, HeroService } from './hero.service';
#Component({
template: `
<h2>HEROES</h2>
<ul class="items">
<li *ngFor="let hero of heroes$ | async"
[class.selected]="hero.Id === selectedId">
<a [routerLink]="['/hero', hero.Id]">
<span class="badge">{{ hero.Id }}</span>{{ hero.HeroName }}
</a>
</li>
</ul>
`
})
export class HeroListComponent implements OnInit {
heroes$: Observable<Hero[]>;
private selectedId: number;
constructor(
private service: HeroService,
private route: ActivatedRoute
) {}
ngOnInit() {
this.heroes$ = this.route.paramMap
.switchMap((params: ParamMap) => {
// (+) before `params.get()` turns the string into a number
this.selectedId = +params.get('id');
return this.service.getHeroes();
});
}
}
My Heroes api controller looks like this:
using HeroesService.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Newtonsoft.Json;
namespace HeroesService.Controllers
{
public class HeroesController : ApiController
{
// GET: api/Heroes
public List<Hero> Get()
{
List<Hero> heroes = new List<Hero>();
Hero superman = new Hero();
superman.Id = 10;
superman.HeroName = "Superman";
superman.Location = "Los Angeles, California";
heroes.Add(superman);
Hero batman = new Hero();
batman.Id = 11;
batman.HeroName = "Batman";
batman.Location = "Chicago, Illinois";
heroes.Add(batman);
return heroes;
}
}
}
I can see data in the Chrome's Network tab that looks like this:
[{"Id":10,"HeroName":"Superman","Location":"Los Angeles, California"},{"Id":11,"HeroName":"Batman","Location":"Chicago, Illinois"}]
Unfortunately, I get an error that looks like this (probably means the response data is undefined):
ERROR SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()
at MapSubscriber.eval [as project] (hero.service.ts:34)
at MapSubscriber._next (map.ts:75)
at MapSubscriber.Subscriber.next (Subscriber.ts:95)
at MapSubscriber._next (map.ts:80)
at MapSubscriber.Subscriber.next (Subscriber.ts:95)
at FilterSubscriber._next (filter.ts:95)
at FilterSubscriber.Subscriber.next (Subscriber.ts:95)
at MergeMapSubscriber.notifyNext (mergeMap.ts:151)
at InnerSubscriber._next (InnerSubscriber.ts:17)
You can take advantage of the fact that HttpClient.get is able to work with JSON data for you. Use the following code to tell HttpClient that the response type is Hero[] and drop your calls to both map and catch:
return this.http.get<Hero[]>('http://localhost:50125/api/heroes');
I expect you are getting an undefined due to the fact that response will not have a property _body.
You're using the new HttpClient but using it the way you would with old http.
getHeroes(): Observable<Hero[]> {
return this.http.get('http://localhost:50125/api/heroes')
.map((response: Response): Hero[] => JSON.parse(response['_body']))
.catch(error => Observable.throw(error));
}
Should be
getHeroes(): Observable<Hero[]> {
return this.http.get<Hero[]>('http://localhost:50125/api/heroes');
}
You can just subscribe to that and you don't need to JSON.parse it.

Get JSON data from API with Angular 2

I am trying to get some JSON data by API that I have created, but it does not receive it. I have used the following Angular code:
getBook(id: string){
return this._http.get(this.url + 'books/' + id)
.map(res => {
console.log(res.json()); //It does not show anything
return res.json();
})
However the getBooks() method has no problems getting the data. There are no errors in the browser console.
This is the whole service code:
import { Injectable } from '#angular/core';
import { Http } from "#angular/http";
import 'rxjs/add/operator/map';
import { Observable } from "rxjs/Observable";
#Injectable()
export class LibrosService {
url: string = "http://localhost/API/public/index.php/api/";
constructor(private _http: Http) { }
getBooks(){
return this._http.get(this.url + 'books')
.map(res => res.json()); //it works
}
getBook(id: string){
return this._http.get(this.url + 'books/' + id)
.map(res => {
console.log(res.json()); //it does not work
return res.json();
})
}
Sorry for my English if it is not very good and thank you for your help.
In Service
getHeroes(): Observable<Hero[]> {
return this.http.get(this.heroesUrl)
.map(this.extractData)
.catch(this.handleError);
}
In Component
getHeroes() {
this.heroService.getHeroes()
.subscribe(
heroes => this.heroes = heroes,
error => this.errorMessage = <any>error);
}
Fortunately, a friend helped me find the solution because the most frustrating thing was console did not show any errors. And the problem was not in service, it was in component.
Here is my solution:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from "#angular/router";
import { BooksService } from "app/services/books.service";
import { Subscription } from "rxjs/Subscription";
#Component({
selector: 'app-book',
templateUrl: './book.component.html'
})
export class BookComponent implements OnInit {
public book: any =[];
private sub: Subscription;
public errorMessage: string;
constructor( private _activatedRoute: ActivatedRoute,
private _booksService: BooksService ) {}
ngOnInit() {
this.sub = this._activatedRoute.params
.subscribe(params => {
let id = +params['id'];
this.getBok(id);
});
}
getBok(id){
this._booksService.getBook(id)
.subscribe(book => {
this.book = book,
error => this.errorMessage = <any>error
});
}
}
Thanks all of you for your help.

Error trying to loop Observable Object in Angular 2

I'm stuck here trying to loop the observable object on my users service.
The Chrome's console throws:
error_handler.js:47 EXCEPTION: undefined is not a function
Here's my code:
users.component.ts
import { Component, OnInit } from '#angular/core';
import { UserService } from '../user.service';
import { Observable } from 'rxjs/Rx';
import { User } from '../user';
#Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
people: Observable<User[]>;
constructor( private _userService: UserService) { }
ngOnInit() {
this.people = this._userService.getAll();
console.log(this.people);
}
}
users.service.ts
import { Injectable } from '#angular/core';
import { Http, Response, Headers } from '#angular/http';
import { Observable } from 'rxjs/Rx';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
import { User } from './user';
#Injectable()
export class UserService {
private baseurl: string= 'http://swapi.co/api';
constructor(private http: Http) {
console.log("User service initialized");
}
getAll(): Observable<User[]>{
let users$ = this.http
.get(`${this.baseurl}/people`,{headers: this.getHeaders()})
.map(this.mapUsers);
return users$;
}
private getHeaders(){
let headers = new Headers();
headers.append('Accept', 'application/json');
return headers;
}
mapUsers(response: Response): User[]{
return response.json().results.map(this.toUser);
}
toUser(r:any): User{
let user = <User>({
id: this.extractId(r),
name: r.name
});
console.log('Parsed user'+user.name);
return user;
}
extractId(personData:any){
let extractedId = personData.url.replace('http://swapi.co/api/people/','').replace('/','');
return parseInt(extractedId);
}
}
users.component.html
<ul class="people">
<li *ngFor="let person of people | async " >
<a href="#">
{{person.name}}
</a>
</li>
</ul>
user.ts
export interface User{
id: number;
name: string;
}
When I remove the HTML code from the template, everything works great (no errors on console) so, I guess there's something wrong with 'people' object, and obviously I can't iterative the response. Please guys, a hand would be appreciated here.
The most likely reason is the way you are handling the map callback
getAll(): Observable<User[]>{
let users$ = this.http
.get(`${this.baseurl}/people`,{headers: this.getHeaders()})
.map(this.mapUsers);
}
mapUsers(response: Response): User[]{
return response.json().results.map(this.toUser);
}
toUser() {}
You need to be careful when using this inside callback functions. The context sometimes messes you up. In this case this in .map(this.toUser) does not point to the class instance. You need to bind it, i.e.
let users$ = this.http
.get(`${this.baseurl}/people`,{headers: this.getHeaders()})
.map(this.mapUsers.bind(this));
When you use bind(this) you are saying that any uses of this inside the mapUsers function should be bound to the class instance.
When you use arrow functions, you don't need to worry about this distinction, as it keeps the lexical scope context
let users$ = this.http
.get(`${this.baseurl}/people`,{headers: this.getHeaders()})
.map(res => response.json().results.map(this.toUser));
Also, even passing the toUser function has the same problem, as you are using this.extractId(r). You also need to bind that
mapUsers(response: Response): User[]{
return response.json().results.map(this.toUser.bind(this));
}

Angular2: converting object to an array for json file

I'm trying to load an array of objects from a JSON and display them in my template with *ngFor in my angular2 app. I'm getting this error Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays..
I've found quite a bit of documentation on this particular error and a fix, but I'm having trouble understanding/translating it into a working fix. From what I understand the *ngFor will only render arrays of data and my home.component is trying to render an object of arrays.
The fix I've read is to write a pipe like this:
#Pipe({ name: 'values', pure: false })
export class ValuesPipe implements PipeTransform {
transform(value: any, args: any[] = null): any {
return Object.keys(value).map(key => value[key]);
}
}
I've tried this but then I'm getting an error that says compiler.umd.js?9df7:14126Uncaught Error: Unexpected value 'HomeComponent' declared by the module 'AppModule' I've built the pipe directly into my home component so I'm unsure why this is a problem.
Here is my code.
home.component.js
import { Component, OnInit, Pipe, PipeTransform } from '#angular/core';
import { Project } from './project';
import { ProjectService } from './project.service';
#Component({
selector: 'home',
templateUrl: './home.html',
styleUrls: ['./home.scss'],
providers: [ProjectService]
})
#Pipe({ name: 'values', pure: false })
export class ValuesPipe implements PipeTransform {
transform(value: any, args: any[] = null): any {
return Object.keys(value).map(key => value[key]);
}
}
export class HomeComponent implements OnInit {
errorMessage: string;
projects: Project[];
selectedProject: Project;
mode = 'Observable';
constructor(private projectService: ProjectService) { }
ngOnInit() { this.getProjects(); }
getProjects() {
this.projectService.getProjects()
.subscribe(
projects => this.projects = projects,
error => this.errorMessage = <any>error);
}
onSelect(project: Project): void {
this.selectedProject = project;
}
}
projects.service.js
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Project } from './project';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class ProjectService {
private projectsUrl = 'data/project.json'; // URL to web API
constructor(private http: Http) { }
getProjects(): Observable<Project[]> {
return this.http.get(this.projectsUrl)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body.data || {};
}
private handleError(error: Response | any) {
// In a real world app, we might use a remote logging infrastructure
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();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
}
project.json
{
"project": [{
"title": "The Upper Crust",
"id": "upper-crust",
"year": "2016",
"category": ["Design", "Web Design"],
"thumbnail": "thumbnails/upper-crust.jpg"
}, (...)
}
Sorry if the answer is already out there I've spent a few hours last night and this morning trying to solve this issue and can't seem to figure it out. I appreciate your help in advance, I'm new to development and am at a loss with much of this stuff.