Last active
December 11, 2016 22:04
-
-
Save Y2017/dc9b495cad4a77482c9924621018853a to your computer and use it in GitHub Desktop.
Username in header
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*********** | |
ORILAB | |
SHARED SERVICES | |
- username in header | |
- ngDestroy eventEmitter.unsubscribe(); | |
private _subscription: Subscription; | |
ngOnDestroy() { | |
if (this._subscription != null) { | |
this._subscription.unsubscribe(); | |
} | |
} | |
_ app.component.css ald <p [ngStyle]="{color:'blue'}" | |
Observable.unsubscribe() for cancelling progress | |
Children route async | |
http://www.javascripttuts.com/getting-started-with-the-new-angular-2-router/ | |
Change <app>Loading...</app> | |
Deploy in Docker Lamp | |
http://www.it-connect.fr/debuter-avec-docker-et-les-containers-sous-debian-8/ | |
https://www.eyesoreinc.com/getting-started-angular2-using-docker-compose/ | |
*********** | |
Plan NG2 : | |
o wishtack : http://courses.wishtack.com/angular-2/javascript | |
o orilab2/ code | |
Focus | |
- ADVANTAGES OF ANGULAR2 | |
Clean : ES6 & Typescript | |
classes, typage | |
Shadow Dom : integration de webcomponents multi origine (react, ng1, ng2...) | |
dom dans le dom | |
Observables RxJs | |
Performances | |
- COMPONENTS | |
arbre de composants | |
(plus haut : smart component : high-level : logique Business | |
plus bas : dumb component : low-level : design : echange données via ses inputs/outputs avec les parents) | |
communication entre composants | |
http://courses.wishtack.com/angular-2/components | |
see : /Two-Way Data Binding | |
[propInput] : ex : <div [hidden]="name.length > 0" [disabled]=".." | |
[value]="stringInterpol" <-> value="{{stringInterpol}}" | |
(eventOutput) : <button (click)="doIt($event)" ... | |
[(2waysBinding)] : [(name)]="name" | |
_ TEMPLATES | |
Projection (Transclusion) | |
override layout template feeding block content | |
factorisation des composants | |
possible de définir plusieurs zones de projection (Block Content) | |
<ng-content select=".wt-title"></ng-content> | |
<ng-content select=".wt-content"></ng-content> | |
<ng-content select=".wt-actions"></ng-content> | |
Css encapsulation (ViewEncapsulation) | |
.Emulated : les styles du composant ne s'appliquent qu'au composant lui-même. | |
.None (déconseillé) : Les styles du composant sont appliqués sur toute la page. | |
.Native : Les styles appliqués à la page HTML n'affectent pas le composant et les styles du composant ne sont appliqués | |
qu'au composant. Celà s'effectue grâce au "Shadow DOM". | |
Change Detection | |
Avec Angular 2, la "change detection" traverse les composants de façon arborescente en commençant par le "root component". | |
Phase 1 : Chaque évènement (click, network, timer, etc...) déclenche notre code puis la "change detection". | |
Phase 2 : A chaque cycle de "change detection", chacun des composants est vérifié une seule fois. | |
liste des stratégies disponibles : | |
- Default | |
- OnPush | |
La stratégie "Default" déclenche la "change detection" après chaque évènement (click, network, timer, etc...). | |
La stratégie "OnPush" ne déclenche la "change detection" que si les "inputs" du composant changent. | |
Si un composant est "OnPush" ou s'il a désactivé la "change detection", la "change detection" des "child components" sera désactivé également. | |
ex: tree | |
_ DIRECTIVES, PIPES | |
customized directives | |
pipes | |
{{ now | date:'medium' }} avec : now : Date = new Date(); | |
{{ user.firstName | slice:0:10 | lowercase }} | |
{{ observable | async }} avec : this.observable = Observable.interval(1000); | |
Contrairement à AngularJS, par optimisation, Angular 2 ne déclenchera le "pipe" que si la valeur ou les paramètres changent. | |
_ ROUTER | |
protected routes, guards | |
children routes | |
_ FORMS | |
Template-driven | |
<form #userForm="ngForm"></form> | |
Pour récupérer l'état de validité du formulaire, il faut récupérer une référence de l'instance de la directive `NgForm` | |
Data-driven (with Form Builder) | |
_ OBSERVABLES, PROMISES, HTTP, SERVICES | |
avec RxJs (pas encore dans ES6, Typescript) serait dans ES7 été 2017 | |
Promises dans ES6 mais pas de methode Finally, interrompue dès la premiere erreur (non relancable, annulable, lazy) | |
Promise vs Observable vs EventListener (1 shot) | |
immediate vs lazy : le subscribe est obligatoire | |
1 meme value vs 1 flux de données cancelable | |
appelée 1 fois vs stream : declenché à chaque fois | |
ex Observables : http, outputs de composants, EventEmitter, Controls de formulaire | |
Une centaine d'operateurs pour controler le flux de données | |
Operateur .cache() | |
.toPromise() .all() / .race() avec bluebird | |
ex : UserSchema / User / UserStoreService | |
API Restful | |
getsandbox.com | |
editor.swagger.io | |
jsonapi.org | |
the following are all identical for a promise or plain value X: | |
Promise.resolve(x); | |
new Promise(function(resolve, reject){ resolve(x); }); | |
Promise.resolve().then(function(){ return x; }); | |
Promise.all([x]).then(function(arr){ return arr[0]; }); | |
_ TESTS | |
DI : providers in module with useClass: MyMockService | |
_ PERFS, OPTIMISATIONS | |
universal rendering (server-side) | |
tree shaking (aot) : baisse taille initialisation | |
lazy-loading des routes | |
webworkers | |
STACK | |
ANGULAR-CLI | |
ng new app --prefix ijb | |
ng g c compo --flat -is -it (inner style, inner template : no suppl files) | |
ng g d unless --directory 02-directives --prefix dir | |
BEST PRACTICES | |
- injecter les services au niveau Module (et non component) | |
pouvoir mocker/initialiser avec : | |
providers : [ { provide : UserStore, useFactory : () => new UserStore(1,2) }] | |
providers : [ { provide : UserStore, useClass : FakeUserStore }] | |
- utiliser l'immutabilité car obj comparés par ref (cloner les objets {}) | |
- Pensez à désinscrire le composant des "observables", "events", arrêtez les timers etc... | |
dans "ngDestroy" pour éviter les fuites mémoire. | |
GUIDELINES | |
- https://angular.io/styleguide | |
Class NomClassEnCamelCase | |
file file-name-en-kebab-case.ts | |
prop _privateProp | |
interface IUser | |
SemVer : "Major(BreakingVersion).Minor(Feature).Patch(Bug/Secu)" | |
"4.17.2" better than "^4.17.2" (ie : >= 4.17.x) | |
+ mettre à jour avec npm-check-updates (NCU) | |
*********** | |
Tests : | |
_ Code Coverage avec WebStorm | |
_ | |
*********** | |
GENERATORS | |
- https://github.com/mcfly-io/generator-mcfly-ng2 | |
- https://github.com/AngularClass/angular2-webpack-starter / run build docker | |
IDE | |
- VSCODE https://github.com/ultrasonicsoft/vscode-ng2-typescript-snippets | |
- https://github.com/johnpapa/vscode-angular2-snippets | |
IONIC2 | |
- http://ionicframework.com/getting-started/ | |
- UI creator and Ionic-cli | |
- https://rangle.io/resources/intro-ionic-2/ | |
SERIES | |
- https://julienrenaux.fr/2015/12/13/angular2-series-component-directive-pipe-and-service/ | |
- https://rangle.io/resources/ | |
TRAINING | |
- https://github.com/wishtack/wt-training-angular2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="container body-container"> | |
<span style="font-size:32px;font-weight: bold;font-style: italic">{{title}} </span> | |
<br> | |
<span style="float:left"> | |
<a class="item" routerLink="/" routerLinkActive="active">Home</a> | |
| | |
<a class="item" routerLink="/dropdown" routerLinkActive="active">Dropdown</a> | |
| | |
<a class="item" routerLink="/date" routerLinkActive="active">Date</a> | |
| | |
<a class="item" routerLink="/tab" routerLinkActive="active">Tab</a> | |
| | |
<a class="item" routerLink="/upload" routerLinkActive="active">Upload</a> | |
| | |
<a class="item" routerLink="/wizard" routerLinkActive="active">Wizard</a> | |
</span> | |
<span style="float:right"> | |
<span *ngIf="isLoggedIn()">{{ usernameFromEmitter}} </span> | |
<span *ngIf="isLoggedIn()"> | <a [routerLink]="['/login']">Logout</a></span> | |
</span> | |
<!--<app-menu></app-menu>--> | |
<br> <br> | |
<div class="col-lg-12"> | |
<!-- Routed views go here --> | |
<router-outlet></router-outlet> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Component, EventEmitter} from "@angular/core"; | |
import {AuthenticationService} from "./login/authentication.service"; | |
@Component({ | |
selector: 'app-root', | |
templateUrl: './app.component.html', | |
styleUrls: ['./app.component.css'] | |
}) | |
export class AppComponent { | |
title = '< orilab >'; | |
usernameFromEmitter: string; | |
//_authenticationService; | |
// userLoggedInAtInit: EventEmitter<any>; | |
constructor(private _authenticationService: AuthenticationService) { | |
/// PubSub 1 : onLogin | |
// this._authenticationService = authenticationService; | |
this._authenticationService.userLoggedInFromService.subscribe(username => this.onUserLoggedIn2(username)); | |
/// PubSub 2 : onReload | |
// this.userLoggedInAtInit = new EventEmitter(); | |
// this.userLoggedInAtInit.subscribe(username => this.onUserLoggedIn2(username)); | |
} | |
ngOnInit() { | |
this._authenticationService | |
.getOUserFromDB(this._authenticationService.isLoggedIn()) | |
.flatMap((username) => { | |
return this._authenticationService.getOUser(username) | |
}) | |
.subscribe( currentUser => { | |
console.log('currentUserOnInit') | |
// this.userLoggedInAtInit.emit((currentUser && currentUser.username)?currentUser.username:'no user'); | |
} ) | |
} | |
onUserLoggedIn2(username): void { | |
this.usernameFromEmitter = username; | |
} | |
isLoggedIn(){ | |
return this._authenticationService.isLoggedIn(); | |
} | |
ngOnChanges() { | |
// this.childUsername = "Username has changed" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Injectable, EventEmitter} from '@angular/core'; | |
import {Http, Response} from "@angular/http"; | |
import {Observable} from "rxjs"; | |
@Injectable() | |
export class AuthenticationService { | |
token: string; | |
currentUser; | |
/// Event Emitter | |
public userLoggedInFromService: EventEmitter<any>; | |
private usernameConnected; | |
constructor(private http: Http) { | |
/// Event Emitter | |
this.userLoggedInFromService = new EventEmitter(true); | |
this.currentUser = JSON.parse(localStorage.getItem('currentUser')); | |
this.token = this.currentUser && this.currentUser.token; | |
} | |
login(username, password):Observable<boolean>{ | |
return this.http.post('/api/authenticate', JSON.stringify({username: username, password:password})). | |
map( (resp: Response) => { | |
let token = resp.json() && resp.json().token; | |
if (token) { | |
this.token = token; | |
localStorage.setItem('currentUser', JSON.stringify({id: '26', username: username, token:token})); | |
return true; | |
} else { | |
return false; | |
} | |
}); | |
} | |
//// merge these 2 functions | |
getOUserFromDB(connected):Observable<string> { | |
let user_id = (JSON.parse(localStorage.getItem('currentUser')) && JSON.parse(localStorage.getItem('currentUser')).id) | |
? JSON.parse(localStorage.getItem('currentUser')).id: ''; | |
let username = (JSON.parse(localStorage.getItem('currentUser')) && JSON.parse(localStorage.getItem('currentUser')).username ) | |
? JSON.parse(localStorage.getItem('currentUser')).username: ''; | |
return Observable.of('UsernameFromDB'+user_id+username) | |
// return this.http.get('api/userconnected').map((resp: Response) => { | |
// let username = resp.json().username; | |
// if (connected && username) { | |
// | |
// console.log('username = '+username) | |
// this.userLoggedInFromService.emit(username); | |
// return Observable.of(true); | |
// | |
// } else { | |
// return Observable.of(false) | |
// } | |
// }) | |
// .catch((error:any) => Observable.throw(error.json().error || 'Server error')); | |
} | |
getOUser(username):Observable<boolean>{ | |
if (username) { | |
this.userLoggedInFromService.emit(username); | |
return Observable.of(true); | |
} | |
else | |
return Observable.of(false) | |
} | |
getUser(){ | |
return this.currentUser; | |
} | |
getPUser(){ | |
return Observable.of(JSON.parse(localStorage.getItem('currentUser'))); | |
} | |
logout(){ | |
this.token = null; | |
localStorage.removeItem('currentUser'); | |
} | |
isLoggedIn(){ | |
return (this.token !== null); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let promise = new Promise((resolve, reject) => { | |
$.get('/', (response) => { | |
if (response.status === 200) { | |
resolve(response.data); | |
} | |
else { | |
reject(new Error(response.status)); | |
} | |
}); | |
}); | |
promise | |
.then(data => { | |
... | |
/* Returns a promise. */ | |
return $.get('/users/USER_ID'); | |
}) | |
.then(user => { | |
if (user.name == null) { | |
/* Throws an error... */ | |
throw new Error('anonymous user'); | |
} | |
/* or returns a value. */ | |
return user.name; | |
}) | |
.then(name => { | |
console.log(name); | |
}) | |
.catch(error => { | |
console.error(error); // anonymous user. | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Component, OnInit, EventEmitter, Output} from "@angular/core"; | |
import {AuthenticationService} from "./authentication.service"; | |
import {Router} from "@angular/router"; | |
import {Observable} from "rxjs"; | |
@Component({ | |
selector: 'app-login', | |
templateUrl: './login.component.html', | |
styleUrls: ['./login.component.css'] | |
}) | |
export class LoginComponent implements OnInit { | |
private error: string = ''; | |
private loading: boolean = false; | |
private model: any = {}; | |
constructor(private authenticationService: AuthenticationService, | |
private router: Router) { | |
} | |
ngOnInit() { | |
this.authenticationService.logout(); | |
} | |
login() { | |
this.loading = true; | |
this.authenticationService.login(this.model.username, this.model.password) | |
// .delay(500) | |
.flatMap((connected) => { | |
return this.authenticationService.getOUserFromDB(connected) | |
}) | |
.flatMap((username) => { | |
return this.authenticationService.getOUser(username) | |
}) | |
.subscribe( | |
result => { | |
if (result) { | |
this.router.navigate(['/home']); | |
} else { | |
this.error = "Username or password is incorrect."; | |
this.loading = false; | |
} | |
}, | |
error => { | |
console.log(error.text()); | |
}, | |
() => { | |
this.loading = false; | |
} | |
) | |
} | |
signup(event) { | |
event.preventDefault(); | |
this.router.navigate(['signup']); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment