changes to get to Angular 5 and the new HttpClient
for complete documentation on the new HttpClient go to
angular.io
check node.js version
node -v
and update node as necessary
update/install the latest NodeJs
uninstall NodeJs if installed and version is not the latest from
nodejs.org
to check installed version use the command prompt
node -v
- Uninstall from Programs & Features with the uninstaller
- reboot
-
Look for these folders and remove them (and their contents) if any still exist.
Depending on the version you installed, UAC settings, and CPU architecture, these
may or may not exist:
- C:\Program Files (x86)\Nodejs
- C:\Program Files\Nodejs
- C:\Users\{User}\AppData\Roaming\npm (or %appdata%\npm)
- C:\Users\{User}\AppData\Roaming\npm-cache (or %appdata%\npm-cache)
- C:\Users\{User}\.npmrc (and possibly check for that without the . prefix too)
- reboot
-
Check your %PATH% environment variable to ensure no references to Node.js or npm
exist.
install latest version of NodeJS using the msi from
nodejs.org
update/install the latest version of Angular's CLI (command line interface)
to determine the installed version of CLI
ng --version
to update Angular CLI to a new version, both the global package and the project's
local package must be uninstalled
global
npm uninstall -g @angular/cli
npm cache clean
npm install -g @angular/cli@latest
node versions change quickly going from 6.11.1 to 8.9.1 LTS in just the feek weeks
of course time
the many steps are tedious, with W10 the installed node.js version's msi cleans
the up the uninstall quite well
each step just verifies how well everything cleans up
update angular CLI to latest version
npm uninstall -g @angular/cli
npm cache clean
npm install -g @angular/cli@latest
new apps created using CLI 1.5 use angular 5 which is global as well so no warnings
Top
Index
in app.module imports property includes HttpModule
change to HttpClientMode and change import statement accordingly
...
// import { HttpModule } from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
...
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
// HttpModule,
HttpClientModule,
...
],
bootstrap: [AppComponent]
})
export class AppModule { }
the HttpClient has a generic get function
getRecipes() {
const token = this.authService.getToken();
this.httpService.get<Recipe[]>('https://ng-recipe-book-47065.firebaseio.com/recipes.json?auth=' + token)
.map(
(recipes) => {
for (let recipe of recipes) {
if (!recipe['ingredients']) {
recipe['ingredients'] = [];
}
}
return recipes;
})
.subscribe(
(recipes) => {
this.recipeService.setRecipes(recipes);
}
);
}
Top
Index
request configuration and response
HttpClient's generic get used when response is json data
overloaded get and put methods can be used for other data formats
additional JSON arg named options
snippet from data-storage.service
getRecipes() {
const token = this.authService.getToken();
// use overloaded generic method so mapping doesn't change
this.httpService.get<Recipe[]>('https://ng-recipe-book-47065.firebaseio.com/recipes.json?auth=' + token,
// options are to return the body as JSON data
{ 'observe': 'body', 'responseType': 'json' }
).map(
(recipes) => {
for (const recipe of recipes) {
if (!recipe['ingredients']) {
recipe['ingredients'] = [];
}
}
return recipes;
}
).subscribe(
(recipes) => {
this.recipeService.setRecipes(recipes);
}
);
}
when no observe value is set in the options then the body is returned
Top
Index
add options arg to put request
set observe property to events snippet from data-storage.service
storeRecipes() {
const token = this.authService.getToken();
const recipes = this.recipeService.getRecipes();
return this.httpService.put(
'https://ng-recipe-book-47065.firebaseio.com/recipes.json?auth=' + token, recipes,
{ observe: 'events' });
}
the header component subscribes to the events
onSaveData() {
this.dataStorageService.storeRecipes()
.subscribe(
(event: HttpEvent<object>) => {
console.log(event.type);
}
);
}
Top
Index
in options object can use headers property
in data-storage.service the function below appends a custom header to the request
storeRecipes() {
const token = this.authService.getToken();
const recipes = this.recipeService.getRecipes();
return this.httpService.put(
'https://ng-recipe-book-47065.firebaseio.com/recipes.json?auth=' + token, recipes,
{
observe: 'events',
headers: new HttpHeaders().append('foo', 'bar')
});
}
Top
Index
in data-storage.service the function below the query string has been removed from
the URL
the parameters are passed in the options arg's params property
storeRecipes() {
const token = this.authService.getToken();
const recipes = this.recipeService.getRecipes();
return this.httpService.put(
// 'https://ng-recipe-book-47065.firebaseio.com/recipes.json?auth=' + token, recipes,
'https://ng-recipe-book-47065.firebaseio.com/recipes.json', recipes,
{
observe: 'events',
headers: new HttpHeaders().append('foo', 'bar'),
params: new HttpParams().set('auth', token)
});
}
Top
Index
HttpClient's built-in HttpRequest does not support progress events
a manually created HttpRequest will support progress events
use HttpClient's request method to post the request
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams, HttpRequest } from '@angular/common/http';
...
@Injectable()
export class DataStorageService {
constructor(
private httpService: HttpClient,
private recipeService: RecipeService,
private authService: AuthService) { }
storeRecipes() {
const token = this.authService.getToken();
const url = 'https://ng-recipe-book-47065.firebaseio.com/recipes.json';
const recipes = this.recipeService.getRecipes();
const req = new HttpRequest('PUT', url, recipes, {
reportProgress: true,
params: new HttpParams().set('auth', token)
});
return this.httpService.request(req);
}
...
}
Top
Index
typical use case to do something with every http request
example is adding auth token to request params
create new file in shared directory
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('intercepted :', req);
// call to let request continue its journey
return next.handle(req);
}
}
in core.module add AuthInterceptor to providers array property using JSON data
format show in comment below
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
...
import { AuthInterceptor } from '../shared/auth.interceptor';
@NgModule({
declarations: [
...
],
imports: [
...
],
exports: [
...
],
providers: [
ShoppingListService,
RecipeService,
DataStorageService,
AuthService,
AuthGuard,
// purpose of provider, type to use, multiple instances?
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
})
export class CoreModule { }
Top
Index
modifying requests in interceptors
HttpRequests are immutable
to change a request it must be cloned
the clone method takes a configuration info as JSON data
add Injectable decoration to AuthInterception
inject AuthService to be able to get the token
clone the request passing a configuration object
set the auth param to the token using the request's param's set method
in the cloned request's configuration object set the params property to the modified
request params
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import {AuthService} from '../auth/auth.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('intercepted :', req);
const token = this.authService.getToken();
const copiedRequest = req.clone({ params: req.params.set('auth', token) });
// call to let request continue its journey
return next.handle(copiedRequest);
}
}
Top
Index
add new file logging.interceptor.ts in shared directory
when the call to next.handle returns the chained do method logs the event
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/do';
export class LoggingInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('intercepted :', req);
return next.handle(req).do(
event => {
console.log('logging interceptor :', event);
}
);
}
}
in core.module add the new interceptor as a provider
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
...
import { AuthInterceptor } from '../shared/auth.interceptor';
import { LoggingInterceptor } from '../shared/logging.interceptor';
@NgModule({
declarations: [
...
],
imports: [
...
],
exports: [
...
],
providers: [
...
// order here determines chain
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }
]
})
export class CoreModule { }
Top
Index