Not receiving Products from function in Angular - javascript

I am working through the tutorial files in the book Pro Angular for a Store Front application. I am currently working on an administration section and am getting an error saying "Failed to load resources, cannot connect to the server". This is my rest.datasource.ts file:
import { Injectable } from "#angular/core";
import { Http, Request, RequestMethod } from "#angular/http";
import { Observable } from "rxjs/Observable";
import { Product } from "./product.model";
import { Cart } from "./cart.model";
import { Order } from "./order.model";
import "rxjs/add/operator/map";
const PROTOCOL = "http";
const PORT = 3000;
#Injectable()
export class RestDataSource {
baseUrl: string;
auth_token: string;
constructor(private http: Http) {
this.baseUrl = `${PROTOCOL}://${location.hostname}:${PORT}/`;
}
authenticate(user: string, pass: string): Observable<boolean> {
return this.http.request(new Request({
method: RequestMethod.Post,
url: this.baseUrl + "login",
body: { name: user, password: pass }
})).map(response => {
let r = response.json();
this.auth_token = r.success ? r.token : null;
return r.success;
});
}
getProducts(): Observable<Product[]> {
return this.sendRequest(RequestMethod.Get, "products");
}
saveProduct(product: Product): Observable<Product> {
return this.sendRequest(RequestMethod.Post, "products",
product, true);
}
updateProduct(product): Observable<Product> {
return this.sendRequest(RequestMethod.Put,
`products/${product.id}`, product, true);
}
deleteProduct(id: number): Observable<Product> {
return this.sendRequest(RequestMethod.Delete,
`products/${id}`, null, true);
}
getOrders(): Observable<Order[]> {
return this.sendRequest(RequestMethod.Get,
"orders", null, true);
}
deleteOrder(id: number): Observable<Order> {
return this.sendRequest(RequestMethod.Delete,
`orders/${id}`, null, true);
}
updateOrder(order: Order): Observable<Order> {
return this.sendRequest(RequestMethod.Put,
`orders/${order.id}`, order, true);
}
saveOrder(order: Order): Observable<Order> {
return this.sendRequest(RequestMethod.Post,
"orders", order);
}
private sendRequest(verb: RequestMethod,
url: string, body?: Product | Order, auth: boolean = false)
: Observable<Product | Product[] | Order | Order[]> {
let request = new Request({
method: verb,
url: this.baseUrl + url,
body: body
});
if (auth && this.auth_token != null) {
request.headers.set("Authorization", `Bearer<${this.auth_token}>`);
}
return this.http.request(request).map(response => response.json());
}
}
and here is my static.datasource.ts file:
import { Injectable } from "#angular/core";
import { Product } from "./product.model";
import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/from";
import { Order } from "./order.model";
#Injectable()
export class StaticDataSource {
//Populate product fields with Inventory information
private products: Product[] = [
//products omitted for brevity
];
getProducts(): Observable<Product[]> {
return Observable.from([this.products]);
}
saveOrder(order: Order): Observable<Order> {
console.log(JSON.stringify(order));
return Observable.from([order]);
}
}
I am following the tutorial exactly but for some reason the site falls apart now that I am on Chapter 9 creating the admin section. Any help or pointers would be greatly appreciated.

Related

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

Angular http.post not sending data with subscribe

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

Error: Expected no open requests, found 1 (Angular)

I am trying to create a test case for a service in angular6. The service has a bunch of different http request methods (get, put, post etc) and within them an API call is made which fetches the appropriate response. I'm trying to create the test cases where a mock http request is made and a response is returned. However, I have followed a Tutorial which apparently helps me do exactly what I want.
However, when I run the test case for the service it gives me the following error (I've censored the URL in GET for privacy purposes:
Error: Expected no open requests, found 1: GET https://staging.xxxxxxxxxx.co.uk/rest/v11_1/oauth2/token
at HttpClientTestingBackend.push../node_modules/#angular/common/fesm5/http/testing.js.HttpClientTestingBackend.verify (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/common/fesm5/http/testing.js:326:1)
at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/webpack:/src/app/Services/adapter.service.spec.ts:22:13)
at TestBed.push../node_modules/#angular/core/fesm5/testing.js.TestBed.execute (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/core/fesm5/testing.js:1073:1)
at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/core/fesm5/testing.js:1224:29)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:388:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:288:1)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:387:1)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:138:1)
at runInTestZone (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:509:1)
at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:524:1)
I've tried browsing through This solution as well as This one, but to no avail.
Here is the code for my service:
import { Injectable } from '#angular/core';
import { environment } from '../../environments/environment';
import {
HttpHeaders,
HttpClient,
HttpParams,
} from '#angular/common/http';
import { Request, RequestOptions, Headers } from '#angular/http';
import { Observable } from 'rxjs/Rx';
import { throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { JwtService } from './jwt.service';
const API_URL = environment.api.host;
#Injectable({
providedIn: 'root'
})
export class AdapterService {
constructor(private http: HttpClient, private jwtService: JwtService) {}
private formatErrors(self: AdapterService) {
return (res: Response) => {
return Observable.throw(res);
};
}
private requestHeaders(path: string) {
let headers;
if (path !== 'oauth2/token') {
headers = new HttpHeaders({
'Accept': 'application/json',
'Oauth-Token': this.jwtService.getToken()
})
}
return headers;
}
get(path: string, params: HttpParams = new HttpParams()): Observable < any > {
let headers = this.requestHeaders(path);
return this.http.get(`${API_URL}${path}`, { headers })
.catch(catchError(this.formatErrors(this)));
}
put(path: string, body: Object = {}): Observable < any > {
return this.http.put(
`${API_URL}${path}`,
JSON.stringify(body),
).catch(catchError(this.formatErrors(this)));
}
post(path: string, body: Object = {}): Observable < any > {
return this.http.post(
`${API_URL}${path}`,
JSON.stringify(body),
).catch(catchError(this.formatErrors(this)));
}
delete(path): Observable < any > {
return this.http.delete(
`${API_URL}${path}`,
).catch(catchError(this.formatErrors(this)));
}
}
The Test Case:
import { TestBed, async, inject } from '#angular/core/testing';
import { HttpClientModule, HttpRequest, HttpParams } from '#angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { AdapterService } from './adapter.service';
describe('AdapterService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
HttpClientTestingModule
],
providers: [
AdapterService
]
});
});
afterEach(inject([HttpTestingController], (backend: HttpTestingController) => {
backend.verify();
}));
it('should send a valid get request for token', async(inject([AdapterService, HttpTestingController],
(service: AdapterService, backend: HttpTestingController) => {
service.get('oauth2/token').subscribe((next)=>{
expect(next).toBeDefined();
});
})));
// it('')
});
SOLVED I forgot to add an expectOne request for the API call within the test case:
backend.expectOne( API_URL + 'oauth2/token').flush(null, { status: 200, statusText:'Ok' });
A very naive observation, apologies for the inconvenience.

How do I chain service methods in Angular?

I need to chain two services together in order to make a successful HTTP request. The first service creates an Authorization Header, and the second service makes the call to the Angular Http service.
How do I chain these calls so that the Authorization Header service returns before the main HTTP call is made?
When I run this code I get an error of .toPromise() of undefined
get(url) {
const headers = new Headers();
this.createAuthorizationHeader(headers,function(){
return this.http.get(url, {headers: headers});
});
}
Authorization Header Service:
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import { environment } from '../../environments/environment';
import { ErrorHandlerService } from './error-handler.service';
import { tokenNotExpired, JwtHelper } from 'angular2-jwt';
#Injectable()
export class HttpClient {
jwtHelper: JwtHelper = new JwtHelper();
count = 1;
constructor(private http: Http, private _errorHandler: ErrorHandlerService)
{ }
createAuthorizationHeader(headers: Headers) {
let token = '';
if (sessionStorage.getItem('token')) {
token = sessionStorage.getItem('token')
}
if (token && typeof token === 'string') {
if (this.jwtHelper.isTokenExpired(token) && this.count === 1) {
this.refreshToken()
}
else {
headers.append('Authorization', 'Bearer ' + token);
}
}
}
get(url) {
const headers = new Headers();
this.createAuthorizationHeader(headers);
return this.http.get(url, {
headers: headers
});
}
refreshToken(): any {
this.getRefreshAWSToken(sessionStorage.getItem('refresh_token'))
.then(resp => {
return this.getwithheader(environment.BASE_URL + '/token', JSON.parse(resp).id_token).toPromise()
.then((resp1: Response) => {
console.log(resp1)
const newJwttoken = JSON.parse(resp1.text()).token;
sessionStorage.setItem('token', newJwttoken);
const headers = new Headers();
headers.append('Authorization', 'Bearer ' + newJwttoken);
})
.catch(err => this._errorHandler.handleError(err));
});
}
}
Http Request Service:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import { DataTableParams } from 'angular-4-data-table';
import { SharedService } from './shared.service';
import { HttpClient } from './http.service';
import { Observable } from 'rxjs/rx';
import { ErrorHandlerService } from './error-handler.service';
#Injectable()
export class DeviceService {
BASE_URL: String;
constructor(private http: HttpClient,
private _sharedService: SharedService,
private _errorHandler: ErrorHandlerService) {
this.BASE_URL = this._sharedService.BASE_URL;
};
getCarriers(): any {
return this.http.get(this.BASE_URL + '/lookup/carriers').toPromise()
.then((resp: Response) => resp.text())
.catch(err => this._errorHandler.handleError(err));
}
}

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