Skip to content

Instantly share code, notes, and snippets.

@Y2017
Last active December 11, 2016 22:04
Show Gist options
  • Save Y2017/dc9b495cad4a77482c9924621018853a to your computer and use it in GitHub Desktop.
Save Y2017/dc9b495cad4a77482c9924621018853a to your computer and use it in GitHub Desktop.
Username in header
***********
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
<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>
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"
}
}
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);
}
}
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.
});
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