Angular map function is returning "undefined is not a function" - json

I'm following this tutorial https://www.barbarianmeetscoding.com/blog/2016/04/02/getting-started-with-angular-2-step-by-step-6-consuming-real-data-with-http/, with Angular2 and VS Code.
I created a db.json server to test an api with, with the test data looking like
{
"articles": [{
"id": 1,
"name": "Wand of Lightning",
"description": "A powerful wand of ligthning.",
"price": 50,
"imageUrl": "/assets/images/wand.png",
"specs": [{
"name": "weight",
"value": 10
}, {
"name": "height",
"value": 22
}, {
"name": "material",
"value": "wood"
}],
"reviews": [{
"author": "Jaime",
"title": "I loved it!",
"content": "I loved the wand of ligthning! I usually use it to charge my laptop batteries!",
"rating": 5
}, {
"author": "John Doe",
"title": "Underwhelming",
"content": "I didn't like it at all...",
"rating": 1
}]
}, {
"id": 2,
"name": "Staff of Fire",
"description": "A powerful staff of fire.",
"price": 150,
"imageUrl": "/assets/images/staff-of-fire.png",
"specs": [{
"name": "weight",
"value": 10
}, {
"name": "height",
"value": 22
}, {
"name": "material",
"value": "wood and alabaster"
}],
"reviews": [{
"author": "Jaime",
"title": "I loved it!",
"content": "I loved the wand of ligthning! I usually use it to charge my laptop batteries!",
"rating": 5
}, {
"author": "John Doe",
"title": "Underwhelming",
"content": "I didn't like it at all...",
"rating": 1
}]
}
Now if I try to adapt my code to the sample, I get
undefined is not a function
Here's items.component.ts
import { Component, OnInit } from '#angular/core';
import {ItemsService} from '../items.service';
import {Item} from '../item';
#Component({
selector: 'app-items',
templateUrl: './items.component.html',
styleUrls: ['./items.component.css']
})
export class ItemsComponent implements OnInit {
items: Item[] = [];
errorMessage: string = '';
isLoading: boolean = true;
constructor(private itemsService: ItemsService) { }
ngOnInit() {
this.itemsService
.getAll().
subscribe(
p => this.items =p,
e => this.errorMessage = e,
/* onCompleted */ () => this.isLoading = false
)
}
}
items.service.ts
import { Injectable } from '#angular/core';
import { Http, Response, RequestOptions, Headers } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import {Item} from './item';
#Injectable()
export class ItemsService {
private baseUrl: string ='http://localhost:3000';
constructor(private http: Http) {
}
getAll(): Observable<Item[]>{
let items = this.http
.get(`${this.baseUrl}/articles`, { headers: this.getHeaders()})
.map(this.mapItems)
.catch(this.handleError);
return items;
}
private getHeaders(){
let headers = new Headers();
headers.append('Accept', 'application/json');
return headers;
}
mapItems(response:Response): Item[]{
return response.json().map(this.toItem)
}
toItem(r:any): Item{
let result = <Item>({
id: r.id,
name: r.name,
description: r.description,
price: r.price,
imageUrl: r.imageUrl,
});
console.log('Parsed item:', result);
return result;
}
// this could also be a private method of the component class
handleError (error: any) {
// log error
// could be something more sofisticated
let errorMsg = error.message || `Yikes! There was a problem with our hyperdrive device and we couldn't retrieve your data!`
console.error(errorMsg);
// throw an application level error
return Observable.throw(errorMsg);
}
}
Note: making
return response.json().map(this.toItem)
Into
return response.json()
works. But I would like to get map working.
EDIT: Screenshot

this will solve your issue -
getAll(): Observable<Item[]> {
const items = this.http
.get(`${this.baseUrl}/articles`, {headers: this.getHeaders()})
.map((response: Response) => this.mapItems(response.json()))
.catch(this.handleError);
return items;
}
mapItems(data: Array<any>): Item[] {
return data.map(item => this.toItem(item));
}

I think what you want to map (Array.prototype.map) is the articles in your response object, and not the object itself. Do this:
mapItems(response:Response): Item[]{
return response.json().articles.map(this.toItem)
}

Related

How to I use object based json data in Angular

//Employee service starts
import {
Injectable
} from "#angular/core";
import {
HttpClient,
HttpErrorResponse
} from "#angular/common/http";
import {
IEmployee
} from "../interfaces/employee";
import {
Observable
} from "rxjs/Observable";
import "rxjs/add/operator/catch";
import "rxjs/add/observable/throw";
#Injectable()
export class EmployeeService {
private _url: string = "assets/data/employee.json";
constructor(private http: HttpClient) {}
getEpmloyees(): Observable < IEmployee[] > {
return this.http.get < IEmployee[] > (this._url).catch(this.errorHandler);
}
errorHandler(error: HttpErrorResponse) {
return Observable.throw(error.message || "Server Error");
}
}
//Employee service end
//-------**********-------*********------**********-------
//Employee component starts
#Component({
selector: "app-employee-details",
templateUrl: "./employee-details.component.html",
styleUrls: ["./employee-details.component.scss"]
})
export class EmployeeDetailsComponent implements OnInit {
public employees = [];
public errorMsg;
constructor(private _employeeService: EmployeeService) {}
ngOnInit() {
this._employeeService.getEpmloyees().subscribe(
data => ((this.employees = data),
error => (this.errorMsg = error)
);
}
}
//Employee component ends
<p>{{errorMsg}}</p>
<table border="1">
<tr>
<th>ID</th>
<th>NAME</th>
<th>AGE</th>
<th>Mobile</th>
<th>Action</th>
</tr>
<tbody *ngFor="let employee of employees">
<tr>
<td>{{employee.id}}</td>
<td>{{employee.name}}</td>
<td>{{employee.age}}</td>
<td>{{employee.mob}}</td>
<td><button>Delete</button></td>
</tr>
</tbody>
</table>
<!--Used JSON data
[
{ "id": 1, "name": "sam", "age": 25, "mob": 9996663752 },
{ "id": 2, "name": "adward", "age": 26, "mob": 9124563712 },
{ "id": 3, "name": "yoshi", "age": 27, "mob": 9246663012 },
{ "id": 4, "name": "casie", "age": 29, "mob": 967663012 }
]
-->
<!-- This data through items object I want to use in above code
{
"items": [
{ "id": 1, "name": "harry", "age": 33, "mob": 3476643752 },
{ "id": 2, "name": "jorge", "age": 54, "mob": 7845633712 },
{ "id": 3, "name": "timon", "age": 65, "mob": 9753833012 },
{ "id": 4, "name": "simon", "age": 43, "mob": 8547763012 }
]
}
-->
Above is my Employee service code and employee's component which is working fine and so here also I have shared my JSON data on how I use second JSON data (which is below the first JSON data) and which is based on "items" object so I am in a situation that what changes do I need to get object base JSON data..?
Try with this.employees = data.items
ngOnInit() {
this._employeeService.getEpmloyees().subscribe(
data => ((this.employees = data.items),
error => (this.errorMsg = error)
);
}
}
Try creating a new interface for the Json data you're gonna retrieve.
interface RootObject {
items: IEmployee[];
}
In your service, get this RootObject and return it to your components.
public getEmployees(): RootObject {
return this.http.get<RootObject>(this._url).catch(this.errorHandler);
}
In your Employee Component, retrieve the array of IEmployees from "items" in the RootObject.
ngOnInit() {
this._employeeService.getEmployees().subscribe(
data => ((this.employees = data.items),
error => (this.errorMsg = error)
);
}
}
Be careful, you misspelled Employees in your service function. You might want to enable spell check in your IDE to avoid mistakes ;)

Angular - convert HAL to JSON

The following service extracts category objects from a REST service which returns them in HAL format. Now I try to convert that response into JSON. For that I searched and tried different solutions, e.g. chariotsolutions or so. Some are based on Response from '#angular/http' which is deprecated and which I cannot make work.
How can I do the conversion?
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs/Rx';
import { of } from 'rxjs/observable/of';
import 'rxjs/Rx';
import 'rxjs/add/operator/map';
import { Category } from './category';
#Injectable()
export class CategoryService {
private categoriesUrl = 'http://localhost:8080/account/categories';
constructor(private http: HttpClient) { }
getCategories(): Observable<Category[]> {
return this.http.get<Category[]>(this.categoriesUrl);
}
}
The response as HAL
{
"_embedded": {
"categories": [
{
"id": 1,
"name": "hardware",
"description": "comprises all computer hardware",
"level": "FIRST",
"_links": {
"self": {
"href": "http://localhost:8080/account/categories/1"
},
"categoryEntity": {
"href": "http://localhost:8080/account/categories/1"
}
}
},
{
"id": 2,
"name": "hardware_notebook",
"description": "all notebooks",
"level": "SECOND",
"_links": {
"self": {
"href": "http://localhost:8080/account/categories/2"
},
"categoryEntity": {
"href": "http://localhost:8080/account/categories/2"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/account/categories{?page,size,sort}",
"templated": true
},
"profile": {
"href": "http://localhost:8080/account/profile/categories"
}
},
"page": {
"size": 20,
"totalElements": 8,
"totalPages": 1,
"number": 0
}
}
getCategories(): Observable<Category[]> {
return this.http.get<Category[]>(this.categoriesUrl)
.map((result:any)=>{
console.log(result); //<--it's an object
//result={"_embedded": {"categories": [..]..}
return result._embedded.categories; //just return "categories"
});
}
With Rjxs 6.0 we must use pipe(map)
getCategories(): Observable<Category[]> {
return this.http.get<Category[]>(this.categoriesUrl).pipe(
map((result:any)=>{
console.log(result); //<--it's an object
//result={"_embedded": {"categories": [..]..}
return result._embedded.categories; //just return "categories"
}));
}
Try following:
getCategories(): Observable<Category[]> {
return this.http.get<Category[]>(this.categoriesUrl).map((response)=>{
return response;
})
}

ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed

I have issue with nested JSON file. I use primeNG templates dataTable and treeTable. When I try to access data via API call in console I can see data but in template I'm getting this error:
ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed
json file
{
"CategoryId": "257cf663-f6ba-40f7-69b8-08d527528e70",
"Name": "House Only",
"OverBudgetCalculator": true,
"Scopes": [
{
"ScopeId": 1,
"Name": "Budget",
"Question": {
"QuestionId": 1,
"Content": "What is your maximum budget ?",
"QuestionType": "range",
"Strict": true,
"NeutralScore": 10,
"Weight": 100,
"UpDownSelectionApplied": false,
"Active": true,
"RelatedProductFields": [
{
"RelatedProductFieldId": 3,
"FieldName": "Budget",
"Step": 1000,
"Min": 0,
"Max": 0
}
],
"Answers": []
}
},
{
"ScopeId": 2,
"Name": "Levels",
"Question": {
"QuestionId": 2,
"Content": "Do you want a single or double ?",
"QuestionType": "singleSelection",
"Strict": true,
"NeutralScore": 10,
"Weight": 95,
"UpDownSelectionApplied": false,
"Active": true,
"RelatedProductFields": [
{
"RelatedProductFieldId": 10,
"FieldName": "House_Only_Levels",
"Step": 0,
"Min": 0,
"Max": 0
}
],
"Answers": [
{
"AnswerId": 18,
"Title": "Double Story",
"Content": "Double Story",
"MatchRule": "Double",
"UpDownSpecifications": [],
"Selected": false
},
{
"AnswerId": 19,
"Title": "Single Story",
"Content": "Single Story",
"MatchRule": "Single",
"UpDownSpecifications": [],
"Selected": false
}
]
}
scope.service.ts
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from "#angular/http";
import { AppSessionService } from '#shared/common/session/app-session.service';
import { Observable } from 'rxjs/Observable';
import { Scope } from './scope';
import { TreeTableModule } from 'primeng/components/treetable/treetable';
#Injectable()
export class ScopeService {
constructor(
private http: Http,
private appSessionService: AppSessionService) { }
// GET api/categories/scopes/257CF663-F6BA-40F7-69B8-08D527528E70
getScopes(categoryId): Observable<any> {
let headers = new Headers({ 'Content-Type': 'application/json' })
let options = new RequestOptions({ headers: headers });
return this.http.get('/api/categories/' + categoryId)
.map((res: Response) => res.json())
.catch(this.handleErrorObservable);
}
private extractData(res: Response) {
let body = res.json();
return body.data || {};
}
private handleErrorObservable(error: Response | any) {
console.error(error.message || error);
return Observable.throw(error.message || error);
}
}
scope.component.ts
import { Component, Injector, OnInit, ViewChild } from '#angular/core';
import { AppComponentBase } from '#shared/common/app-component-base';
import { appModuleAnimation } from '#shared/animations/routerTransition';
import { ScopeService } from './scope.service';
import { DataTable } from 'primeng/components/datatable/datatable';
import { Paginator } from 'primeng/components/paginator/paginator';
import { TreeTableModule } from 'primeng/components/treetable/treetable';
#Component({
templateUrl: './scopes.component.html',
animations: [appModuleAnimation()]
})
export class ScopesComponent extends AppComponentBase implements OnInit {
errorMessage: String;
scopes: any = [];
categoryId: String = '257CF663-F6BA-40F7-69B8-08D527528E70';
constructor(
injector: Injector,
private scopeService: ScopeService
) {
super(injector);
}
ngOnInit(): void {
this.getScopes(this.categoryId);
}
getScopes(categoryId) {
this.scopeService.getScopes(categoryId).subscribe(values => {
this.scopes = values;
console.log(this.scopes);
})
}
}
This is component file with treeTable
scope.component.html (treeTable)
<p-treeTable [value]="scopes" [style]="{'margin-top':'50px'}">
<p-header>Editable Cells with Templating</p-header>
<p-column field="CategoryId" header="ScopeId">
<ng-template let-node="rowData" pTemplate="body">
<input type="text" [(ngModel)]="categories.Scopes.ScopeId" style="width:100%;border-width:0px 0px 1px 0px">
</ng-template>
</p-column>
<p-column field="Name" header="Name">
<ng-template let-node="rowData" pTemplate="body">
<input type="text" [(ngModel)]="categories.Scopes.Name" style="width:100%;border-width:0px 0px 1px 0px">
</ng-template>
</p-column>
</p-treeTable>
This is component file with dataDatable.
scope.components.html (dataTable)
<p-dataTable [value]="scopes"
selectionMode="single"
[rows]="10"
[responsive]="true">
<p-column field="Scopes" header="Scope name">
<ng-template let-account="rowData" pTemplate="body">
<ul>
<li *ngFor="let scope of categories.scopes">
{{scope.ScopeId}} - {{scope.Name}}
</li>
</ul>
</ng-template>
</p-column>
</p-dataTable>
When I use dataTable option I'm getting different error.
ERROR TypeError: val.slice is not a function
enter image description here
enter image description here

parsing json data into objects with type script

My json data:
{
"status": "OK",
"data": {
"id": 3,
"initials": "mci",
"nom": "chabli",
"prenom": "mohammed Yassin",
"password": "m1ltRoJZRS",
"username": "yassine.chabli#edu.umi.ac.ma",
"photo": null,
"enabled": true,
"roles": [{
"id": 2,
"roleName": "DP",
"topSupression": false,
"lesGrilles": [{
"id": 2,
"affecte": true,
"privilege": {
"id": 1,
"actionName": "AjouterAVV"
}
},
{
"id": 3,
"affecte": true,
"privilege": {
"id": 2,
"actionName": "ModifierAVV"
}
}
]
},
{
"id": 3,
"roleName": "CP",
"topSupression": false,
"lesGrilles": [{
"id": 4,
"affecte": true,
"privilege": {
"id": 1,
"actionName": "AjouterAVV"
}
},
{
"id": 5,
"affecte": true,
"privilege": {
"id": 2,
"actionName": "ModifierAVV"
}
}
]
}
],
"departement": {
"id": 1,
"libelle": "Software",
"topSupression": false,
"area": {
"id": 1,
"libelle": "Maroc",
"topSupression": false
}
}
},
"error": null
}
I get this data successfully in my angular component like this:
import {AfterContentInit, Component, OnInit} from '#angular/core';
import {UserService} from '../services/user.service' ;
import {User} from '../classes/user' ;
import {Departement} from '../classes/departement';
import {Region} from '../classes/region';
import {Role} from '../classes/role';
import {Grille} from '../classes/grille';
import {Privilege} from '../classes/privilege';
#Component({
selector: 'rb-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: User = new User() ;
dept: Departement = new Departement();
area: Region = new Region();
roles: Role[] ;
grilles: Grille[];
privilege: Privilege
status: string ;
error: string;
constructor(public _us: UserService ) {
}
ngOnInit() {
this._us.getOneUser().subscribe(
data => (this.user = data.data, this.status = data.status, this.error = data.error , this.dept = this.user.departement,
this.area = this.dept.area , this.roles = this.user.roles),
error => alert(error),
() => console.log(this.roles)
);
}
}
In my HTML view I try to show some attribute like {{user.username }} it works.
But when I try to show like user.roles[0].id or something like that I have some error in the console:
the property id is undefined
While when I'm logging the user variable in the console, I can see that the property id of my roles array exist.

AngularJS 2 : Getting data from json file not working

I am trying to get the json data from an Angular service hero.service.ts. When using the fake http API inMemoryDataService, everything works fine and I am getting the json data from the in-memory-data.service.ts file. But when I try to get the data from a real json file, it does not work and I am getting an error 'collection not found' in the browser.
Here are the files contents (all 3 files are located in the app/ folder):
hero.service.ts :
import { Injectable } from '#angular/core';
import { Headers, Http , Response} from '#angular/http';
import 'rxjs/add/operator/toPromise';
import { Hero } from './hero';
#Injectable()
export class HeroService {
private heroesUrl = 'app/fakeListOfHeroes'; // URL to web api
//private heroesUrl = 'app/heroes.json'; // URL to JSON file
constructor(private http: Http) { }
getHeroes(): Promise<Hero[]>
{
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json().data)
.catch(this.handleError);
}
private handleError(error: any)
{
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
hero.service.ts :
export class InMemoryDataService {
createDb() {
let fakeListOfHeroes = [
{id: 11, name: 'Mr. Nice'},
{id: 12, name: 'Narco'},
{id: 13, name: 'Bombasto'},
{id: 14, name: 'Celeritas'},
{id: 15, name: 'Magneta'},
{id: 16, name: 'RubberMan'},
{id: 17, name: 'Dynama'},
{id: 18, name: 'Dr IQ'},
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'}
];
return {fakeListOfHeroes};
}
}
heroes.json :
{
"data": [{
"id": 11,
"name": "Mr. Nice"
}, {
"id": 12,
"name": "Narco"
}, {
"id": 13,
"name": "Bombasto"
}, {
"id": 14,
"name": "Celeritas"
}, {
"id": 15,
"name": "Magneta"
}, {
"id": 16,
"name": "RubberMan"
}, {
"id": 17,
"name": "Dynama"
}, {
"id": 18,
"name": "Dr IQ"
}, {
"id": 19,
"name": "Magma"
}, {
"id": 20,
"name": "Tornado"
}]
}
Error in the browser:
error in browser
Any help would be appreciated. Thanks!
Found it ! It was due to the InMemoryBackendService and InMemoryDataService used in main.ts file, that seem to 'redirect' the calls from http.get method. Commenting those lines from main.ts file resolved the issue :
// Imports for loading & configuring the in-memory web api
import { XHRBackend } from '#angular/http';
//import { InMemoryBackendService, SEED_DATA } from 'angular2-in-memory-web-api';
//import { InMemoryDataService } from './in-memory-data.service';
// The usual bootstrapping imports
import { bootstrap } from '#angular/platform-browser-dynamic';
import { HTTP_PROVIDERS } from '#angular/http';
import { AppComponent } from './app.component';
import { appRouterProviders } from './app.routes';
bootstrap(AppComponent, [
appRouterProviders,
HTTP_PROVIDERS
/*,
{ provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server
{ provide: SEED_DATA, useClass: InMemoryDataService } // in-mem server data
*/
]);