Adrian Brand
8 min readDec 23, 2018

--

constructor(private cache: RxCacheService)
private usersCache = this.cache.get<User[]>({ id: '[Users] users' });
private usersCache = this.cache.get<User[]>({
id: '[Users] users',
construct: () => this.http.get<User[]>('user')
});
users$ = this.usersCache.value$;
loading$ = this.usersCache.loading$;
import { Injectable } from '@angular/core';
import { RxCacheService } from 'ngx-rxcache';
import { MockHttpService } from './mock-http.service';
import { User } from '../models/user';
@Injectable({
providedIn: 'root'
})
export class UsersService {
private usersCache = this.cache.get<User[]>({
id: '[Users] users',
construct: () => this.http.get<User[]>('user')
});
users$ = this.usersCache.value$;
loading$ = this.usersCache.loading$;
constructor(
private http: MockHttpService,
private cache: RxCacheService
) {}
load() {
this.usersCache.load();
}
}
import { Component } from '@angular/core';import { UsersService } from '../../services/users.service';@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent {
users$ = this.usersService.users$;
loading$ = this.usersService.loading$;
constructor(private usersService: UsersService) {
usersService.load();
}
}
<h1>Users</h1><app-spinner *ngIf="loading$ | async else loaded">loading</app-spinner>
<ng-template #loaded>
<table *ngIf="users$ | async as users">
<thead>
<tr *ngIf="users.length">
<th>Name</th>
<th>Email</th>
</tr>
<tr *ngIf="users.length === 0">
<th>No users</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td>{{user.firstName}} {{user.lastName}}</td>
<td>{{user.email}}</td>
</tr>
</tbody>
</table>
</ng-template>
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { RxCacheService } from 'ngx-rxcache';
import { MockHttpService } from './mock-http.service';
import { SelectItem } from '../models/select-item';
@Injectable({
providedIn: 'root'
})
export class RefDataService {
private titlesCache = this.cache.get<SelectItem[]>({
id: '[RefData] titles',
construct: () => this.http.get<SelectItem[]>('titles'),
autoload: true
});
constructor(
private http: MockHttpService,
private cache: RxCacheService
) {}
get titles$(): Observable<SelectItem[]> {
return this.titlesCache.value$;
}
}
titles$ = this.titlesCache.value$;
import { Injectable } from '@angular/core';
import { RxCacheService } from 'ngx-rxcache';
import { MockHttpService } from './mock-http.service';
import { User } from '../models/user';
@Injectable({
providedIn: 'root'
})
export class UserService {
private userCache = this.cache.get<User>({
id: '[User] user',
save: (user: User) => user.id ? this.http.put<User>(`user/${user.id}`, user) : this.http.post<User>('user', user),
delete: (user: User) => this.http.delete(`user/${user.id}`),
errorHandler: (response) => response.error
});
user$ = this.userCache.clone$;
loading$ = this.userCache.loading$;
saving$ = this.userCache.saving$;
error$ = this.userCache.error$;
constructor(
private http: MockHttpService,
private cache: RxCacheService
) {}
save(user: User, saved?: (response) => void) {
this.userCache.save(user, saved);
}
delete(user: User, deleted?: (response) => void) {
this.userCache.delete(user, deleted);
}
load(id?: number) {
if (id) {
this.userCache.load(() => this.http.get<User>(`user/${id}`));
} else {
this.userCache.update({
id: null,
title: null,
firstName: '',
lastName: '',
email: ''
});
}
}
}
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { map } from 'rxjs/operators';
import { UserService } from '../../services/user.service';
import { RefDataService } from '../../services/ref-data.service';
import { User } from '../../models/user';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent {
user$ = this.userService.user$;
loading$ = this.userService.loading$;
saving$ = this.userService.saving$;
error$ = this.userService.error$;
titles$ = this.refDataService.titles$;
constructor(
private userService: UserService,
private refDataService: RefDataService,
private route: ActivatedRoute,
private router: Router
) {
const id = route.snapshot.paramMap.get('id');
userService.load(parseInt(id));
}
save(user: User) {
this.userService.save(user, _ => {
this.router.navigate(['/users']);
});
}
}
<h1>User</h1><app-spinner *ngIf="loading$ | async else loaded">loading</app-spinner><ng-template #loaded>  <div class="error" *ngIf="error$ | async as error">{{error}}</div>  <form *ngIf="user$ | async as user" (submit)="save(user)">    <label for="title">Title</label><br>
<select id="title" name="title" [(ngModel)]="user.title">
<option [ngValue]="null">Please select</option>
<option *ngFor="let title of titles$ | async" [value]="title.value">{{title.label}}</option>
</select><br>
<label for="firstName">First Name</label><br>
<input type="text" id="firstName" name="firstName" [(ngModel)]="user.firstName"><br>
<label for="lastName">Last Name</label><br>
<input type="text" id="lastName" name="lastName" [(ngModel)]="user.lastName"><br>
<label for="email">Email</label><br>
<input type="text" id="email" name="email" [(ngModel)]="user.email"><br>
<app-spinner *ngIf="saving$ | async else saved">saving</app-spinner>
<ng-template #saved>
<button>Save</button>
</ng-template>
</form>
</ng-template><a routerLink="/users">Cancel</a>
{ path: 'user', component: UserComponent },
{ path: 'user/:id', component: UserComponent }
<td><a [routerLink]="'/user/' + user.id">{{user.firstName}} {{user.lastName}}</a></td>
<a routerLink="../user">Add new user</a>
<td><button (click)="delete(user)">delete</button></td>
constructor(private usersService: UsersService, private userService: UserService) {
delete(user: User) {
this.userService.delete(user, _ => {
this.usersService.load();
});
}

--

--