Angular 5 "map is not defined" - json

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

Related

IONIC API Undefined

I have an IONIC APP with CORDOVA. I Just want to GET a JSON from an URL.
I Created a service call rest.service.ts
rest.service.ts
import { Injectable } from '#angular/core';
import { HTTP } from '#ionic-native/http/ngx';
#Injectable({
providedIn: 'root'
})
export class RestService {
BASE_URL = 'http://whatever.....';
constructor(public http: HTTP) {}
getProjects() {
const URL = this.BASE_URL + 'getProjects';
this.http.get(URL, {}, { 'Content-Type': 'application/json' })
.then(answer => {
return JSON.parse(answer.data);
})
.catch(error => {
console.log(error.status);
console.log(error.error); // error message as string
console.log(error.headers);
});
}
}
Here in this file I can see the info. If I insert something like...
console.log(JSON.parse(answer.data));
I can see the results in JSON just as I Want.
The problem is when I try to use this methods in other files...
otherpage.page.ts
import { Platform } from '#ionic/angular';
import { RestService } from './../rest.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-otherpage',
templateUrl: './otheropage .page.html',
styleUrls: ['./otherpage .page.scss']
})
export class OtherPage implements OnInit {
projects;
constructor(
public platform: Platform,
public rest: RestService,
) {
this.projects = this.rest.getProjects();
console.log(this.projects); // UNDEFINED
}
ngOnInit() { }
}
Here... this.projects... is undefined... ¿What is happening? I tried platform.ready, insert in ngOnInit... nothing works.
You need to modify the service and subscribe this service your page.
BASE_URL = 'http://whatever.....';
getProjects() {
const URL = this.BASE_URL + 'getProjects';
return this.http.get(URL, {}, { 'Content-Type': 'application/json' });
}
Subscribe this service observable in your page.ts file.
this.rest.getProjects().subscribe((answer)=>{
this.projects = JSON.parse(answer.data);
console.log(this.projects); // here you get the json
},error=>{
consoole.log(error)
});
Note:
console.log(this.projects); // UNDEFINED
Because this line executes before the http observable send the response, you need to subscribe that http observable to get the json.

How to parse an array of json object to typescript (object) after a get method

I am a beginner in angular and start to build my first app.My goal is to build a generic service that will be inherited from others service. I am following the structure of this link to my approach Generic HTTP Service .In read method i`m using Serializer class to convert the response json object to my typescript an it work. I got a map error. How can I solve it?
Service code:
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Resource } from '../models/resource.model';
import { Observable } from 'rxjs/Observable';
import { Serializer } from '../serializer/serializer';
import { AuthenticationService } from './authentication.service';
#Injectable()
export class SharedService<T extends Resource> {
constructor(
private httpClient: HttpClient,
private url: string,
private endpoint: string,
private authentication: AuthenticationService,
private serializer: Serializer
) { }
create(resource: T) {
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json; charset=utf-8');
return this.httpClient.post(`${this.url}/${this.endpoint}`, JSON.stringify(resource), { headers: headers });
}
//PUT
update(item: T): Observable<T> {
return this.httpClient.put<T>(`${this.url}/${this.endpoint}`, JSON.stringify(item), { headers: this.addHeaders() })
.map(data => this.serializer.fromJson(data) as T);
}
//GET
read(id: number): Observable<T> {
return this.httpClient.get(`${this.url}/${this.endpoint}/${id}`, { headers: this.addHeaders() })
.map((data: any) => this.serializer.fromJson(data) as T);
}
//GET ALL
list(): Observable<T[]> {
return this.httpClient.get<T>(`${this.url}/${this.endpoint}` , {headers : this.addHeaders()})
.map((data: any) =>
this.convertData(data.items));
}
protected convertData(data: any): T[] {
return data.map(item => {this.serializer.fromJson(item)});
}
protected addHeaders() {
let token = ('Bearer ' + this.authentication.getToken()).valueOf();
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json; charset=utf-8').set('Authorization', token);
return headers;
}
}
UserService:
import { Injectable } from '#angular/core';
import { SharedService } from './shared.service';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { User } from '../models/user/user.model';
import { AuthenticationService } from 'app/service/authentication.service';
import { UserSerializer } from '../serializer/user-serializer';
import { NgForm } from '#angular/forms';
#Injectable()
export class UserService extends SharedService<User>{
constructor(httpClient: HttpClient, authenticate: AuthenticationService) {
super(httpClient,
'http://localhost:8084/SuperCloud/webresources',
'user',
authenticate,
new UserSerializer()
);
}
UserSerializer:
import { User } from "../models/user/user.model";
import { Serializer } from "./serializer";
import { Resource } from "../models/resource.model";
export class UserSerializer extends Serializer {
fromJson(json: any): Resource {
const user = new User();
user.id = json.id;
user.name = json.name;
user.surname = json.surname;
user.email = json.email;
user.phoneNumber = json.phoneNumber;
user.password = json.password;
user.username = json.username;
user.active = json.active;
console.log('serializer');
console.log(user);
return user;
}
}
User model:
import { Resource } from "../resource.model";
export class User extends Resource{
username: string;
email: string;
name: string;
surname: string;
phoneNumber: string;
password?: string;
active : boolean;
}
UserService inherited inherited:
ngOnInit() {
this.userService.list().subscribe(
(data) => console.log(data)
);
}
Error:
core.es5.js:1020 ERROR TypeError: Cannot read property 'map' of
undefined
at UserService.SharedService.convertData (shared.service.ts:53)
at MapSubscriber.eval [as project] (shared.service.ts:48)
at MapSubscriber._next (map.js:79)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at MapSubscriber._next (map.js:85)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at FilterSubscriber._next (filter.js:90)
at FilterSubscriber.Subscriber.next (Subscriber.js:95)
at MergeMapSubscriber.notifyNext (mergeMap.js:151)
at InnerSubscriber._next (InnerSubscriber.js:25)
First of all, I assume the data that you passed into convertData function is not an array.
Only Array or Observable have map function in this case.
Also, chained function has been changed into pipeable operators in RxJS 6
https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
Secondly, looking at the error message - I don't think the data value returned from the endpoint has value.
Third, data.map(item => {this.serializer.fromJson(item)}); - if the arrow function inside the map function is wrapped in curly bracket, you need to have return keyword.
in other word, data.map(item => {this.serializer.fromJson(item)}); should be data.map(item => this.serializer.fromJson(item)); or data.map(item => {return this.serializer.fromJson(item)});
Use subscribe instead of map to return the response.
return this.httpClient
.put<T>(`${this.url}/${this.endpoint}`, JSON.stringify(item), {
headers: this.addHeaders()
})
.subscribe(data => this.serializer.fromJson(data) as T);
BTW RXJs6 has changed the implementation of using observable map function

Unexpected token < in JSON at position 0 when attempt call ASP.NET controller

I'm found and read many post about this error but don't found analogous or similar issues.
Attempt get data from MVC controller using post in angular 2.
Controller:
[RoutePrefix("")]
public class CategoryController : ApiController
{
[HttpPost, Route("createNode")]
public object CreateNode([FromBody]string nodeText)
{
return Json( new { nodeText = "test"});
}
}
function in component
onclickCreateFolder(categoryName: string) {
this.categoryService.createNode(categoryName).then(result => {
});
angular-2 service
import { Injectable } from '#angular/core';
import { Http, RequestOptions, Request, RequestMethod, Headers } from '#angular/http';
import { BaseService } from '../../base/base.service'
import { CategoryViewModel } from '../model/category-tree.model';
import { TreeNode } from 'primeng/primeng';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class CategoryTreeService {
private apiUrl: string = '/';
constructor(private baseService: BaseService, private http: Http) {
}
createNode(nodeText: string): Promise<any> {
return this.baseService.post(this.apiUrl + "createNode", JSON.stringify({nodeText}));
}
}
I am using base service. Here is a part that initiate post request:
import { Injectable } from '#angular/core';
import { Router } from '#angular/router';
import { Response, RequestOptionsArgs, ResponseContentType } from '#angular/http';
import { Http, RequestOptions, Request, RequestMethod, Headers } from '#angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/map';
#Injectable()
export class BaseService {
private headers: Headers = new Headers({ 'Content-Type': 'application/json; charset=utf-8', 'Data-Type': 'json' });
constructor(private http: Http, private router: Router) {
}
public post<T>(url: string, body: any, options?: RequestOptionsArgs): Promise<T> {
return this.http.post(url, body, this.mergeHeaders(options))
.toPromise()
.then(response => response.json() as T)
.catch(this.handleError.bind(this));
}
private mergeHeaders(options?: RequestOptionsArgs): RequestOptionsArgs {
let args = options || {};
args.headers = args.headers || this.headers;
return args;
}
public handleError(error: any) {
if (error.status == 400) {
switch (error.statusText) {
case "Authentication":
this.router.navigate(['/error/auth']);
break;
default:
return Promise.reject(error);
}
return;
}
return Promise.reject(error.toString());
}
}
I understand the reason for the error because in response i see my single html page. Also in debug i see that method in ASP.NET controller is not called. Maybe error in ASP.NET MVC routing?
Already spent a lot of time, but I still do not understand where the error is. What i'm doing wrong?

SyntaxError: Unexpected token < in JSON at position 3 in ionic 2

I'm having an error in Ionic 2 "SyntaxError: Unexpected token < in JSON at position 3". My json format is correctly structured using spring boot.
Below is my spring boot code.
Appreciate your help.
#RequestMapping(value="/myview", method=RequestMethod.GET, produces = "application/json")
#ResponseBody
List<Client> myView( #ModelAttribute("client") Client client){
List<Client> data=(List<Client>) clientService.getAll();
return data;
}
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class PeopleService {
people: any;
constructor(public http: Http) {}
load(){
if (this.people) {
return Promise.resolve(this.people);
}
return new Promise(resolve => {
this.http.get('http://localhost:8080/myview')
.map((res)=>res.json()).subscribe((data)=>{
console.log(data);
this.people=data;
resolve(this.people);
}, err=>{console.log(err)});
});
}// end load function
}
JSON from /myview
[{"id":1,"username":"donald#yahoo.com","policy":"V121293031","name":"Donald","mobile":"0504735260","email":"dcgatan#gmail.com","address":"Dafza Dubai","amount":800.98,"datetimestamp":1472861297000},{"id":3,"username":"dcgatan78#gmail.com","policyno":"V38998933","fname":"Donald","mobile":"0501234567","email":"dcgatan#gmail.com","address":"MetDubai","amount":334.34,"datetimestamp":1472862939000},{"id":4,"username":"dcgatan#yahoo.com","policyno":"V34342323","fname":"Snoopy","mobile":"0501234567","email":"dcgatan#yahoo.com","address":"Metlife Dafza Dubai","amount":883.43,"datetimestamp":1472916463000}]
My http://localhost:8080/myview is not working because when I tried the below code with Array value it works. How to call the http instead of putting static values in the Array?
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class PeopleService {
people: Array<any> = [{"id":1,"username":"donald#yahoo.com","policyno":"V121293031","fname":"Donald","mobile":"0504735250","email":"dcgatan#gmail.com","address":"Dafza Dubai","amount":800.98,"datetimestamp":1472861297000},{"id":3,"username":"dcgatan78#gmail.com","policyno":"V38998933","fname":"Donald","mobile":"0501234567","email":"dcgatan#gmail.com","address":"MetLife Dubai","amount":334.34,"datetimestamp":1472862939000}];
constructor(private http: Http) {}
load(){
if (this.people) {
return Promise.resolve(this.people);
}
return new Promise(resolve => {
this.http.get('http://localhost:8080/myview')
.map((res)=>res.json())
.subscribe((data)=>{
this.setPeople(data);
resolve(this.people);
});
});
}// end load function
setPeople(data) {
if (data) {
for (let id of Object.keys(data)) {
let item = data[id];
item.id = id;
this.people.push(item);
}
}
}
}
Your call to /myview would be returning incorrect json. It must be having HTML elements. Performing res.json() extracts data from _body of the response, if it's valid. But in your case it is throwing an error.

Problems with Angular 2 Http GET

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