Angular - HTTPClientModule delete request not working - javascript

I am making a simple delete request from my angular app but nothing is happening and no error is appearing. My service code is as follows :
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class TodoService {
todoUrl = 'https://example.herokuapp.com/api/todoDB/';
constructor(private http: HttpClient) { }
getTodo() {
return this.http.get(this.todoUrl);
}
postTodo(todoObject: any) {
return this.http.post(this.todoUrl , todoObject);
}
deleteTodo(id: any) {
const url = `${this.todoUrl}${id}`;
console.log(url); // *** This is printing correct URL
return this.http.delete(url);
}
}
My getTodo() and postTodo() are working completely fine but the deleteTodo() method is not working and also it does not show any error either. When I put the URL from the console.log(url) in postman, it works but it is not working from my app.I am using the following code in my component to access the deleteTodo() method of my service :
removeTodo(i: any) {
this.todoService.deleteTodo(this.todoArray[i]._id);
}
My delete route of server :
// Delete Todo
router.delete('/:id' , (req , res) => {
Todo.findById(req.params.id)
.then((todo) => todo.remove().then(() => res.json({success : true})))
.catch(err => res.json({success : false}).status(404))
});

You need to subscribe to the Observable
Code Snippet for your problem:
removeTodo(i: any) {
this.todoService.deleteTodo(this.todoArray[i]._id).subscribe(e=>{
// Callback
// Perform Actions which are required after deleting the id from the TODO
});
}
Additional Reference:
https://www.pluralsight.com/guides/posting-deleting-putting-data-angular
https://angular.io/guide/http#making-a-delete-request

Modify your code to support catchError and throwError using pipe for debugging.
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
deleteTodo(id: any) {
const url = `${this.todoUrl}${id}`;
return this.http.delete(url).pipe(
catchError((err) => {
console.log('error caught in service')
console.error(err);
return throwError(err); //Rethrow it back to component
})
);
}

Related

You provided 'undefined' where a stream was expected. in token interceptor

I am trying to make an interceptor to refresh the token, but it throws me this error and I don't know why
ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
token-interceptor.service.ts
import { Injectable } from '#angular/core';
import { AuthService } from './auth.service';
import { HttpClient, HttpErrorResponse, HttpHandler, HttpInterceptor, HttpRequest } from '#angular/common/http';
import { environment } from 'src/environments/environment';
import { catchError, map} from 'rxjs/operators';
import { throwError } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class TokenInterceptorService implements HttpInterceptor {
constructor(
private auth: AuthService,
private http: HttpClient
) { }
intercept(req: HttpRequest<any>, next: HttpHandler) {
return next.handle(req).pipe(
catchError((err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.url.includes('signin') || err.url.includes('refreshToken')) {
return next.handle(req)
}
//if error is not about authorization
if (err.status !== 401) {
return next.handle(req)
}
this.renewToken(req).subscribe(request => {
return next.handle(request)
})
} else {
return throwError(err)
}
})
)
}
renewToken(req: HttpRequest<any>) {
return this.http.get(`${environment.API_URL}/refreshToken`, { withCredentials: true }).pipe(
map((res: any) => {
//update access token
this.auth.setToken(res.token)
return req.clone({
setHeaders: {
authorization: `Bearer ${res.token}`
}
})
})
)
}
}
Ignore this: It looks like your post is mostly code; please add some more details. It looks like your post is mostly code; please add some more details.
this piece of code is wrong:
this.renewToken(req).subscribe(request => {
return next.handle(request)
})
istead it should be:
return this.renewToken(req).pipe(switchMap(request => next.handle(request)));
you are just returning nothing in your variant, that is why it doesn't work.
also the whole logic of token interpceptor seems weird to me. I believe you should rethink about how you want it to work. for now as I see you sending request without token and in almost all cases you are sending it again unmodified, and the one that I fixed above will send it again with token. Wouldn't it be right to add token every time, and only send it 2nd time if token is outdated?

HttpClient & Rxjs

I am working on a case where during a network connection we sometimes might have a limited internet connectivity where we unable to get response from the server or failed response as HttpError.
I hereby trying to ping the URL every second to check whether we are getting response or not, for this
I am trying this code, this is working fine in online method but when i am turning my internet of is doesn't return me false value.
fetch-data.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpResponse, HttpErrorResponse } from '#angular/common/http';
import { Posts } from './posts';
import { Observable, interval, throwError, of } from 'rxjs';
import { take, exhaustMap, map, retryWhen, retry, catchError, tap, mapTo, } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class FetchDataService {
public url = 'https://jsonplaceholder.typicode.com/posts';
constructor(private _httpClient: HttpClient) { }
getData() {
const ob = interval(1000);
return ob.pipe(
exhaustMap(_ => {
return this._httpClient.get<Posts[]>(this.url, { observe: 'response' });
}),
map(val => {
if (val.status === 200)
return true;
throw val;
}),
retryWhen(errors => {
return errors.pipe(map(val => {
if (val.status === 0)
return false;
}))
})
);
}
// 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}`);
// if (error.status !== 200)
// return of(false);
// }
// // return an observable with a user-facing error message
// return throwError(
// 'Something bad happened; please try again later.');
// };
}
pulldata.component.html
import { Component, OnInit } from '#angular/core';
import { FetchDataService } from '../fetch-data.service';
import { Observable } from 'rxjs';
import { Posts } from '../posts';
#Component({
selector: 'app-pulldata',
templateUrl: './pulldata.component.html',
styleUrls: ['./pulldata.component.css']
})
export class PulldataComponent implements OnInit {
public data;
public error = '';
constructor(private _fecthDataServe: FetchDataService) { }
ngOnInit() {
this._fecthDataServe.getData().subscribe(val => {
this.data = val;
console.log(this.data);
});
}
}
what would be the best solution to check the internet connectivity in this manner?
My personal preference would be to not do this with HTTP because of data overhead. Every HTTP request will contain cookie data and other headers that are often useless in these kinds of scenarios.
Is it possible for you to use Web Sockets? With these, you can open up a connection to the server that, unlike HTTP, doesn't have to close. It can remain open forever. And you can subscribe to events to get notified about connection losses. Web Sockets also have the added benefit that it's a new protocol based on TCP, it's not HTTP, resulting in a lot less network data will have to be send.
let socket = new WebSocket('wss://yourserver/socket...');
socket.addEventListener('open', () => console.log('connection has been opened'));
socket.addEventListener('close', () => console.log('connection has been closed'));
In your situation, you might also want to check out the Reconnecting WebSocket, which reconnects when the connection drops. You could also write this small wrapper yourself, of course.
Also, what might even be a simpler solution. You can subscribe to online/offline events on the window object: read more on MDN
function updateOnlineStatus(event) {
var condition = navigator.onLine ? "online" : "offline";
// ...do something with the new status
}
window.addEventListener('online', updateOnlineStatus);
window.addEventListener('offline', updateOnlineStatus);
Both of these solutions should be easily wrappable in an Angular service, but let me know if that works out and/or if these solutions are an option for you.

Duplicate http requests sent when using http interceptor (in Ionic 2)

TL;DR;
Why subscribing to an Observable in an http interceptor produces duplicate http requests to server?
Sample code:
doGetWithInterceptor() {
console.log("Http get with interceptor -> 2 http calls ?? Why?");
this.http_interceptor_get("http://ip.jsontest.com/").subscribe(data => {
console.log("But only one block of data received:", data);
this.result= data.ip;
});
}
http_interceptor_get(url : string) {
let req= this.http.get(url).map(res => res.json());
req.subscribe((data) => {
console.log("[HttpInterceptor]");
});
return req;
}
Full details:
I use an http interceptor service in my Ionic 2 project to globally detect errors, authentication, and more...
But doing so, I am seeing duplicate http requests to the server.
I have an small test App starting from a blank Ionic 2 template:
Which clearly shows the problem in Firebug:
First request (it's ok, single) if using the GET button.
Second request (which duplicates) is using the "Get with interceptor" button.
Meanwhile, the code in the subscription part is executed only once, as it should.
The home.ts code is as follows:
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
result : string = "???";
constructor(public navCtrl: NavController, public http: Http) {
}
http_get(url : string) {
return this.http.get(url).map(res => res.json());
}
http_interceptor_get(url : string) {
let req= this.http.get(url).map(res => res.json());
req.subscribe((data) => {
console.log("[HttpInterceptor]");
});
return req;
}
doGet() {
console.log("Normal http get -> 1 http call");
this.http_get("http://ip.jsontest.com/").subscribe(data => {
console.log("One block of data received:", data);
this.result= data.ip;
});
}
doGetWithInterceptor() {
console.log("Http get with interceptor -> 2 http calls ?? Why?");
this.http_interceptor_get("http://ip.jsontest.com/").subscribe(data => {
console.log("But only one block of data received:", data);
this.result= data.ip;
});
}
doClearResult() {
this.result= "???";
}
}
Its because you are not really intercepting. You are simply subscirbing to the request twice.
http_interceptor_get(url : string) {
let req= this.http.get(url).map(res => res.json());
req.subscribe((data) => { //1st subscription - 1st call
console.log("[HttpInterceptor]");
});
return req; //return original request
}
Then you are subscribing again in doGetWithInterceptor() to your http req.
If you want to log details of call, you can use do().
http_interceptor_get(url : string) {
//return http call
return this.http.get(url).map(res => res.json())
.do(data=>{
//do checks.
return data; //be sure to return data so it is passed on to subscription.
});
}
Then call in your doGetWithInterceptor()

Angular 2 HTTP Service not returning promise

I'm trying to get an angular 2 service to retrieve data from an HTTP request and return it as a promise. When I use the service in the component, the data I'm passing from the service is returned as undefined.
This is my service
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class RecordService {
constructor(private http: Http) {}
getPosts(): Promise<any> {
return this.http
.get('https://jsonplaceholder.typicode.com/posts')
.toPromise()
.then((response: Response) => response.json().data)
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error);
console.log('ERROR');
return Promise.reject(error.message || error);
}
}
and this is my component
import { Component, OnInit } from '#angular/core';
import { RecordService } from './record.service';
import { Router } from '#angular/router';
#Component({
selector: 'record-view',
template: '<h1>This is the record creation page</h1>',
providers: [RecordService]
})
export class RecordComponent implements OnInit{
message: string;
error: any;
constructor(private recordService: RecordService) {
}
ngOnInit() {
this.recordService.getPosts()
.then(data => console.log(data))
.catch(error => console.log(error));
}
}
Any ideas why the data would be undefined?
response.json() already gives you back the data object of your response as JSON, so remove the .data property access.
When you response.json() the result is the exact content from the response of the request you made.
In this case, https://jsonplaceholder.typicode.com/posts returns an array (if open the url in a browser you'll see the array): [{...}, {...}, ...].
From response.json().data remove .data and add || {} if body is null
Finally:
.then((response: Response) => response.json() || {})

Angular 2 Http Request to Promise returns zone obj instead of actual data

I'm trying to have quick test of ng 2 http to return real data. I know there is a better/longer way to do it. This is meant to be quick and simple, not best practices.
I know the server returns data because I can see it in another terminal window. The json is very simple {a:b} because it is just a proof of concept.
I don't care if it is a promise or an observable as long as it hangs around to return the real data right there -- so I can figure out that it actually works -- not that I want to write production code that way.
//app.data.service.ts
import { Injectable } from '#angular/core';
import { Http, Response} from '#angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/toPromise';
#Injectable() export class DataService {
constructor(private http: Http) {
}
public getItems(){
return this.http.get('http://localhost:8090/data/config.txt')
.toPromise()
.then(data => Promise.resolve(data.json()));
}
}
// app.data.service.spec.ts
/* tslint:disable:no-unused-variable */
import { AppComponent } from './app.component';
import { TestBed, inject, fakeAsync } from '#angular/core/testing';
import { MockBackend, MockConnection } from '#angular/http/testing';
import { By } from '#angular/platform-browser';
import { HttpModule } from '#angular/http';
import { DataService } from './app.data.service';
describe('DataService', function () {
let dataService: DataService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
declarations: [AppComponent],
providers: [DataService]
});
dataService = TestBed.get(DataService);
});
it('should be instantiated by the testbed', () => {
expect(dataService).toBeDefined();
});
it('should return get', () => {
let data = dataService.getItems();
console.log('test data= ' + data);
console.log('test string(data)= ' + JSON.stringify(data));
});
});
//tail end of tests.html
<tr class="system-out">
<td colspan="3"><strong>System output:</strong><br />Chrome 53.0.2785 (Mac OS X 10.11.6) LOG: 'WARNING: System.import could not load "systemjs.config.extras.js"; continuing without it.'
<br />Chrome 53.0.2785 (Mac OS X 10.11.6) LOG: Error{originalErr: Error{}}
<br />Chrome 53.0.2785 (Mac OS X 10.11.6) LOG: 'test data= [object Object]'
<br />Chrome 53.0.2785 (Mac OS X 10.11.6) LOG: 'test string(data)= {"__zone_symbol__state":null,"__zone_symbol__value":[]}'
</td>
In app.data.service.ts
public getItems(){
return this.http.get("http://......")
.toPromise()
.then(res => res.json())
.catch(this.handleError);
}
In your component.ts call this method/subscribe to it
data:any;
ngOnInit() {
this.appService.getItems()
.then(data => console.log(data));
}
Several issues to fix this, debugging the chrome browser that the karma test popped up helped -
server wasn't returning CORS headers
observable/subscribe code was
not working
json data was {a:b}, when I changed it to {"a":"b"} - the
result.json() worked
For issue #2 the following is the code for getItems:
//app.data.service.ts
getItems(url:string) : Observable<Response> {
return this._http.get(url)
.map((response: Response) => {
return response;
}).catch(this.handleError);
};
//app.data.service.spec.ts
it('should return {a:b}', () => {
let data: string;
dataService.getItems("http://localhost:8090/data/config.json")
.subscribe(
(response) => {
//Here you can map the response to a type
console.log("test getItems returned");
data = JSON.stringify(response.json());
console.log("data = " + data);
},
(err) => {
//Here you can catch the error
console.log("test getItems returned err");
}
);
});

Categories

Resources