Angular 2 GET request - node.js

I am extremely incompetent in Angular 2. I have been using it for a while, and the only thing that I can ever get to work is when I copy and paste from tutorial videos.
With that said, I am creating a REST api (Node.js, expressJS, angular2, mongodb) and I am having trouble calling a GET from frontend to backend. I am trying to call an endpoint (/games) that returns an array of game objects. I want to use this array to display the games eventually, but I can't even get a successfull call working correctly.
I'm trying to use all-games.component.ts to use the service get-last25.service.ts to return all of the games from the database (25 max). I have JWT authentication turned off for this route for now.
The errors I receive:
Unhandled Promise rejection: No provider for GetLast25Service! ; Zone: angular ; Task: Promise.then ;
and
EXCEPTION: Uncaught (in promise): Error: DI Error
and an empty error...
=====================================
Code:
get-last25.service.ts:
import { Injectable } from '#angular/core';
import {Http, Headers} from '#angular/http';
import 'rxjs/add/operator/map';
import { tokenNotExpired } from 'angular2-jwt';
#Injectable()
export class GetLast25Service {
constructor(private http:Http) { }
getLast25(game){
if(game == null || game == undefined){
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http.get('http://localhost:3000/games',{ headers: headers })
.map(res => res.json());
} else {
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http.get(`http://localhost:3000/games/${game}`,{ headers: headers })
.map(res => res.json());
}
}
}
all-games.component.ts:
import { Component, Input, OnInit, ViewEncapsulation } from '#angular/core';
import { ActivatedRoute, Router, Params } from '#angular/router';
//import {FlashMessagesService} from 'angular2-flash-messages';
import { AuthService } from '../../services/auth.service';
import { GetLast25Service } from '../../services/get-last25.service';
#Component({
selector: 'app-all-games',
templateUrl: './all-games.component.html',
styleUrls: ['./all-games.component.css']
})
export class AllGamesComponent implements OnInit {
private games: any[];
private comments: any;
constructor(
private route: ActivatedRoute,
private router: Router,
private authService: AuthService,
//private flashMessage: FlashMessagesService,
private getLast25Service: GetLast25Service
) { }
ngOnInit() {
this.getLast25Service.getLast25(null).subscribe(games => {
this.games = games;
},
err => {
return false;
});
}
}
whenever I call get(http://localhost:3000/games), it returns:
[
{
"_id": "58e87513fbcdca1f54b4a84c",
"name": "League of Legends",
"game_endpoint": "lol",
"release_date": "2012-04-23T18:25:43.511Z",
"image_path": "../assets/images/lol.png",
"__v": 0,
"posts": 0,
"subscribers": 0,
"categories": [
"MOBA",
"strategy",
"multiplayer",
"Dota ripoff"
]
},
{
"_id": "58e8823b8da3fa1e6c8f0885",
"name": "Rocket League",
"game_endpoint": "rl",
"release_date": "2012-04-23T18:25:43.511Z",
"image_path": "../assets/images/rocketleague.png",
"__v": 0,
"posts": 0,
"subscribers": 0,
"categories": [
"cars",
"racing",
"soccer",
"chat_disabled"
]
}
]

You need to add the service as a Provider to the module,
#NgModule({
providers: [
GetLast25Service
]
})

Related

NestJS serving JSON and adds a "default" section repeating the JSON

I have a strange behaviour on an endpoint in NestJS serving a piece of JSON.
The JS with the JSON object is exporting
module.exports = Object.freeze({
translation: {
TestMessage: 'Bienvenue à React et react-i18next'
}
});
The result on the Client is:
{
"translation": {
"TestMessage": "Bienvenue à React et react-i18next"
},
"default": {
"translation": {
"TestMessage": "Bienvenue à React et react-i18next"
}
}
}
The question is where is the "default" coming from?
To paint the whole picture, below the module, controller and service:
Module
import { Module } from '#nestjs/common';
import { LoggerService } from '#modules/logger';
import { I18nController } from './i18n.controller';
import { I18nService } from './i18n.service';
#Module({
controllers: [I18nController],
providers: [I18nService, LoggerService],
exports: [I18nService]
})
export class I18nModule {}
Controller
import { Controller, Get, Param } from '#nestjs/common';
import { LoggerService } from '#modules/logger';
import { I18nService } from './i18n.service';
#Controller('i18n')
export class I18nController {
constructor(private logger: LoggerService, private i18nService: I18nService) {
this.logger.setContext(I18nController.name);
}
#Get('/:lang')
async getLanguage(#Param('lang') lang: string) {
console.log(lang);
return await this.i18nService.findOneByLanguageCode(lang);
}
}
Service
import { Injectable } from '#nestjs/common';
import { access } from 'fs/promises';
import { constants as fsconstants } from 'fs';
#Injectable()
export class I18nService {
async findOneByLanguageCode(language: string): Promise<any | null> {
const languagefile = __dirname + '/../../public/languages/' + language + '.js';
await access(languagefile, fsconstants.R_OK);
return await import(languagefile);
}
}
From the Client I do a simple http://localhost:3001/i18n/fr-FR
and get the above result.
Again, where is the 'default' section coming from?
There should be esModuleInterop enabled in your tsconfig.json
https://www.typescriptlang.org/tsconfig#esModuleInterop
a default import like import moment from "moment" acts the same as const moment = require("moment").default
That's why you have default object exist.
tsconfig.json
{
"compilerOptions": {
"esModuleInterop": true, // change it to false or remove it
}
}

JWT library error: Generic type 'ModuleWithProviders<T>' requires 1 type argument(s) in Angular 10

For an authentication project I am using:
Angular CLI: 11.0.4 for the frontend
Node: 10.19.0 for the backend
OS: linux x64
I receive the following error after ng serve and I am not sure why that is happening, the error seems to be in the library node_modules/angular2-jwt/angular2-jwt.d.ts and not in the code I wrote:
node_modules/angular2-jwt/angular2-jwt.d.ts:88:41 - error TS2314:
Generic type 'ModuleWithProviders' requires 1 type argument(s).
static forRoot(config: AuthConfig): ModuleWithProviders;
Also connected to that (so I believe the errors are concurrent or even, I am afraid, interchangeable), because it was shown as soon as the 'ModuleWithProviders<T>' error was shown, so I though it would make sense to show them both as they are linked together:
Error: node_modules/angular2-jwt/angular2-jwt.d.ts:1:77 - error
TS2307: Cannot find module '#angular/http' or its corresponding type
declarations.
1 import { Http, Request, RequestOptions, RequestOptionsArgs, Response
} from "#angular/http";
So the difficulty I have is also due to the fact that I am not sure which parts of the code are affected so I will put for the sake of completeness the app.module.ts and the files carrying the jwt include
app.module.ts:
import { ValidateService } from './services/validate.service';
import { FlashMessagesModule } from 'angular2-flash-messages';
import { HttpClientModule } from '#angular/common/http';
import { AuthService } from './services/auth.service';
import { AuthGuard } from './guards/auth.guards';
const appRoutes: Routes = [
{path:'', component: HomeComponent},
{path:'register', component: RegisterComponent},
{path:'login', component: LoginComponent},
{path:'dashboard', component: DashboardComponent, canActivate: [AuthGuard]},
{path:'profile', component: ProfileComponent, canActivate: [AuthGuard]},
]
#NgModule({
declarations: [
AppComponent,
NavbarComponent,
LoginComponent,
RegisterComponent,
HomeComponent,
DashboardComponent,
ProfileComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
RouterModule.forRoot(appRoutes),
FlashMessagesModule.forRoot(),
HttpClientModule,
],
providers: [ValidateService, AuthService, AuthGuard],
bootstrap: [AppComponent]
})
export class AppModule { }
auth.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { map } from 'rxjs/operators';
import { tokenNotExpired } from 'angular2-jwt';
#Injectable({
providedIn: 'root'
})
export class AuthService {
authToken: any;
user: any;
constructor(private httpClient: HttpClient) { }
registerUser(user) {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
};
return this.httpClient.post('http://localhost:3000/users/register', user, httpOptions);
}
authenticateUser(user) {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
};
return this.httpClient.post('http://localhost:3000/users/authenticate', user, httpOptions);
}
getProfile() {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
Authorization: this.authToken,
})
};
this.loadToken();
return this.httpClient.get('http://localhost:3000/users/profile', httpOptions);
}
storeUserData(token, user) {
localStorage.setItem('id_token', token);
localStorage.setItem('user', JSON.stringify(user));
this.authToken = token;
this.user = user;
}
loadToken() {
const token = localStorage.getItem('id_token');
this.authToken = token;
}
loggedIn() {
return tokenNotExpired();
}
logout() {
this.authToken = null;
this.user = null;
localStorage.clear();
}
}
profile.components.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object = {};
constructor(private authService: AuthService, private router: Router) { }
ngOnInit(): void {
this.authService.getProfile().subscribe(profile => {
this.user = profile;
},
err => {
console.log(err);
return false;
})
}
}
I did research on how to solve the problem and here is was I was able to find so far:
this post is very useful because it has my same exact problem.
The answer calls for a bug report repo that, however, does not provide any answer to that.
The answer that was provided suggests to insert the following code:
declare module "#angular/core" {
interface ModuleWithProviders<T = any> {
ngModule: Type<T>;
providers?: Provider[];
}
}
Unfortunately this was not an accepted answer and I am not sure where I can put this piece of code in any part of the app.module.ts I provided above.
I also studied this post which was also useful but did not use the suggestion above.
The strange fact I understand from the error is that it seems to come from the library itself and not from the code that I wrote.
Following this I proceeded with:
rm -rf all the node_modules
rm -rf the package jason file
clean the cache
npm install
But outcome is the same, I always receive the same error on the same library.
Please if anyone had the same problem can you share how it was solved and what should I do more to take care of that.
Insert this piece of code into the angular2-jwt.d.ts class and confirm the class change:
declare module "#angular/core" {
interface ModuleWithProviders<T = any> {
ngModule: Type<T>;
providers?: Provider[];
}
}
But you should use a newer library than this, like #auth0/angular-jwt
After installing this library, you must register its module in the class app.module.ts :
import {JwtModule} from '#auth0/angular-jwt'
imports: [
JwtModule.forRoot({
config: {
tokenGetter:() => {
return localStorage.getItem('access_token');
},
},
})
],
And then you can use it in your AuthService class:
import {JwtHelperService} from '#auth0/angular-jwt';
constructor(public jwtHelper: JwtHelperService) {
}
isAuthenticated(): boolean {
return !this.jwtHelper.isTokenExpired(this.token);
}
All this is explained in a short documentation with examples (https://www.npmjs.com/package/#auth0/angular-jwt), so don't be lazy to read it before using any library.

Angular 7/8 - How to get url parameters in app component

I have Single sign on in place but for testing I want to read the values from the url localhost:4200/?id=test&name=testing&email=testing#test.com and pass them to an API in app component.
there will be a flag on which basis I will reading from url instead of using single sign on function
if (url_enabled == true) {
getParamsFromUrl()
} else {
singleSignOn()
}
I tried ActivatedRoute but it doesn't seem to be working.
I have tried queryParams, params, url, queryParamsMap but none of these seems to be working. all I get is empty value.
inside app component
app.component.ts
getParamsFromUrl() {
this._router.events.subscribe((e) => {
if (e instanceof NavigationEnd) {
console.log(e.url)
}
})
}
this.route.queryParams.subscribe(params => {
console.log(params);
})
app.component.html
<router-outlet></router-outlet>
app-routing.module.ts
const routes: Routes = [
{path:'*/:id', component: AppComponent},
];
I have tried whatever I could found on stackoverflow or other blogs. Can somebody point out what am I missing here?
For this route:
You can try this way:
const routes: Routes = [
{path:'*/:id', component: AppComponent},
];
In AppComponent .ts file:
constructor(
private activatedRoute: ActivatedRoute,
) { }
ngOnInit() {
this.activatedRoute.params.subscribe(params => {
const id = params['id'];
console.log('Url Id: ',id);
}
OR
ngOnInit() {
this.activatedRoute.queryParams.subscribe(params => {
const id = +params.id;
if (id && id > 0) {
console.log(id);
}
});
}
first of all there is an url with queryParams like yours :
localhost:4200/?id=test&name=testing&email=testing#test.com
in this way tou get to the queryparams with ActivatedRoute object lik :
this.name = this.activatedRoute.snapshot.queryParamMap.get('name'); // this.name = 'testing'
Or :
this.activatedRoute.queryParams.subscribe(params => {
this.name= params['name'];
});
and the other way is
localhost:4200/test/testing/testing#test.com
you use for sync retrieval (one time) :
this.name = this.activatedRoute.snapshot.ParamMap.get('name');
Angular comes us with the ActivatedRoute object. We can access the URL parameter value in same way its done above with little difference. Data in this type can be accessed with two different ways. One is through route.snapshot.paramMap and the other is through route.paramMap.subscribe. The main difference between the two is that the subscription will continue to update as the parameter changes for that specific route.
ngOnInit() {
this.route.paramMap.subscribe(params => {
this.userType = params.get("userType")
})
}
You need to create a new component and update the routing configuration as follows:
First, create a new component: MainComponent:
import { Component } from '#angular/core';
#Component({
selector: 'main',
template: `<router-outlet></router-outlet>`,
})
export class MainComponent {
constructor() { }
}
Then, update your AppModule:
import { AppComponent } from './app.component';
import { MainComponent } from './main.component';
#NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot([
{path: '', component: AppComponent}
])
],
declarations: [ MainComponent, AppComponent ],
bootstrap: [ MainComponent ]
})
export class AppModule { }
Finally, you'll need to update your index.html file(Make sure to load the brand new component instead of the AppComponent):
<main>loading</main>
Now you'll be able to read your parameters as requested in your AppComponent:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, Params } from '#angular/router';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
params: Params;
constructor(private route: ActivatedRoute){}
ngOnInit() {
this.route.queryParams.subscribe((params: Params) => {
this.params = params;
console.log('App params', params);
const id = params['id'];
console.log('id', id);
});
}
}
See a working example here: https://read-params-app-component.stackblitz.io/?id=test&name=testing&email=testing#test.com.
And find the source code here.
I hope it helps!
You can try like this
constructor(
private activatedRoute: ActivatedRoute
)
ngOnInit() {
this.activatedRoute.paramMap
.pipe(
tap(console.log(this.activatedRoute.snapshot.paramMap.get(
"id"
)))
).subscribe()
}
Let me know if you need any help
Using Transition from #uirouter/core makes it easy to get params from url.
import {Transition} from '#uirouter/core';
#Component()
export class MyComponent {
public myParam = this.transition.params().myParam;
public constructor(public transition: Transition) {}
}
I used jquery inside angular 8 and got the href using jquery $ variable after declaring it in app component.
import { query } from '#angular/animations';
declare var $: any;

How to send events from nodeJS/express to angular

I have a long running transaction, and I would like to inform the client of the progress. My front end is Angular 4 and backend is nodeJS/Express . The client initiates the transaction via HTTP Post .
Angular does provide a facility to listen to event progress . https://angular.io/guide/http#listening-to-progress-events
My question is, how can I send events from my express App to Angular app?
As of the moment I don't want to use sockets.io .
Listening to upload progress events is actually a client-side feature. What it does behind the scenes is that it tells you the progress based on how much data the client i.e. the browser, has sent to the server. It doesn't actually get a response from the server (as I assume what you are thinking) for how much data the server has received and then displaying the progress to the user. So, if you would think logically and technically, it can not help you in any way. Also, as far as my knowledge goes, sockets are the only way to get a real-time update of the things happening on the server side.
Based on Angular's documentation, progress events can be handled by client, and after doing some searching I cam across server side events - SSE, which is basically sending response headers with connection alive header, and then progress data .
I was able to do it, but I still have issues sending and handling custom user events per angular. Here is what that I have.
App component.ts
import { Component ,OnInit} from '#angular/core';
import { CommonService} from './common.service';
import { Observable,Subscription } from "rxjs/Rx";
import 'rxjs/add/operator/timeout';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css','../../node_modules/bootstrap/dist/css/bootstrap-
theme.min.css']
})
export class AppComponent implements OnInit {
private sseStream: Subscription;
messages:Array<string> = [];
progress:number=0;
totalProgress:number=7;
constructor(private commonService: CommonService ) { }
ngOnInit(){
this.commonService.getHttpObj().subscribe(event=>{
if(event){
if(event['loaded']){
console.log(event['loaded']);
this.progress=(event['loaded'] / this.totalProgress)*100;
}
}
});
}
title = 'Angular4';
}
common.service.ts
import { Injectable } from '#angular/core';
import {HttpRequest} from '#angular/common/http';
import { Observable } from "rxjs/Rx";
import { catchError, map, tap , last} from 'rxjs/operators';
import { HttpClient } from '#angular/common/http';
import { HttpEventType } from '#angular/common/http';
const req = new HttpRequest('GET', 'http://localhost:9080/event', {
reportProgress: true
});
#Injectable()
export class CommonService {
constructor(private http: HttpClient) { }
getHttpObj(){
return this.http.request(req).pipe(
map(event => this.getEventMessage(event)),
tap(message => this.showProgress(message)),
// last(), // return last (completed) message to caller
// catchError(this.handleError())
);
};
private getEventMessage(event: any) {
switch (event.type) {
// case HttpEventType.Sent:
// return `Uploading file `;
case HttpEventType.UploadProgress:
// Compute and show the % done:
const percentDone = Math.round(100 * event.loaded / event.total);
return `File is ${percentDone}% uploaded.`;
case HttpEventType.Response:
return `Complete`;
case HttpEventType.User:
return event;
case HttpEventType.UploadProgress:
return `${JSON.stringify(event)}`;
case HttpEventType.DownloadProgress:
return event;
default:
return event;
}
}
showProgress(a:any){
//console.log(a);
return a;
}
private handleError<T> () {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
// console.error('error'); // log to console instead
// TODO: better job of transforming error for user consumption
// console.log(`${error.message}`);
// Let the app keep running by returning an empty result.
return null;
};
}
}
app.component.html
`<div class="container">
<div style="text-align:center">
<h1>
Welcome to {{title}}!!
</h1>
<input type="text" [(ngModel)]="test">
<p>{{test}}</p>
</div>
<div class="progress">
<div class="progress-bar bg-success" [ngStyle]="{'width':progress + '%'}"></div>
</div>
</div> `
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms'
import { AppComponent } from './app.component';
import { ServerComponent } from './server/server.component';
import { ServersComponent } from './servers/servers.component';
import { HttpClientModule } from '#angular/common/http';
import {CommonService } from './common.service';
import { HttpModule } from '#angular/http';
#NgModule({
declarations: [
AppComponent,
ServerComponent,
ServersComponent
],
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
HttpModule
],
providers: [CommonService],
bootstrap: [AppComponent]
})
export class AppModule { }
server.js
var express=require('express');
var app=express();
app.listen(9080);
app.get('/event',(req,res)=>{
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write("\n") ;
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write( "\n") ;
res.write(JSON.stringify({})) ;
res.end();
},
2000);
},
2000);
},
2000);
},
2000);
},
2000);
[enter image description here][1]});

How to wait for async HTTP requests to return values on Angular 4?

I have some "cards" that I want to get information for them on an Angular service, the problem is that I get this information with http requests on an API, and I want the return to happen after ALL requests are completed.
cards.component.ts
import {Component} from '#angular/core';
import {CardsService} from './cards.service';
import 'easy-pie-chart/dist/jquery.easypiechart.js';
#Component({
selector: 'cards',
templateUrl: './cards.html',
styleUrls: ['./cards.scss']
})
// TODO: move easypiechart to component
export class Cards {
public charts: any;
constructor(private _cardsService: CardsService) {
this.charts = this._cardsService.getData();
}
}
cards.service.ts
import {Injectable} from '#angular/core';
import {BaThemeConfigProvider, colorHelper} from '../../../theme';
import { Http, Headers, Response } from '#angular/http';
import {Observable} from "rxjs/Observable";
#Injectable()
export class CardsService {
_meterCountURL = 'http://localhost:8080/meter/count';
_cardMeter;
_cardConsumption;
constructor(private _baConfig:BaThemeConfigProvider, private http: Http) {
}
getData() {
let pieColor = this._baConfig.get().colors.custom.dashboardPieChart;
let headers = new Headers({'Content-type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + localStorage.getItem('id_token')});
Observable.forkJoin(
this.http.get(this._meterCountURL, {headers: headers}).map((response) => {response.json()['data'];}),
this.http.get(this._meterCountURL, {headers: headers}).map((response) => {response.json()['data'];})
).subscribe(
data => {
this._cardMeter = data[0];
this._cardConsumption = data[1];
},
error => console.log(error)
);
return [
color: pieColor,
description: 'Consumo do mês atual',
stats: 0 || this._cardConsumption,
icon: 'ion-flash',
}, {
color: pieColor,
description: 'Número de unidades ativas',
stats: 0 || this._cardMeter,
icon: 'ion-ios-speedometer',
}
];
}
}
When It runs, where it should have an Integer, it appears:
[object Object].
If I try to put the return statement INSIDE the subscribe function, 'cards.component.ts' gives me the following error:
Type 'void' is not assignable to type 'Object[]'.
How can I return the card information after the http requests finishes correctly?
You should be returning the observable in your getData() method, then subscribe in your component. This way the component knows when the observable completes (in the subscribe method).
// card.service.ts
getData() {
return Observable.forkJoin(...);
}
// cards.component.ts
this._cardsService.getData().subscribe(data => {
this.charts = ...;
});

Resources