Force Gradle to redownload dependencies
./gradlew build --refresh-dependencies
References
https://stackoverflow.com/questions/13565082/how-can-i-force-gradle-to-redownload-dependencies
./gradlew build --refresh-dependencies
References
https://stackoverflow.com/questions/13565082/how-can-i-force-gradle-to-redownload-dependencies
LC_ALL=C lscpu | grep Virtualization
zgrep CONFIG_KVM /proc/config.gz
sudo pacman -S virt-manager qemu vde2 ebtables dnsmasq bridge-utils openbsd-netcat
sudo systemctl enable libvirtd.service
sudo systemctl start libvirtd.service
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule, HttpModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
app.component.html
<div class="container"> <div class="row"> <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2"> <form (ngSubmit)="onSubmit(myForm)" #myForm="ngForm"> <div id="user-data"> <div class="form-group"> <label for="username">Username</label> <input type="text" id="username" class="form-control" ngModel name="username"> </div> <button class="btn btn-default" type="button">Suggest an Username</button> <div class="form-group"> <label for="email">Mail</label> <input type="email" id="email" class="form-control" ngModel name="email"> </div> </div> <div class="form-group"> <label for="secret">Secret Questions</label> <select id="secret" class="form-control" ngModel name="secret"> <option value="pet">Your first Pet?</option> <option value="teacher">Your first teacher?</option> </select> </div> <button class="btn btn-primary" type="submit">Submit</button> </form> </div> </div> </div>
app.component.ts
import {Component} from '@angular/core'; import {NgForm} from '@angular/forms'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { suggestUserName() { const suggestedName = 'Superuser'; } onSubmit(form: NgForm) { console.log(form); } }
References
https://angular.io/guide/forms
Reactive forms are more robust: they’re more scalable, reusable, and testable. If forms are a key part of your application, or you’re already using reactive patterns for building your application, use reactive forms.
Template-driven forms are useful for adding a simple form to an app, such as an email list signup form. They’re easy to add to an app, but they don’t scale as well as reactive forms. If you have very basic form requirements and logic that can be managed solely in the template, use template-driven forms.
References
https://angular.io/guide/forms-overview
let error = true; function doAsyncTask() { return new Promise((resolve, reject) => { setTimeout(() => { if (error) { reject('error'); // pass values } else { resolve('done'); // pass values } }, 1000); }); } doAsyncTask().then( (val) => console.log(val), (err) => console.error(err) );
Nested Promise
this.localStorage.clear().toPromise() .then((value1: boolean) => { console.log(value1); return this.localStorage.setItem(value.userName, value.token).toPromise(); }) .then((value2: boolean) => { console.log(value2); });
References
https://codecraft.tv/courses/angular/es6-typescript/promises/
https://stackoverflow.com/questions/40519484/promise-waterfall
app.module.ts
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { Routes, RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; const routes: Routes = [ ]; @NgModule({ imports: [ BrowserModule, FormsModule, RouterModule.forRoot(routes, { useHash: true }) // .../#/crisis-center/ ], declarations: [ AppComponent, PageNotFoundComponent ], providers: [ ], bootstrap: [ AppComponent ] }) export class AppModule { }
Output
http://localhost:4200/#/users
References
https://angular.io/guide/router#hashlocationstrategy
One way to deal with getting and displaying data from an API is to route a user to a component, and then in that component’s ngOnInit hook call a method in a service to get the necessary data. While getting the data, perhaps the component can show a loading indicator. There’s another way however using what’s known as a route resolver, which allows you to get data before navigating to the new route.
server-resolver.service.ts
import {Injectable} from '@angular/core'; import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from '@angular/router'; import {Observable} from 'rxjs/Observable'; import {ServersService} from '../servers.service'; interface Server { id: number; name: string; status: string; } @Injectable({ providedIn: 'root' }) export class ServerResolverService implements Resolve<Server> { constructor(private serversService: ServersService) { } resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Server> | Promise<Server> | Server { return this.serversService.getServer(+route.params['id']); } }
app.module.ts
import {BrowserModule} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {HttpModule} from '@angular/http'; import {AppComponent} from './app.component'; import {HomeComponent} from './home/home.component'; import {UsersComponent} from './users/users.component'; import {ServersComponent} from './servers/servers.component'; import {UserComponent} from './users/user/user.component'; import {EditServerComponent} from './servers/edit-server/edit-server.component'; import {ServerComponent} from './servers/server/server.component'; import {ServersService} from './servers/servers.service'; import {RouterModule, Routes} from '@angular/router'; import {PageNotFoundComponent} from './page-not-found/page-not-found.component'; import {AuthService} from './auth.service'; import {AuthGuard} from './auth.guard'; import {CanDeactivateGuard} from './can-deactivate.guard'; import {ErrorPageComponent} from './error-page/error-page.component'; import {ServerResolverService} from './servers/server/server-resolver.service'; const appRoutes: Routes = [ {path: '', component: HomeComponent}, { path: 'users', component: UsersComponent, children: [ {path: ':id/:name', component: UserComponent}] }, { path: 'servers', canActivateChild: [AuthGuard], component: ServersComponent, children: [ {path: ':id', component: ServerComponent, resolve: {server: ServerResolverService}}, {path: ':id/edit', component: EditServerComponent, canDeactivate: [CanDeactivateGuard]} ] }, // {path: 'not-found', component: PageNotFoundComponent}, {path: 'not-found', component: ErrorPageComponent, data: {message: 'Page not found'}}, {path: '**', redirectTo: '/not-found'}, ]; @NgModule({ declarations: [ AppComponent, HomeComponent, UsersComponent, ServersComponent, UserComponent, EditServerComponent, ServerComponent, PageNotFoundComponent, ErrorPageComponent ], imports: [ BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes) ], providers: [ServersService, AuthGuard, AuthService, CanDeactivateGuard, ServerResolverService], bootstrap: [AppComponent] }) export class AppModule { }
server.component.ts
import {Component, OnInit} from '@angular/core'; import {ServersService} from '../servers.service'; import {ActivatedRoute, Data, Params, Router} from '@angular/router'; @Component({ selector: 'app-server', templateUrl: './server.component.html', styleUrls: ['./server.component.css'] }) export class ServerComponent implements OnInit { server: { id: number, name: string, status: string }; constructor(private serversService: ServersService, private route: ActivatedRoute, private router: Router) { } ngOnInit() { this.route.data.subscribe((value: Data) => { this.server = value['server']; }); // const id = +this.route.snapshot.params['id']; // this.server = this.serversService.getServer(id); // this.route.params.subscribe((params: Params) => { // this.server = this.serversService.getServer(+params['id']); // }); } onEdit() { this.router.navigate(['edit'], {relativeTo: this.route, queryParamsHandling: 'preserve'}); } }
References
https://angular.io/guide/router#resolve-pre-fetching-component-data
error-page.component.html
<h4>{{errorMessage}}</h4>
app.module.ts
import {BrowserModule} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {HttpModule} from '@angular/http'; import {AppComponent} from './app.component'; import {HomeComponent} from './home/home.component'; import {UsersComponent} from './users/users.component'; import {ServersComponent} from './servers/servers.component'; import {UserComponent} from './users/user/user.component'; import {EditServerComponent} from './servers/edit-server/edit-server.component'; import {ServerComponent} from './servers/server/server.component'; import {ServersService} from './servers/servers.service'; import {RouterModule, Routes} from '@angular/router'; import {PageNotFoundComponent} from './page-not-found/page-not-found.component'; import {AuthService} from './auth.service'; import {AuthGuard} from './auth.guard'; import {CanDeactivateGuard} from './can-deactivate.guard'; import {ErrorPageComponent} from './error-page/error-page.component'; const appRoutes: Routes = [ {path: '', component: HomeComponent}, { path: 'users', component: UsersComponent, children: [ {path: ':id/:name', component: UserComponent}] }, { path: 'servers', canActivateChild: [AuthGuard], component: ServersComponent, children: [ {path: ':id', component: ServerComponent}, {path: ':id/edit', component: EditServerComponent, canDeactivate: [CanDeactivateGuard]} ] }, // {path: 'not-found', component: PageNotFoundComponent}, {path: 'not-found', component: ErrorPageComponent, data: {message: 'Page not found'}}, {path: '**', redirectTo: '/not-found'}, ]; @NgModule({ declarations: [ AppComponent, HomeComponent, UsersComponent, ServersComponent, UserComponent, EditServerComponent, ServerComponent, PageNotFoundComponent, ErrorPageComponent ], imports: [ BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes) ], providers: [ServersService, AuthGuard, AuthService, CanDeactivateGuard], bootstrap: [AppComponent] }) export class AppModule { }
error-page.component.ts
import {Component, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; @Component({ selector: 'app-error-page', templateUrl: './error-page.component.html', styleUrls: ['./error-page.component.css'] }) export class ErrorPageComponent implements OnInit { errorMessage: string; constructor(private route: ActivatedRoute) { } ngOnInit() { this.errorMessage = this.route.snapshot.data['message']; this.route.data.subscribe((value: Date) => { this.errorMessage = value['message']; }); } }
can-deactivate.guard.ts
import {Injectable} from '@angular/core'; import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanDeactivate} from '@angular/router'; import {Observable} from 'rxjs/Observable'; export interface CanComponenDeactive { canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean; } @Injectable({ providedIn: 'root' }) export class CanDeactivateGuard implements CanDeactivate<CanComponenDeactive> { canDeactivate(component: CanComponenDeactive, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { return component.canDeactivate(); } }
edit-server.component.ts
import {Component, OnInit} from '@angular/core'; import {ServersService} from '../servers.service'; import {ActivatedRoute, Params, Router} from '@angular/router'; import {CanComponenDeactive} from '../../can-deactivate.guard'; import {Observable} from 'rxjs/Observable'; @Component({ selector: 'app-edit-server', templateUrl: './edit-server.component.html', styleUrls: ['./edit-server.component.css'] }) export class EditServerComponent implements OnInit, CanComponenDeactive { server: { id: number, name: string, status: string }; serverName = ''; serverStatus = ''; allowEdit = false; changesSaved = false; constructor(private serversService: ServersService, private route: ActivatedRoute, private router: Router) { } ngOnInit() { // retrieve params on initializing this.allowEdit = this.route.snapshot.queryParams['allowEdit'] === '1' ? true : false; console.log(this.route.snapshot.fragment); // retrieve params on changes this.route.queryParams.subscribe((value: Params) => { this.allowEdit = value['allowEdit'] === '1' ? true : false; }); this.route.fragment.subscribe((value: string) => { console.log(value); }); const id = +this.route.snapshot.params['id']; this.server = this.serversService.getServer(id); this.route.params.subscribe((value: Params) => { this.server = this.serversService.getServer(+value['id']); }); this.serverName = this.server.name; this.serverStatus = this.server.status; } onUpdateServer() { this.serversService.updateServer(this.server.id, {name: this.serverName, status: this.serverStatus}); this.changesSaved = true; this.router.navigate(['../'], {relativeTo: this.route}); } canDeactivate(): boolean | Observable<boolean> | Promise<boolean> { if (!this.allowEdit) { return true; } if ((this.serverName !== this.server.name || this.serverStatus !== this.server.status) && !this.changesSaved) { return confirm('Do you want to discard the changes?'); } { return true; } } }
app.module.ts
import {BrowserModule} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {HttpModule} from '@angular/http'; import {AppComponent} from './app.component'; import {HomeComponent} from './home/home.component'; import {UsersComponent} from './users/users.component'; import {ServersComponent} from './servers/servers.component'; import {UserComponent} from './users/user/user.component'; import {EditServerComponent} from './servers/edit-server/edit-server.component'; import {ServerComponent} from './servers/server/server.component'; import {ServersService} from './servers/servers.service'; import {RouterModule, Routes} from '@angular/router'; import {PageNotFoundComponent} from './page-not-found/page-not-found.component'; import {AuthService} from './auth.service'; import {AuthGuard} from './auth.guard'; import {CanDeactivateGuard} from './can-deactivate.guard'; const appRoutes: Routes = [ {path: '', component: HomeComponent}, { path: 'users', component: UsersComponent, children: [ {path: ':id/:name', component: UserComponent}] }, { path: 'servers', canActivateChild: [AuthGuard], component: ServersComponent, children: [ {path: ':id', component: ServerComponent}, {path: ':id/edit', component: EditServerComponent, canDeactivate: [CanDeactivateGuard]} ] }, {path: 'not-found', component: PageNotFoundComponent}, {path: '**', redirectTo: '/not-found'}, ]; @NgModule({ declarations: [ AppComponent, HomeComponent, UsersComponent, ServersComponent, UserComponent, EditServerComponent, ServerComponent, PageNotFoundComponent ], imports: [ BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes) ], providers: [ServersService, AuthGuard, AuthService, CanDeactivateGuard], bootstrap: [AppComponent] }) export class AppModule { }
References
https://angular.io/guide/router#candeactivate-handling-unsaved-changes
auth.guard.ts
import {Injectable} from '@angular/core'; import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, CanActivateChild} from '@angular/router'; import {Observable} from 'rxjs'; import {AuthService} from './auth.service'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate, CanActivateChild { constructor(private authService: AuthService, private router: Router) { } canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { return this.authService.isAuthenticated().then( (authenticated: boolean) => { if (authenticated) { return true; } else { this.router.navigate(['/']); return false; } } ); } canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { return this.canActivate(childRoute, state); } }
auth.service.ts
import {Injectable} from '@angular/core'; @Injectable({ providedIn: 'root' }) export class AuthService { loggedIn = false; constructor() { } login() { this.loggedIn = true; } logout() { this.loggedIn = false; } isAuthenticated() { const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve(this.loggedIn); }, 800); }); return promise; } }
app.module.ts
import {BrowserModule} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {HttpModule} from '@angular/http'; import {AppComponent} from './app.component'; import {HomeComponent} from './home/home.component'; import {UsersComponent} from './users/users.component'; import {ServersComponent} from './servers/servers.component'; import {UserComponent} from './users/user/user.component'; import {EditServerComponent} from './servers/edit-server/edit-server.component'; import {ServerComponent} from './servers/server/server.component'; import {ServersService} from './servers/servers.service'; import {RouterModule, Routes} from '@angular/router'; import {PageNotFoundComponent} from './page-not-found/page-not-found.component'; import {AuthService} from './auth.service'; import {AuthGuard} from './auth.guard'; const appRoutes: Routes = [ {path: '', component: HomeComponent}, { path: 'users', component: UsersComponent, children: [ {path: ':id/:name', component: UserComponent}] }, { path: 'servers', canActivateChild: [AuthGuard], component: ServersComponent, children: [ {path: ':id', component: ServerComponent}, {path: ':id/edit', component: EditServerComponent} ] }, {path: 'not-found', component: PageNotFoundComponent}, {path: '**', redirectTo: '/not-found'}, ]; @NgModule({ declarations: [ AppComponent, HomeComponent, UsersComponent, ServersComponent, UserComponent, EditServerComponent, ServerComponent, PageNotFoundComponent ], imports: [ BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes) ], providers: [ServersService, AuthGuard, AuthService], bootstrap: [AppComponent] }) export class AppModule { }
References
https://angular.io/guide/router#milestone-5-route-guards