This is a sample application to get up and running with Angular 5+ and RethinkDB The middle layer is using Horizon
At the time of writing, horizon.io is not online anymore. But the docs can be found at RethinkDB git here
An online version can be found here
You can clone this project, run it as is: git clone https://github.com/BartNetJS/AngularWithRethinkDB cd AngularWithRethinkDB npm i npm run start
https://code.visualstudio.com/
Or any code editor you like
Install RethinkDB: https://rethinkdb.com/docs/install/
Check the administrative portal: http://localhost:8080/
Check if the path to rethinkdb.exe exist in your environment variables!
On windows I had to logout and login again before the path to rethinkdb was active
The horizon server is the api where your angular app will talk to
npm install -g horizon
hz init will initialize the horizon server. See the .hz map for settings
And start the horizon server
hz serve --dev
you should see the following:
__App available at http://127.0.0.1:8181_
_RethinkDB_
_├── Admin interface: http://localhost:43534
_└── Drivers can connect to port 43533__
_Starting Horizon..._
_🌄 Horizon ready for connections_
Check the administrative portal: http://localhost:43534/ (the port can be diferent, see your output)
Note the "App available at": http://127.0.0.1:8181. This is the endpoint your app will talk to
you can stop the horizon server for now
npm install -g @angular/cli
ng new RethinkNGDemoApp -minimal
cd RethinkNGDemoApp
npm i rxjs -s
npm i @horizon/client -s
npm i angular2-uuid -s
npm install @angular/material @angular/cdk -s
npm install @angular/animations -s
npm install concurrently --save-dev
If you see an error while
ng new
is scafolding the app (e.g. 'Package install failed, see above.'), then runyarn install
in the root folder of your app again. If it still fails, trynpm i
open VSCode by entering
code .
(notice the '.', vscode will be opened in the working folder)
export const environment = {
production: false,
horizonConfiguration: {
host: '127.0.0.1:8181',
}
};
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
BrowserAnimationsModule
],
This section is optional, but the front end will look nice
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
import { MatTableModule, MatButtonModule, MatInputModule } from "@angular/material";
import { CdkTableModule } from "@angular/cdk/table";
imports: [
...,
CdkTableModule,
MatTableModule,
MatButtonModule,
MatInputModule
],
ng g interface models/iModel
Replace the code in i-model.ts with
import { UUID } from 'angular2-uuid';
export interface IModel {
id: UUID;
}
ng g service services/table
Replace the code in table.service.ts with the folowing
import { Observable } from 'rxjs/Rx';
import * as Horizon from '@horizon/client';
import { UUID } from 'angular2-uuid';
import { environment } from '../../environments/environment'
import { IModel } from '../models/i-model';
export interface ITableService {
readonly name: string;
}
export class TableService<T extends IModel> {
private _hz: any;
private _table: any;
constructor(model: ITableService) {
this._hz = new Horizon(environment.horizonConfiguration);
this._table = this._hz(model.name);
}
addObject(data: T | Array<T>): void {
this._table.insert(data);
}
clearCollection(): void {
this._table.fetch().subscribe(
(returnVar: Array<T>) => {
this._table.removeAll(returnVar);
});
}
removeObject(id: UUID | string | Array<UUID> | Array<string>): void {
this._table.remove(id);
}
getCollection(): Observable<T[]> {
return this._table.watch().map((rslt: Observable<T[]>) => { return rslt; });
}
getLimitedCollection(): Observable<T[]> {
return this._table.limit(100).watch().map((rslt: Observable<T[]>) => { return rslt; });
}
getFirstObject(): Observable<T> {
return this._table.watch().map((rslt: Observable<T[]>) => { return rslt[0]; });
}
getObjectThroughUuid(id: UUID | string): Observable<T> {
return this._table.find(id).watch().map((rslt: Observable<T>) => { return rslt; });
}
updateObject(obj: T) {
this._table.update(obj);
}
}
ng g service services/customer
Replace code with
import { Injectable } from '@angular/core';
import { TableService } from './table.service';
import { Customer, Customers } from '../models/customer';
@Injectable()
export class CustomerService extends TableService<Customer> {
constructor() {
super(new Customers());
}
}
add the CustomerService to the provider section in app.module.ts
import {CustomerService} from './services/customer.service';
providers: [CustomerService]
ng g class models/Customer
Replace code with
import { UUID } from 'angular2-uuid';
import { ITableService } from '../services/table.service';
import { IModel } from './i-model';
export interface ICustomer extends IModel {
id: UUID;
name: string;
contactMail: string;
telephone: string;
contactName: string;
contactTitle: string;
contactTelephone: string;
street: string;
houseNumber: string;
city: string;
postCode: string;
country: string;
}
export class Customer {
id: UUID;
name: string;
contactMail: string;
telephone: string;
contactName: string;
contactTitle: string;
contactTelephone: string;
street: string;
houseNumber: string;
city: string;
postCode: string;
country: string;
public constructor(init?: Partial<ICustomer>) {
Object.assign(this, init);
}
}
export class Customers implements ITableService{
readonly name: string;
constructor() {
this.name = (<any>this).constructor.name;
}
}
ng g component components/customers
Replace code with
import { Component, OnInit } from "@angular/core";
import { MatTableDataSource } from "@angular/material";
import { CustomerService } from "../../services/customer.service";
import { Customer, ICustomer } from "../../models/customer";
@Component({
selector: "app-customers",
template: `
<app-customer></app-customer>
<mat-table #table [dataSource]="dataSource">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
</ng-container>
<!-- remove Column -->
<ng-container matColumnDef="remove">
<mat-header-cell *matHeaderCellDef>
</mat-header-cell>
<mat-cell *matCellDef="let row">
<button mat-button (click)="remove(row)">Remove</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
`,
styles: []
})
export class CustomersComponent implements OnInit {
public customers: Customer[] = [];
public dataSource: MatTableDataSource<Customer>;
public displayedColumns = ["name", "remove"];
constructor(private customerService: CustomerService) {}
ngOnInit(): void {
this.customerService.getCollection().subscribe(customers => {
this.customers = customers;
this.dataSource = new MatTableDataSource(this.customers);
});
}
remove(customer: ICustomer): void {
this.customerService.removeObject(customer.id);
}
}
ng g component components/customer
Replace the code
import { Component, OnInit, Input } from "@angular/core";
import { CustomerService } from "../../services/customer.service";
import { ICustomer, Customer } from "../../models/customer";
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
@Component({
selector: "app-customer",
template: `
<form #f="ngForm" (ngSubmit)="onSubmit()" name="form" >
<mat-form-field>
<input matInput required placeholder="Customer name" type="text" [(ngModel)]="customer.name" name="first">
</mat-form-field>
<button mat-button type="submit">Add</button>
<!--[disabled]="!form.valid"-->
</form>
`,
styles: []
})
export class CustomerComponent implements OnInit {
@Input() customer: ICustomer = new Customer();
form: FormGroup;
constructor(private customerService: CustomerService, private formBuilder: FormBuilder) {}
ngOnInit(): void {
this.form = this.formBuilder.group({
name: [null, [Validators.required]],
});
}
onSubmit(): void {
this.customerService.addObject(this.customer);
}
}
import { Component } from "@angular/core";
@Component({
selector: "app-root",
template: `
<h1>Customers</h1>
<app-customers></app-customers>
`,
styles: []
})
export class AppComponent {
title = "app";
}
"scripts": {
...
"start": "concurrently \"hz serve --dev\" \"ng serve --open\" ",
...
}
npm run start