Trying to call nodejs local host using angular http client but it is not hitting the backend i have added url in the proxy.config in angular app as i added in the question that doesnt work either any idea ?
angular service.ts
import { Injectable } from '#angular/core';
import { HttpClient , HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({providedIn: 'root'})
export class AdminService {
constructor(private http: HttpClient) { }
private url = "http://localhost:9001/api/saveClients";
saveClientJobs(data) {
let options = this.createRequestOptions();
console.log("Service", data);
return this.http.post(this.url, data, { headers: options });
}
private createRequestOptions() {
let headers = new HttpHeaders({
"Content-Type": "application/json"
});
return headers;
}
}
angular proxy.config.json
{
"/api/*":{
"target":"http://localhost:9001",
"secure":false,
"logLevel":"debug",
"changeOrigin": true
}
}
NodeJs routes
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const admin_controller_1 = require("./api/admin/admin.controller");
class RegisterRouteClass {
RegisterRoutes(app) {
app.post('/api/saveClients', admin_controller_1.AdminController.save);
}
}
exports.RegisterRouteClass = RegisterRouteClass;
In order for a post/get to be executed you need to subscribe to it. If you are not subscribing to the post/get, it will never execute thus nothing will be output in the network tab of the developer tools.
saveClientJobs(data).subscribe(result => /* do something with the result */)
Related
I want to create a Node REST API with Typescript and created a basic class managing the Express application
import express from 'express';
import { Server } from 'http';
import { injectable } from 'inversify';
import { IWebServer } from './IWebServer';
import { RoutesLoader } from './routes/RoutesLoader';
import * as webServerConfig from '../../config/webServerConfig';
import { IPlugin } from './plugins/IPlugin';
import { LoggerPlugin } from './plugins/LoggerPlugin';
import { CorsPlugin } from './plugins/CorsPlugin';
import { BodyParserPlugin } from './plugins/BodyParserPlugin';
#injectable()
export class WebServer implements IWebServer {
public app: express.Application;
public httpServer: Server;
private port: any;
constructor () {
this.app = express();
this.httpServer = null;
this.port = webServerConfig.port;
}
public startListening(): void
{
const plugins: IPlugin[] = [
new LoggerPlugin(),
new CorsPlugin(),
new BodyParserPlugin()
];
for (const plugin of plugins) { // load all the middleware plugins
plugin.register();
}
new RoutesLoader(); // load all the routes
try {
this.httpServer = this.app.listen(this.port);
} catch (error) {
throw error;
}
}
public stopListening(): void
{
this.httpServer.close();
}
}
This code looks fine to me but the problem is that I have to assign a value to httpServer in the class constructor. As you can see I assign a value to it later in startListening. But I can't assign null to it in the constructor. undefined neither. This type is not nullable. How can I declare this variable without assigning a value to it when creating an instance of this class?
As mentioned in the comments, your httpServer field can be null and also is null before a call to startListening.
Therefor you have to specify that in the type declaration like this:
public httpServer: Server | null;
and then handle the null cases in further methods:
public stopListening(): void
{
if (this.httpServer === null) {
throw "Not listening, call "startListening()" first";
}
this.httpServer.close();
}
Here is my code. I am simply trying to do a GET to a localserver and take the response (which is a JSON object) and send it to a different angular component.
For some reason it is saying ERROR TypeError: this.sendData is not a function
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
interface myData {
data: Object
}
#Injectable({
providedIn: 'root'
})
export class ApiService {
goldProducts: any[] = [];
httpOptions: any;
constructor(private http: HttpClient) {}
base_path = 'http://localhost:80';
shareData = new Subject<any>();
sendData(data: any) {
this.shareData.next(data);
}
getGoldProducts() {
this.httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
return this.http.get<myData>(this.base_path + '/get/goldProducts', this.httpOptions).subscribe(function(res) {
console.log(res);
this.sendData(res);
});
}
}
and the component it is going to is:
import { Component } from '#angular/core';
import { HttpClientModule } from '#angular/common/http';
import { ApiService } from '../services/api.service';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
goldProducts: any[] = [];
getItemPrices: any[] = [];
constructor(public api: ApiService, public http: HttpClientModule) { }
displayGoldProducts() {
this.api.shareData.subscribe(data => {
console.log(data);
});
this.api.getGoldProducts();
}
}
the function displayGoldProducts() is simply hooked up to a button in the html.
I will get the correct console log of the response but only from the api.service.
I am at a loss on how to hook this up. I just want an observable so when I push new data which are new prices from the server then the prices on the client will automatically update. Something simple to do in javascript but apparently a pain to do so far in angular. I am learning angular and the tutorials seem to cover different use cases. Any help would be appreciated and is probably just a formatting issue. Thankyou in advance.
use your arrow function like this
this.http.get<myData>
(this.base_path + '/get/goldProducts',
this.httpOptions).subscribe
(res => {
this.sendData(res);
});
check out this
this.http.get<yourData>
(this.base_path + '/get/goldProducts',
this.httpOptions).subscribe
(res => {
//handle your data
this.sendData(res);
});
You can use arrow function this way.
getGoldProducts(){
this.httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
return this.http.get<myData>(this.base_path + '/get/goldProducts', this.httpOptions)
.subscribe((res: any) => {
console.log(res);
this.sendData(res);
});
}
You should use the Fat arrow function (Lambda expression). The fat arrow => separates the function parameters and the function body. The right side of => can contain one or more code statements.Moreover, it dropped the need to use the 'function' keyword. In TypeScript, everything that comes after the : but before an = (assignment) is the type information.
getGoldProducts(){
this.httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
//drop the use of function keyword while subcribing and use fat arrow instead.
return this.http.get<myData>(this.base_path + '/get/goldProducts',this.httpOptions).subscribe(res => {
console.log(res);
this.sendData(res);
});
}
This is my component.ts where when it's loaded I get the data from the api, which I can see in the console.log, I do infact get my array of 10 objects (they come in groups of 10 on the api). I have the correct path in the API for the source code of the first image in the array of 10 which I typed to out the correct path for in normal http/javascript format of data.hits.hits[n]._source.images[n].urls.original. However when I try to put it in angular it can't read the data value as it is right now since it's out of scope, but I can't figure out how to word it in a better way.
import { Component, OnInit } from '#angular/core';
import { ConfigService } from '../../config.service';
import { Observable } from 'rxjs';
#Component({
selector: 'app-property-binding',
templateUrl: './property-binding.component.html',
styleUrls: ['./property-binding.component.css']
})
export class PropertyBindingComponent implements OnInit {
private isHidden : boolean;
public zeroImage : string;
private Photos : Observable<Object>;
constructor(private configService: ConfigService) { }
ngOnInit() {
//doing the API call
this.Photos = this.configService.getConfig();
this.Photos.subscribe((data) => console.log(data));
}
toggle() : void {
this.isHidden = !this.isHidden;
if(this.isHidden){
//var zeroImg = document.createElement("img");
this.zeroImage.src = data.hits.hits[0]._source.images[0].urls.original;
}
}
}
Here is the Angular html page that should property bind the src with the variable that I want.
<p>
View Artworks
</p>
<button class="btn btn-info" (click)="toggle()">Show Artwork</button>
<div class="col-md-4" *ngIf="isHidden">
<img [src]="zeroImage">
</div>
Here is the service method that I have the method that makes the API call
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { HttpHeaders } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ConfigService {
private httpOptions = {
headers: new HttpHeaders({
'ApiKey': 'my_personal_key'
})
};
private configUrl = 'https://api.art.rmngp.fr/v1/works';
constructor(private http: HttpClient) { }
getConfig(){
let obs = this.http.get(this.configUrl, this.httpOptions)
console.log("Inside the getConfig method, before subscribe, doing API call" +
obs);
//might not need to subscribe here??
//obs.subscribe((response) => console.log(response))
return obs;
//return this.http.get(this.configUrl, this.httpOptions);
}
}
And slightly unrelated code, this is the normal http/javascript where I wrote the code Outside of Angular, which works perfectly fine.
function displayPhoto(){
fetch('https://api.art.rmngp.fr/v1/works/, {headers: {ApiKey: "my_personal_key"}})
.then(function(response){
return response.json();
})
.then(function(data){
document.getElementById("zeroImg").src = data.hits.hits[0]._source.images[0].urls.original;
Again, the API call in Angular works, I can see I am pulling the data successfully, I however can not set the image to the first image in the set of data and have been struggling with it. any help will help
You are not doing anything with the data when you subscribe
this.Photos.subscribe((data) => console.log(data));
You have not done anything with the data here.
zeroImg.src = data.hits.hits[0]._source.images[0].urls.original;
zeroImg is a string and makes no sense to set a src property on it and data is undefined at the point. The only place there is a data variable is in your subscription function but it is not available here.
The following will set the src of the image
this.Photos.subscribe((data) => {
this.zeroImg = data.hits.hits[0]._source.images[0].urls.original;
});
Make the toggle function just toggle the isHidden flag and get rid of the rest.
ngOnInit() {
//doing the API call
this.Photos = this.configService.getConfig();
this.Photos.subscribe((data) => {
this.zeroImg = data.hits.hits[0]._source.images[0].urls.original;
});
}
toggle() : void {
this.isHidden = !this.isHidden;
}
I am attempting to write a helper function in an Angular test leveraging HttpTestingController. The reason being is because I will eventually have a series of endpoints within my Angular service, RequestService, that I want to test within this testing file. I do not want to repeatedly inject my RequestService and HttpTestingController instances into each test function that tests the service. That is redundant. Rather, I would prefer to have a single test function that takes the injected RequestService and HttpTestingController instances and repeatedly passes them into the helper function I have created, requestHelper. This way when I want to test additional endpoints, all I need to do is make a call to the helper function and provide the parameters that are needed.
The problem I am bumping into is that when the helper function runs, the service's instance for some reason does not appear to exist, Even though the test is able to access the service's functions. When it reaches my service method's call to the http.get within the callEndpoint function, it gives me the below error:
Failed: Cannot read property 'http' of undefined
This does not make sense to me because the this keyword is referring to the instance of the Angular service, and the test case is able to reach the service's function, so how could this possibly be undefined?
Here is my test spec:
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 { RequestService } from './request.service';
describe(`RequestService`, () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
HttpClientTestingModule
],
providers: [
RequestService
]
});
}));
afterEach(async(inject([HttpTestingController], (backend: HttpTestingController) => {
backend.verify();
})));
it(`TESTING INJECTION`, async(inject([RequestService, HttpTestingController],
(service: RequestService, backend: HttpTestingController) => {
requestHelper(service.callEndpoint,'https://endpointurl.com',backend);
})));
function requestHelper(serviceCall: Function, url: string, backendInstance: any) {
serviceCall(...serviceParams).subscribe();
backendInstance.expectOne((req: HttpRequest<any>) => {
return req.url === url
&& req.method === 'GET';
}, 'GET');
}
});
And the respective service that the spec is testing
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { RequestOptions } from '#angular/http';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class RequestService {
private requestOptions = {
headers: new HttpHeaders({'Locale': 'en_US'})
};
constructor(private http: HttpClient) { }
callEndpoint(state: string, countryCode: string): Observable<Object> {
return this.http.get(`https://endpointurl.com`,this.requestOptions);
}
}
Thank you for your help!
You can bind the context in the it block:
it(`TESTING INJECTION`, async(inject([RequestService, HttpTestingController],
(service: RequestService, backend: HttpTestingController) => {
requestHelper(service.callEndpoint.bind(service),'https://endpointurl.com',backend);
})));
I'm trying a simple component that has to pull data from a JSON file. I'm almost copying the functionality from generated Fountain App, but for some reason I can't get the desired results. I have a component like:
import {Component, Inject} from "#angular/core";
import {Http} from '#angular/http';
#Component({
selector: 'body-selector',
template: require('./body.html')
})
#Inject(Http)
export class BodyComponent {
constructor(http: Http) {
this.http = http;
this.getText('app/texts/main.json').subscribe(result => {
console.log(result);
this.texts = result;
});
console.log(this.texts);
}
getText(url) {
return this.http.get(url).map(response => response.json());
}
}
on the first console.log I have [Object object] [Object object] [Object object], which is correct as I have three entries in the JSON. On the second however I've got undefined, which turns into an error in the browser.
Error in ./BodyComponent class BodyComponent - inline template:3:6 caused by: Cannot read property 'title' of undefined
I'm looking at the example generated from the fountain app, but I can't get what I'm doing wrong.
You have multiple problems:
The first console.log is inside the callback, where this.texts has just been set. However the second one is outside the callback, so it won't have been. Therefore you'll always see undefined for that, because...
...you never set a default value for this.texts, and your template apparently doesn't have any e.g. *ngIf to handle it being null or undefined, causing errors prior to the callback being called.
Below is your code, refactored to start with an empty this.texts (assuming it should be an array; please adapt to taste) and simplifying the injection of Http. Also note the comments, and that I've used templateUrl to avoid the require and OnInit to trigger the HTTP call slightly later in the component lifecycle rather than doing it in the constructor.
import {Component, OnInit} from '#angular/core'; // note consistent quotes
import {Http} from '#angular/http';
#Component({
selector: 'body-selector',
templateUrl: './body.html',
})
export class BodyComponent implements OnInit {
texts: any[] = []; // start with an empty array
constructor(private http: Http) { } // inject Http here, no need to assign to this
ngOnInit() {
this.http
.get('app/texts/main.json')
.map(response => response.json())
.subscribe(result => {
console.log(result); // only log *inside* the callback
this.texts = result;
});
// outside the callback, the HTTP call hasn't yet finished
}
}
You could also solve this by having an ngIf in your HTML to prevent the element from being loaded before the data is.
<div class="main-container" *ngIf="texts">
...
</div>
I'd strongly recommend running through the basic Angular 2 tutorials to get on top of this stuff, see e.g. the Tour of Heroes.
You get undefined because this:
this.getText('app/texts/main.json')
Is an asynchronous call that gets the data and when it's done, it executes the code in the 'subscribe' block. So this.text is empty until that executes. That is the expected behavior.
Better way to use data or making API call use service:
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
#Injectable()
export class BodyService {
private _requestOptions: RequestOptions;
private static handleError(error: Response): ErrorObservable {
return Observable.throw(error.json().error || 'Server error');
}
constructor(private http: Http) {
const headers = new Headers({ 'Accept': 'application/json' });
this._requestOptions = new RequestOptions({ headers: headers});
}
/**
* [getJsonData will get data of json file: main.json ]
*/
getJsonData() {
return this.http.get('app/texts/main.json', this._requestOptions)
.map(res => res.json()) //needs to add map for converting data in json format
.catch(BodyService.handleError);
}
}
Now Inject this service in your component:
import {Component, OnInit} from '#angular/core';
import { BodyService } from './adminModules.service';
#Component({
selector: 'body-selector',
templateUrl: './body.html',
providers: [BodyService]
})
export class BodyComponent implements OnInit {
texts: any = []; // start with an empty array
errorMessage: any;
constructor(private _bodyService: BodyService) {}
ngOnInit() {
this._bodyService.getJsonData()
.subscribe(data => {
this.texts = data;
console.log('data', this.texts);
}, error => {
this.errorMessage = <any> error;
})
}
}
For calling service, you can call directly in constructor or create one method and call either in constructor or any place where you want to call.
Hope it will helpful for you :)