How to Write Better Code in Angular
Optimize template expressions
Binary expressions
Function calls
Method calls
Primary expressions
@Component ( {
// ...
template : `
<div>
{{longMethod()}}
</div>
`
} )
export class App {
longMethod ( ) {
// takes 3 mins to exec
return 67
}
}
Finish quickly
Use web workers
Cache the template expressions
Use pipe
Shareable/Reusable Angular components
Container and compositional components
Divide components into Smart and Dumb
Keep components as Dumb as possible
Decide when a component should be Smart instead of Dumb
@Component ( {
...
template : `
<div>
<h3>My List</h3>
<div class="alert alert-danger" *ngIf="logged == true">You are not allowed here</div>
...
<div class="panel">
<div class="panel-header">{{name == 'undefined' ? "John Doe" : name}}</div>
...
</div>
</div>
`
} )
export class App {
logged : boolean = false
name : string = null
//...
}
@Component ( {
...
template : `
<div>
<h3>My List</h3>
<div class="alert alert-danger" *ngIf="logged">You are not allowed here</div>
...
<div class="panel">
<div class="panel-header">{{name}}</div>
...
</div>
</div>
`
} )
export class App {
logged : boolean = false
name : string = "John Doe"
//...
}
Unsubscribe in ngOnDestroy
@Component ( {
// ...
template : `
<div *ngFor="let list of lists">
//...
</div>
`
} )
export class App implements OnInit {
private listObservable : Observable
ngOnInit ( ) {
listObservable = this . listService . getAllLists ( ) . subscribe ( res => this . lists = res )
}
}
@Component ( {
// ...
template : `
<div *ngFor="let list of lists">
//...
</div>
`
} )
export class App implements OnDestroy , OnInit {
private listObservable : Observable
ngOnInit ( ) {
listObservable = this . listService . getAllLists ( ) . subscribe ( res => this . lists = res )
}
ngOnDestroy ( ) {
this . listObservable . unsubscribe ( )
}
}
Use trackBy
function for *ngFor
@Component ( {
// ...
template : `
<div *ngFor="let movie of movies">
...
</div>
`
} )
export class App {
private movies : Movies [ ]
constructor ( ) {
this . movies = [
{
id : 0 ,
name : 'nnamdi'
} ,
{
id : 1 ,
name : 'feynman'
} ,
// ... 1000 items
]
}
}
this . movies = this . movies . concat ( [
{
id : Date . now ( ) ,
name
}
] )
@Component ( {
// ...
template : `
<div *ngFor="let movie of movies; trackBy: trackByFn">
...
</div>
`
} )
export class App {
private movies : Movies [ ]
constructor ( ) {
this . movies = [
{
id : 0 ,
name : 'nnamdi'
} ,
{
id : 1 ,
name : 'feynman'
} ,
// ... 1000 items
]
}
trackByFn ( inde , item ) {
return item . id
}
}
@Component ( {
template : `
{{dataFromTemplate | myPipe}}
`
} )
{
name : string ,
pure : boolean
}
use async pipe in template
@Component ( {
// ...
template :`
<div>
{{movies}}
</div>
`
} )
export class App implements OnInit {
private movies : Movies [ ]
constructor ( private store : Store ) { }
ngOnInit ( ) {
this . store . select ( state => state . movies ) . subscribe ( data = this . movies = data )
}
}
@Component ( {
// ...
template :`
<div>
{{movies$ | async}}
</div>
`
} )
export class App implements OnInit {
private movies$ : Observable < Movies [ ] >
constructor ( private store : Store < Movies [ ] > ) { }
ngOnInit ( ) {
this . movies$ = this . store . select ( state => state . movies )
}
}
XMLHttpRequest
DOM events like mouse movements, click events
setTimeout, setInterval, clearInterval, setImmediate etc
Detach component from component tree
@Component ( {
// ...
template : `
<div>
{{data}}
</div>
`
} )
export class Comp {
private data
constructor ( private dataService : DataService ) { }
getData ( ) {
this . data = this . dataService . loadData ( )
}
}
@Component ( {
// ...
template : `
<div>
{{data}}
</div>
`
} )
export class Comp {
private data
constructor ( private dataService : DataService , private changeDetectorRef : ChangeDetectorRef ) {
this . changeDetectorRef . detach ( )
setInterval ( ( ) => {
this . changeDetectorRef . detectChanges ( )
} , 5000 )
}
getData ( ) {
this . data = this . dataService . loadData ( )
}
}
constructor ( private ngZone : NgZone ) { }
this . ngZone . runOutsideAngular ( ( ) => {
// run outside Angular zone
setTimeout ( ( ) => {
this . ngZone . run ( ( ) => {
// run inside ngZone
} )
} , 5000 )
} )
ChangeDetectionStrategy.OnPush
@Component ( {
// ...
template : `
<div *ngFor="let movie of movies">
...
</div>
`
} )
export class MoviesList {
@Input ( ) movies
}
@Component ( {
// ...
template : `
<div *ngFor="let movie of movies">
...
</div>
` ,
changeDetection : ChangeDetectionStrategy . OnPush
} )
export class MoviesList {
@Input ( ) movies
}