Tips & tricks for tricky but useful things in angular 2. The type of problems that are too small to deserve a full blog post, and that you do not know how to name to search for.
Elvis operator and bracket notation
Bracket notation is javascript is an alternative to dot notation to display the content of an object. The main advantage is has is that you can use variable inside the bracket to display a property whose name depends of a variable.
Elvis operator is a syntax for angular 2 that allow telling angular renderer to ignore template binding of sub-properties for object that does not exist yet. Indeed, it is generally that the object is not yet loaded from the backend.
From this
The Elvis operator is only available for the . notation, not for other operators like []. As a workaround use
//OLD Way
import {ElementRef} from '@angular/core';
@ViewChild('someVar') el:ElementRef;
ngAfterViewInit()
{
this.el.nativeElement.focus();
}
New API with renderer....
//NEW Way
import {ElementRef} from '@angular/core';
@ViewChild('someVar') el:ElementRef;
constructor(private rd: Renderer) {}
ngAfterViewInit() {
this.rd.invokeElementMethod(this.el.nativeElement,'focus');
}
Prevent error when module are failing to be imported
Module handling in JS is a headache. Sometimes it just don't works. But you still need to use a js lib the old way (with a script in the index.html).
You can fool typescript to allow you to use the missing library (that will exist at run time).
declare var braintree:any;
Object property binding & async pipe with bracket syntax
Yes but how to use a bracket syntax with async syntax.
I have an observable that I want to pass to a component. Once passed I want a sub property that is static in that case : the first item of an array. Or may be dynamic, a component property.
The problem is that : (imagesFB | async)[0] would fail because the item does not exist at first and the async is for imagesFB not for the resulting array that (imagesFB | async) return.
So with a ternary syntax :
(bolean) ? /* code if true */ : /* code if false */ ;`
There are 3 keywords that can be used in a class. To defined a property or method
public to get the method available from other classes
private to get it only usable inside the class
static allow to use a class without instantiating it
Instantiate a class, is creating a local copy of it. For example if we are in a component, that mean that we are using an instance of a class.
An instance is creating by passing it to the component constructor like this.
import { UploadService } from '../../../services/api/upload.service'
export class UiUploadUploadcareComponent {
constructor(
private uploadService: UploadService,
){
}
upload() {
// we use the instance of the class with this
this.uploadService.upload()
}
But by using static we do not need, and we cannot actually create a local instance
import { StaticService } from '../../../services/static.service'
export class UiUploadUploadcareComponent {
constructor(
// we do not need to instanciate the class
){
}
upload() {
// we use the static method useStaticClass
// of StaticService class without the this keyword
StaticService.useStaticClass()
}
Simplify module definition with the spread operator
Redirect to the same path changing only the last path parameter
The trick is to use relative path syntax of angular 2 router
// change orderId only while we are at order/22 for example
// but keeping all parameters
this.router.navigate(['../', this.order._id], { queryParams: this.params, relativeTo: this.route });
// For this path (defined in routing configuration)
{ path: 'order/:orderId', component: SROrderPage },
watching queryparams and params changes
queryparams are optional ?step=2&lang=fr so step and lang
params are in the path /project/:projectId so project Id in that cas
For both we use the Activated route service, so we place in our constructor
Execute a js library outside of the scope of angular
Angular run inside an execution context so is not accessible in the global scope of the page. But some libraries like jQuery exist in the global scope of the page.
div(
*ngFor="let item of item; let last = last; let odd = odd; let even = even; let index = index;",
[ngClass]="{'odd': odd,'even': even,'last': last}",
class="item item-{{ index }}")
will result in
<div class="item odd item-1">
First item
</div>
<div class="item even item-2">
Second item
</div>
<div class="item odd last item-2">
Third item
</div>
Dynamic templates
Injection parent component in child component
@ContentChildren() allow to have a reference to a child component in the parent component
@Host() allow to have a reference to a parent component in the child component