Getting started
ng update
ng update
# Check for updates
ng update @angular/core @angular/cli
# Update Angular packages
ng update --all
# Update all dependencies
ng update --dry-run
# Preview changes only
ng add
ng add @angular/material
# Add Material Design
ng add @angular/pwa
# Add PWA support
ng add @angular/elements
# Add Web Components
ng add @ng-bootstrap/schematics
# Add third-party schematics
Tree-Shakable Providers
@Injectable({ providedIn: "root" })
export class DataService {
constructor(private http: HttpClient) {}
}
Service registers itself automatically.
@NgModule({}) // No providers needed
export class AppModule {}
Unused services removed from bundle.
@Injectable({ providedIn: SomeModule })
export class ScopedService {}
Scope to specific module.
RxJS 6 Migration
Import Changes
// OLD (RxJS 5)
import { Observable } from "rxjs/Observable";
import "rxjs/add/operator/map";
import "rxjs/add/observable/of";
// NEW (RxJS 6)
import { Observable, of, from } from "rxjs";
import { map, filter, tap } from "rxjs/operators";
All imports from 'rxjs'.
Pipe Syntax
// OLD
source
.map((x) => x + x)
.filter((x) => x % 2 === 0)
.catch((err) => of("error"))
.subscribe();
// NEW
source
.pipe(
map((x) => x + x),
filter((x) => x % 2 === 0),
catchError((err) => of("error")),
)
.subscribe();
Use pipe() for operators.
Observable Creation
// OLD
Observable.of(1, 2, 3);
Observable.from([1, 2, 3]);
Observable.throw(new Error("fail"));
Observable.empty();
Observable.never();
// NEW
of(1, 2, 3);
from([1, 2, 3]);
throwError(new Error("fail"));
EMPTY;
NEVER;
Top-level creation functions.
Renamed Operators
| Old (RxJS 5) | New (RxJS 6) |
|---|---|
do |
tap |
catch |
catchError |
switch |
switchAll |
finally |
finalize |
throw |
throwError |
Error Handling
// OLD (REMOVED)
try {
source$.subscribe(fn);
} catch (err) {
handle(err);
}
Synchronous errors not caught.
// NEW
source$.subscribe({
next: fn,
error: handle,
complete: completeFn,
});
Use subscribe error callback.
source$
.pipe(
catchError((err) => {
console.error(err);
return of(fallback);
}),
)
.subscribe();
Use catchError operator.
Migration Tool
npm install -g rxjs-tslint
# Install migration tool
rxjs-5-to-6-migrate -p src/tsconfig.app.json
# Auto-migrate imports
npm install rxjs-compat
# Temporary compatibility layer
Angular Elements
Creating Custom Elements
import { createCustomElement } from "@angular/elements";
import { Injector, NgModule } from "@angular/core";
@NgModule({
declarations: [PopupComponent],
entryComponents: [PopupComponent],
})
export class AppModule {
constructor(private injector: Injector) {
const PopupElement = createCustomElement(PopupComponent, { injector });
customElements.define("popup-element", PopupElement);
}
ngDoBootstrap() {}
}
Converts Angular components to Web Components.
Using Custom Elements
<!-- Use in non-Angular pages -->
<popup-element message="Hello!"></popup-element>
// Set properties
const popup = document.querySelector("popup-element");
popup.message = "Dynamic message";
// Listen to events
popup.addEventListener("closed", (e) => {
console.log("Popup closed", e.detail);
});
Component for Elements
@Component({
selector: "popup-element",
template: `
<div class="popup">
<h2>{{ message }}</h2>
<button (click)="close()">Close</button>
</div>
`,
})
export class PopupComponent {
@Input() message: string;
@Output() closed = new EventEmitter<any>();
close() {
this.closed.emit({ timestamp: Date.now() });
}
}
Use @Input/@Output as usual.
CLI Workspaces
angular.json
{
"version": 1,
"projects": {
"my-app": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/my-app"
},
"configurations": {
"production": {
"optimization": true
}
}
}
}
}
}
}
Replaces .angular-cli.json.
Multiple Projects
ng generate application second-app
# Add application
ng generate library my-lib
# Add library
ng build my-app
# Build specific project
ng serve second-app
# Serve specific app
Library Support
Generating Libraries
ng generate library my-lib
Creates projects/my-lib/ structure.
projects/my-lib/
src/
lib/
my-lib.component.ts
my-lib.module.ts
my-lib.service.ts
public-api.ts
ng-package.json
package.json
tsconfig.lib.json
public-api.ts
/*
* Public API Surface of my-lib
*/
export * from "./lib/my-lib.service";
export * from "./lib/my-lib.component";
export * from "./lib/my-lib.module";
Define library exports.
Building Libraries
ng build my-lib
# Build library
ng build my-lib --watch
# Watch mode
// Use in app
import { MyLibModule } from "my-lib";
@NgModule({
imports: [MyLibModule],
})
export class AppModule {}
Publishing Libraries
cd dist/my-lib
npm publish
# Publish to npm
{
"name": "@myscope/my-lib",
"version": "1.0.0",
"peerDependencies": {
"@angular/core": "^6.0.0"
}
}
Configure package.json.
Material Schematics
Navigation Schematic
ng generate @angular/material:material-nav --name=my-nav
Creates sidenav with toolbar.
import { LayoutModule } from "@angular/cdk/layout";
import { MatToolbarModule } from "@angular/material/toolbar";
import { MatSidenavModule } from "@angular/material/sidenav";
Imports CDK layout + Material.
Dashboard Schematic
ng generate @angular/material:material-dashboard --name=my-dashboard
Creates responsive dashboard cards.
import { MatGridListModule } from "@angular/material/grid-list";
import { MatCardModule } from "@angular/material/card";
import { MatMenuModule } from "@angular/material/menu";
Table Schematic
ng generate @angular/material:material-table --name=my-table
Creates data table with sorting/paging.
import { MatTableModule } from "@angular/material/table";
import { MatPaginatorModule } from "@angular/material/paginator";
import { MatSortModule } from "@angular/material/sort";
Common Operators (RxJS 6)
Transformation
map((x) => x * 2);
Transform emitted values.
switchMap((id) => this.http.get(`/user/${id}`));
Switch to new observable.
mergeMap((x) => doAsync(x));
Merge concurrent streams.
concatMap((x) => doAsync(x));
Sequential processing.
exhaustMap((x) => doAsync(x));
Ignore while pending.
Filtering
filter((x) => x > 10);
Emit if condition true.
take(5);
Emit first N values.
takeUntil(notifier$);
Complete when notified.
debounceTime(300);
Wait for pause.
distinctUntilChanged();
Skip duplicate consecutive values.
Combination
combineLatest([a$, b$, c$]);
Latest from each.
merge(a$, b$, c$);
Merge all emissions.
concat(a$, b$, c$);
Sequential concatenation.
forkJoin([a$, b$, c$]);
Wait for all completions.
withLatestFrom(other$);
Include latest from other.
Error Handling
catchError((err) => of(fallback));
Recover from errors.
retry(3);
Retry failed observable.
retryWhen((errors$) => errors$.pipe(delay(1000)));
Conditional retry logic.
Utility
tap((x) => console.log(x));
Side effects.
delay(1000);
Delay emissions.
finalize(() => cleanup());
Execute on completion/error.
share();
Share subscription.
startWith(initialValue);
Emit initial value first.
Gotchas
RxJS 6 Breaking Changes
⚠️ Import paths changed — all from 'rxjs'
⚠️ Operators renamed — do → tap, catch → catchError
⚠️ pipe() required — no more chaining
⚠️ Observable.of → of — creation functions top-level
⚠️ Synchronous error handling removed — no try/catch around subscribe
Configuration Changes
⚠️ angular.json replaces .angular-cli.json — migrate config
⚠️ providedIn: 'root' vs providers array — don't mix for same service
⚠️ rxjs-compat is temporary — remove after refactoring
Angular Elements
⚠️ entryComponents still needed — for custom elements in v6
⚠️ Polyfills required — for custom elements in older browsers
⚠️ Bundle size — includes Angular runtime
General
⚠️ Ivy renderer NOT in v6 — preview only, default in v9
⚠️ No ViewEncapsulation.Native — removed in v6.1
Also see
- Angular 6 Release Announcement - Official blog post
- RxJS 6 Migration Guide - Comprehensive migration guide
- Angular Update Guide - Interactive update tool
- Angular Updating Guide - Official update documentation
- Angular Elements Guide - Web Components with Angular