I am trying to get a json file from HttpClient, but I get a error when I add .subscribe
imports:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpClientModule } from '#angular/common/http';
import { HttpModule, Request, Response, Headers, Http } from '#angular/http';
import { Observable } from 'rxjs';
My code:
When I add .subscribe (yellow marked in image) I got the following error. What does it mean?
Object { _body: error, status: 0, ok: false, statusText: "", headers:
Object, type: 3, url: null }
If you want to make something very clear and organised you should create a service in angular and call the service from your component.
Like this for example:
Service.ts:
import { Injectable } from "#angular/core";
import { Observable, throwError } from "rxjs";
import {
HttpClient,
HttpHeaders,
HttpErrorResponse
} from "#angular/common/http";
import { catchError, map } from "rxjs/operators";
// Set the http options
const httpOptions = {
headers: new HttpHeaders({ "Content-Type": "application/json", "Authorization": "c31z" })
};
#Injectable({
providedIn: "root"
/**
* Service to call all the API
*/
export class ApiService {
constructor(private http: HttpClient) {}
/**
* Function to handle error when the server return an error
*
* #param error
*/
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error("An error occurred:", error.error.message);
} else {
// The backend returned an unsuccessful response code. The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` + `body was: ${error.error}`
);
}
// return an observable with a user-facing error message
return throwError(error);
}
/**
* Function to extract the data when the server return some
*
* #param res
*/
private extractData(res: Response) {
let body = res;
return body || {};
}
/**
* Function to GET what you want
*
* #param url
*/
public getListOfGroup(url: string): Observable<any> {
// Call the http GET
return this.http.get(url, httpOptions).pipe(
map(this.extractData),
catchError(this.handleError)
);
}
}
Component.ts:
import { Component, OnInit } from "#angular/core";
import { ApiService } from "../../services/api.service";
#Component({
selector: "app-example",
templateUrl: "./example.component.html",
styleUrls: ["./example.component.css"]
})
export class ExampleComponent implements OnInit{
url = "/url/path/to/your/server";
constructor(private api: ApiService) {}
ngOnInit() {
this.api
.getListOfGroup(url)
.subscribe(
data => {
console.log(data);
},
err => {
console.log(err);
}
);
}
}
My advice would be to follow the getting start of angular if not you will be quickly lost. Service tutorial angular
Related
I'm using ionic as a front end and Laravel as a back end.
This is the returned JSON data from an API URL, I want to access just the first element which is a.jpg without anything else, I tried using filenames.[0] but it's just displaying [ which means that it's calling the first character not the first element of the array.
Here's the JSON data:
[{"filenames":"[\"a.jpg\",\"b.jpg\",\"c.jpg\"]"}]
Here's my .ts file
import { ApiLandingRecipesService} from '../api-landing-recipes.service'
#Component({
selector: 'app-landing-page',
templateUrl: './landing-page.page.html',
styleUrls: ['./landing-page.page.scss'],
})
export class LandingPagePage implements OnInit {
datauser: any[];
constructor( public api: ApiLandingRecipesService) { }
ngOnInit() {
this.getDataUser();
}
async getDataUser() {
await this.api.getDataUser()
.subscribe(res => {
console.log(res);
this.datauser =res;
console.log(this.datauser);
}, err => {
console.log(err);
});
}
and Here's my service file:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';
import { Observable, throwError } from 'rxjs';
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
};
const apiUrl = "https://example.com/showimages";
#Injectable({
providedIn: 'root'
})
export class ApiLandingRecipesService {
constructor(private http: HttpClient) { }
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
console.error('An error occurred:', error.error.message);
} else {
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
return throwError('Something bad happened; please try again later.');
}
private extractData(res: Response) {
let body = res;
return body || [] ; }
getDataUser(): Observable<any> {
return this.http.get(apiUrl, httpOptions).pipe(
map(this.extractData),
catchError(this.handleError));
}
}
It's because filenames is indeed a string (a json string representation of the array) and not an array.
Try converting the string into an array first.
JSON.parse(filenames)[0]
The value of filenames here is a string and not an array, which is why you're getting [ when you try to access the first element.
You probably need to parse the value, here's an example (assuming datauser) is the JSON data you've shown us.
let filename = JSON.parse(datauser[0].filenames)[0]
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.
when I try to test the app in Ionic serve command, I didn't get any error. But when i try to publish the app, I get the error as "property json does not exist on type object" . The error takes place during the transpile stage:
How to solve this problem? I tried with every possibility, but i didn't get my problem solved.
Home.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { WeatherProvider } from '../../providers/weather/weather';
import { Storage } from '#ionic/storage';
//import { Response } from '#angular/http';
//import 'rxjs/add/operator/map';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
weather:any;
location:{
city:string,
state:string
}
constructor(
public navCtrl: NavController,
private weatherProvider:WeatherProvider,
private storage: Storage) {
}
ionViewWillEnter(){
this.storage.get('location').then((val)=>{
if(val!=null){
this.location = JSON.parse(val);
}else{
this.location = {
city: 'Chennai',
state: 'TN'
}
}
this.weatherProvider.getWeather(this.location.city,this.location.state)
// .map((res: Response) => res.json() )
.subscribe(weather => {
this.weather = weather.current_observation;
});
});
}
}
Weather.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
//import { Response } from '#angular/http';
//import 'rxjs/add/operator/map';
//import 'rxjs/Rx';
#Injectable()
export class WeatherProvider {
apiKey = '6d3243fb22b01d0c';
url;
constructor(public http: HttpClient) {
console.log('Hello WeatherProvider Provider');
this.url = 'http://api.wunderground.com/api/'+this.apiKey+'/conditions/q';
}
getWeather(city, state){
return this.http.get(this.url+'/'+state+'/'+city+'.json')
// .map(res => res.json());
// .map((res: Response) => res.json() );
}
}
Typescript is all about typing. So you should state the type of object you'are receiving from the method getWeather. Start by creating a class Weather at the end of home.ts (look below)
class Weather {
current_observation: string;
}
and make this change:
this.weatherProvider.getWeather(this.location.city,this.location.state)
// .map((res: Response) => res.json() )
.subscribe((weather: Weather) => {
this.weather = weather.current_observation;
});
});
}
ionViewWillEnter(){
this.storage.get('location').then((val) => {
if(val != null){
this.location = JSON.parse(val);
} else{
this.location ={
city: 'miami',
state: 'FL'
}
}
//Try below code
this.weatherprovider.getweather(this.location.city, this.location.state).subscribe(result => {
let weather:any = result;
this.weather = weather.current_observation;
console.log(this.weather);
});
});
}
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?
I have service to parse json
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class TestService {
private tsUrl = './../Test/test.json';
data: Object;
constructor(private http: Http) {}
getTest(): Observable<any> {
return this.http.get(this.tsUrl)
.map(res => res.json());
}
}
But When I call this in my component
private p: any;
constructor(private testService : TestService ) {
this.p =this.testService .getTest().subscribe(
data => {
console.log(data);
};
console.log(this.p);
}
it logs:
What can I do?
And am I doing parse from json file right? File path is correct
#echonax solved my problem but now I see this error message