Angular http.post not sending data with subscribe - javascript

I am trying to post data to my api. The post.subscribe does not send any data, no error is being thrown. The API is 100% working.
Here is my code:
httpservice.ts
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Product } from './Product';
import { Observable, of } from 'rxjs';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class HttpService {
baseURL = 'https://localhost:2403/testapi/';
constructor(private http: HttpClient) {
this.products = new Array();
}
products: Product[];
post(product: Product): boolean {
if ( !this.checkIfProductExistsAlready(product) ) {
console.log('posting product');
this.http.post<any>(baseURL,{"product": product.name, "price": 10, "done": false})
.subscribe((data) => {
console.log(data);
product.id = data.id;
console.log('hi');
},
error => console.log('uojdsigdk' + error)
);
console.log('posted ' + product.id);
this.products.push(product);
return true;
} else {
return false;
}
}
form.component.ts
addItem(): void {
this.isError = false;
if (!this.httpservice.post(new Product(-1, this.name, this.price, 0))) {
this.isError = true;
}
}
This is the provider declaration in the app.module.ts
[...]
providers: [HttpService],
[...]
Is it possible that this is caused by a config file?

Maybe this happens because you try to access the local webserver over https?
baseURL = 'https://localhost:2403/testapi/';
Otherwise use fiddler, do a post request on your api and look what the server is returning. :)

I think baseURL is undefined inside your function scope. Try this.baseURL instead. Also make sure your local webserver is serving HTTPS, as mentioned before
this.http.post<any>(baseURL, product);
becomes
this.http.post<any>(this.baseURL, product);
On a side node, a couple of things are potentially wrong with your Observable code, as well as the way you are injecting your Service in your app, as has been mentioned in comments.

add response type
addItem(): void {
this.isError = false;
if (!this.httpservice.post(new Product(-1, this.name, this.price, 0), { observe: 'response',responseType: 'text' })) {
this.isError = true;
}
}

Related

How to get status code in angular observable

I have services below that I'd like to get status code and handle if statements in it but so far I couldn't figure it out
import { Injectable } from '#angular/core';
import { EnvService } from './env.service';
import { tap } from 'rxjs/operators';
import { Observable, from } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { NativeStorage } from '#ionic-native/native-storage/ngx';
import { Plugins } from '#capacitor/core';
const { Storage } = Plugins;
#Injectable({
providedIn: 'root'
})
export class InvoicesServiceService {
token: any;
constructor(
private env: EnvService,
private http: HttpClient,
private nativeStorage: NativeStorage
) {
Storage.get({ key: 'token' }).then((token: any) => {
this.token = JSON.parse(token.value)
}).catch(error => console.error(error));
}
// All
getInvoices(): Observable<any> {
const tokenPromise =
this.token === undefined
? Storage.get({ key: 'token' })
: Promise.resolve(this.token);
return from(tokenPromise).pipe(
switchMap((token) => {
this.token = this.token;
const httpOptions = {
headers: new HttpHeaders({
Accept: 'application/json, text/plain',
'Content-Type': 'application/json',
Authorization: this.token.access_token,
}),
};
return this.http
.get(`${this.env.Dashboard}` + '/invoices', httpOptions)
.pipe(map((data) => data));
})
);
}
What I try to do is that if, status code is 403 redirect user to specific route other than that just return data.
any idea?
In component where you subscribe this service you can handle error
this.service
.getInvoices()
.subscribe((response) => {
// This is success
},
(error: HttpErrorResponse) => {
// Handle error
// Use if conditions to check error code, this depends on your api, how it sends error messages
});
Another way to handle in service itself.
return this.http
.get(`${this.env.Dashboard}` + '/invoices', httpOptions)
.pipe(map((data) => data))
.toPromise()
.then((response) => {
//Success
})
.catch((error: HttpErrorResponse) => {
// Handle error
});
Hope this helps.
The error is not always sent in the headers.
Sometimes the erros comes via HTML message, like when NGINX tells you someting before you even get to the backend:
<html>
<head><title>413 Request Entity Too Large</title></head>
<body>
<center><h1>413 Request Entity Too Large</h1></center>
<hr><center>nginx</center>
</body>
</html>
In these cases you should use if (error.includes('413 Request Entity Too Large')) {...}

Angular subscription on observable returns undefined

My Service
import { Injectable } from "#angular/core";
import { Observable, of } from "rxjs";
import { SearchResult } from "../Components/container-search/Models/SearchResult";
import { environment } from "../../environments/environment";
import { HttpClient, HttpHeaders } from "#angular/common/http";
#Injectable({
providedIn: "root",
})
export class ContainerService {
constructor(public http: HttpClient) {}
private SearchResults: SearchResult[] = [];
public headers = {
headers: new HttpHeaders({
"Content-Type": "application/json",
}),
};
public Search(): Observable<SearchResult[]> {
if (this.SearchResults.length === 0) {
this.http
.get<SearchResult[]>(
environment.endpointURL + "/FooBar/Search",
this.headers
)
.subscribe((x) => {
this.SearchResults = x;
return of(this.SearchResults);
});
} else {
return of(this.SearchResults);
}
}
}
When I call Search() in my component it returns
TypeError: Cannot read property 'subscribe' of undefined
My calling code is
ngOnInit(): void {
this.dataSource.paginator = this.paginator;
this.searchService.Search().subscribe((x) => {
this.dataSource = new MatTableDataSource<SearchResult>(x);
});
}
Can someone explain why this code this.searchService.Search() would always return with the above error?
The .subscribe call is returning an Observable, but that isn't what's being returned by the Search method. The subscription is an asynchronous process. The subscribe kicks off that process and only reacts when the http call returns, but the Search method keeps executing and returns undefined.
The below code will return the Observable from the http call directly and fix your issue.
import { tap } from 'rxjs/operators';
public Search(): Observable<SearchResult[]> {
if (this.SearchResults.length === 0) {
return this.http
.get<SearchResult[]>(
environment.endpointURL + "/FooBar/Search",
this.headers
).pipe(tap(x => this.SearchResults = x));
} else {
return of(this.SearchResults);
}
}

Trying to use tokenNotExpired from angular2-jwt but getting error in modules

I am trying to use tokenNotExpired of angular2-jwt for check if user is logged in or not. But when i implement this I get below error in cli:-
ERROR in node_modules/angular2-jwt/angular2-jwt.d.ts(3,10): error TS2305: Module '"d:/Visual Studio/asp.net/mean_blog/client/node_modules/rxjs/Observable"' has no exported member 'Observable'.
node_modules/rxjs/Observable.d.ts(1,15): error TS2307: Cannot find module 'rxjs-compat/Observable'.
I have install angular2-jwt using "npm install angular2-jwt#latest --save" commmand.
Below is the auth.service.ts code:-
import { Injectable } from '#angular/core';
import { Http, Headers, RequestOptions } from '#angular/http';
import { map, take } from 'rxjs/operators';
import { tokenNotExpired } from 'angular2-jwt';
#Injectable({
providedIn: 'root'
})
export class AuthService {
authToken;
user;
options;
constructor(private http: Http) { }
createAuthenticationHeaders(){
this.loadToken();
this.options = new RequestOptions({
headers:new Headers({
'Content-Type':'application/json',
'authorization':this.authToken
})
})
}
loadToken(){
this.authToken = localStorage.getItem('token');
}
registerUser(user) {
return this.http.post('/api/auth/register', user).pipe(map(res => res.json()));
}
checkUsername(username) {
return this.http.get('/api/auth/checkUsername/' + username).pipe(map(res => res.json()));
}
checkEMail(email) {
return this.http.get('/api/auth/checkEmail/' + email).pipe(map(res => res.json()));
}
login(user){
return this.http.post('/api/auth/login',user).pipe(map(res=>res.json()));
}
logout(){
this.authToken = null;
this.user = null;
localStorage.clear();
}
storeUserData(token, user){
localStorage.setItem('token',token);
localStorage.setItem('user',JSON.stringify(user));
this.authToken = token;
this.user = user
}
getProfile(){
this.createAuthenticationHeaders();
return this.http.get('/api/auth/profile',this.options).pipe(map(res=>res.json()));
}
loggedIn() {
return tokenNotExpired();
}
}
I have also check the dependency in package.json that is also added correctly.
I don't know from where this error is occured.
Some function of rxjs was deprecated in angular 6, so I use rxjs-compat for backward compatibility. It solve the issue.

Angular 2 - Cannot read property '...' of undefined

Very new to Angular. I checked similar questions but they either dive into specifics or I just don't understand the solutions.
The actual error:
"Cannot read property 'idPlanet' of undefined at Object.eval [as updateRenderer] (PlanetComponent.html:11)"
The issue:
planetDetail.idPlanet is undefined most probably?
Suspect:
getPlanetDetail()
planet.component.html:
<div class="col-sm-9">
ID: {{ planetDetail.idPlanet }}
</div>
planet.component.ts:
import {
Component,
OnInit
} from '#angular/core';
import { Planet } from './planet';
import { PlanetService } from './planet.service';
#Component({
selector: 'planets',
templateUrl: './planet.component.html'
})
export class PlanetComponent implements OnInit {
private planets: Planet[];
private planetDetail: Planet;
constructor(
private planetService: PlanetService
) {}
public ngOnInit(): void {
this.getPlanetDetail();
this.getPlanets();
}
public getPlanets() {
this.planetService.getPlanets()
.subscribe(
(planets) => this.planets = planets
);
}
public getPlanetDetail() {
this.planetService.getPlanetDetail()
.subscribe(
(planets) => this.planetDetail = planets
);
}
}
planet.service.ts:
import { Injectable } from '#angular/core';
import { Headers, Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Planet } from './planet';
#Injectable()
export class PlanetService {
private planetsUrl = 'http://localhost/index.php/api/planet/'; // URL to web api
// Injecting the http client into the service
constructor(private http: Http) {}
public getPlanets(): Observable<Planet[]> {
return this.http.get(this.planetsUrl + 'planets/id_sol/1')
.map(this.parseData)
.catch(this.handleError);
}
public getPlanetDetail(): Observable<Planet> {
return this.http.get(this.planetsUrl + 'planet/id_planet/1')
.map(this.parseData)
.catch(this.handleError);
}
private parseData(res: Response) {
let body = res.json();
if (body instanceof Array) {
return body || [];
} else {
return body.post || {};
}
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
}
I'm at a loss tbh, I tried to build my getPlanetDetail() method from getPlanets() which works fine. Should I use a promise?
I'm having a hard time figuring out where exactly I can put console.log() to debug. I'm using angular-starter kit from Github.
Thanks for your time.
edit 1: the api outputs {"idPlanet":"1","name":"Earth"}
As the request is asynchronous sometime the value will not be fetched from the server when the page loads, therefore, the planetDetail is undefined. in order to avoid this you can use add '?' between planetDetail and idPlanet. that prints only if it has the value
ID: {{ planetDetail?.idPlanet }}
If you want to print the result or error
public getPlanetDetail() {
this.planetService.getPlanetDetail()
.subscribe(
(planets) => {
console.log(planets);
this.planetDetail = planets
},
error => {console.log(error);}
);
}
Since your response is {"idPlanet":"1","name":"Earth"}, try the following:
public getPlanetDetail(): Observable<Planet> {
return this.http.get(this.planetsUrl + 'planet/id_planet/1')
.map(res => res.json())
.catch(this.handleError);
}
my friend to debug if your 'planetDetail' is populated, just add 'console.log (planetDetail)' in the 'subscribe' method. Follow the example below.
public getPlanetDetail() {
this.planetService.getPlanetDetail()
.subscribe(
(planets) => this.planetDetail = planets
);
}
public getPlanetDetail() {
this.planetService.getPlanetDetail()
.subscribe(
(planets) => this.planetDetail = planets, (err) => (err), () => console.log(this.palnetDetail)
);
}
More about subscribe()
subscribe(function(response) {
console.log("Success Response" + response)
},
function(error) {
console.log("Error happened" + error)
},
function() {
console.log("the subscription is completed")
});

Value become null for this in Promise callback

I am using the following code value of this become null when i call it inside the then function here is the code. Am i doing something wrong or it is like this or there is any work around to resolve this issue
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Headers, RequestOptions } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { CanActivate, Router } from '#angular/router';
import { AuthService } from '../services/auth.service';
import { WebAPISettings } from '../services/webapisettings.service';
#Injectable()
export class LoginService {
//_ngWEBAPISettings: WebAPISettings;
//_authService: AuthService;
constructor(private http: Http, private ngWEBAPISettings: WebAPISettings, private authService: AuthService) {
//this._ngWEBAPISettings = ngWEBAPISettings;
//this._authService = authService;
}
public login(username: string, password: string): Promise<any> {
let data = "grant_type=password&username=" + username + "&password=" + password;
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
let options = new RequestOptions({ headers: headers });
try {
debugger;
return this.http.post(this.ngWEBAPISettings.apiServiceBaseUri + "token", data, options)
.toPromise()
.then(function (res: Response) {
debugger;
let body = res.json();
//let _authService: AuthService = new AuthService();
this.authService.fillAuthDataFromLogin(body);
//this.router.navigate(['/Home']);
return body.data || {};
})
.catch(this.handleError);
}
catch (error) {
console.log(error);
}
}
private extractData() {
}
private handleError(error: any) {
debugger;
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
return Observable.throw(errMsg);
}
}
and i am debugging it in the chrome here is the screenshot please help me in fixing it.
after using the arrow function same thing check the screen shot
one thing to mention i am using Angular2 RC4.
You could use an arrow function to be able to use the lexical this:
return this.http.post(this.ngWEBAPISettings.apiServiceBaseUri + "token", data, options)
.toPromise()
.then((res: Response) => { // <-----
(...)
});
This way, this will correspond to the instance of the LoginService service.
See this doc for more details:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Categories

Resources