npm i -S @ngrx-utils/store
# or
yarn add @ngrx-utils/store
This directive will give you ability to add a class to the element when router url match a regular expression. The syntax is same with ngClass
but replace the true/false expression with your string based regexp (like the string you pass to new RegExp('')
).
Example: active-class
will be added to a
tag when router URL contains this segment: products/12345
<a routerLink="/products"
[routerLinkMatch]="{
"active-class": "products/\\d+"
}"></a>
This is a modified version of async pipe in @angular/common package. All the code implement are almost the same but this push pipe will call detectChanges()
instead of markForCheck()
so your pipe continue to work even in {ngZone: 'noop'}
environment.
// main.ts
platformBrowserDynamic()
.bootstrapModule(AppModule, { ngZone: 'noop' })
.catch(err => console.log(err));
// app.module.ts
import { PushPipeModule } from '@ngrx-utils/store';
@NgModule({
imports: [PushPipeModule]
})
export class AppModule {}
// heavy-compute.component.ts
import { Component, OnInit, NgZone } from '@angular/core';
@Component({
template: `<h2>Test: {{ test$ | push }}</h2>`
})
export class HeavyComputeComponent implements OnInit {
compute() {
//...heavy computing
}
ngOnInit() {
this.compute();
}
}
We often use *ngIf="stream$ | async as stream"
to subscribe to an observable property and rename it to a template variable. But with nested template, *ngIf
might remove your template which may not be expected.
import { NgLetModule } from '@ngrx-utils/store';
@NgModule({
imports: [NgLetModule]
})
export class FeatureModule {}
Replace *ngIf
with *ngLet
:
<ng-container *ngLet="(filterDate$ | async) as filterDate">
<pick-date [registeredAt]="(device$ | async)?.registeredAt"
[firstDate]="filterDate?.from"
[secondDate]="filterDate?.to"></pick-date>
</ng-container>
*ngLet
just hold a reference to the result of async
pipe in a template variable and don't have any special logic like structure directives such as *ngIf
or *ngFor
so it run faster and very handy.
You can also subscribe to multiple observable separately with *ngLet
like this:
<ng-container *ngLet="{
device: device$ | async,
date: filterDate$ | async
} as options">
<pick-date [registeredAt]="options.device?.registeredAt"
[firstDate]="options.date?.from"
[secondDate]="options.date?.to"></pick-date>
</ng-container>
Actually this is an feature request in angular for quite long time as described in here but not yet been accepted.
Have you ever feel odd when have to repeat calling unsubscribe with subscriptions in ngOnDestroy
, or creating a Subject property, add takeUntil() to subscription, call next()
in ngOnDestroy?
With untilDestroy pipeable operator:
import { untilDestroy } from '@ngrx-utils/store';
export class MyComponent implements OnDestroy {
user: User;
constructor(userService: UserService) {
userService
.getUsers()
/** Automatically unsubscribe on destroy */
.pipe(untilDestroy(this))
.subscribe(user => (this.user = user));
}
/** Must have */
ngOnDestroy() {}
}
NOTE: You still have to declare
ngOnDestroy
in Component because Angular does not support dynamically add component method in AOT mode
Credit to @SanderElias, this operator is inspired from his idea but he's currently not publishing it as an npm package.
This is just a wrapper function of rxjs/operators/pluck
but has a nice type checking with plucked properties.
import { pluck } from '@ngrx-utils/store';
someObservable
/** Type check here */
.pipe(pluck('matches'));
Shorter store.select and store.dispatch and you don't have to inject store in to your component anymore.
-
@Select
accepts first parameter as a selector type(state: any) => any
to select prop from your store (like selectors created withcreateSelector
from@ngrx/store
) and follows up to 8 pipeable operators. You can use operators liketake(1)
to automatically unsubscribe, or transform that value by usingmap
and reduce selectors for nested properties in store... -
@Pluck
accepts a list of state property name start from root state. It also supports a 'dot' separated shorthand syntax or use component property name when no argument is specified. Inspired from ngrx-actions by @amcdnl. -
@Dispatch
mark your method return result as an action to dispatch from store. You can also return an array of actions if you want to dispatch multi actions in 1 method.
// app.module.ts
import { NgrxSelectModule } from '@ngrx-utils/store';
@NgModule({
// Include `NgrxSelectModule` to your app.module.ts (Only add this to your AppModule):
imports: [, /* ... */ NgrxSelectModule]
})
export class AppModule {}
// my.component.ts
import { take, map } from 'rxjs/operators';
import { Select, Pluck, Dispatch } from '@ngrx-utils/store';
@Component({
template: ``
})
export class MyComponent {
@Select(fromRoot.getRouterState, map(state => state.url), take(1))
url$: Observable<string>;
@Pluck('featureState', 'prop1')
prop1: Observable<any>;
@Pluck('featureState.prop2') prop2: Observable<any>;
@Pluck() featureState: Observable<any>;
@Dispatch()
onLayoutChanged($event) {
return new SetLayout($event);
}
@Dispatch()
onMultiAction() {
return [new SetLanguage(), new Navigate('/home')];
}
}
This feature DO come with a trade-off: it lacks of type checking for your component properties due to Typescript issue #4881.
So please keep it in your mind when using @Select
or @Pluck
. @Dispatch
is safe to use though. Hopefully Typescript team will fix that issue in the near future.
NOTE: You can NOT use this
keyword inside @Select()
to call component's methods because this
using in @Select()
is not your component instance.
You can using Select, Pluck, Dispatch
decorator in any component. It also works with lazy load module too. You only need to import NgrxSelectModule once to your AppModule and in TestBed.configureTestingModule
when running tests.
- Fork this repo
- Add your awesome feature and include it in the top level export
- Run
git add . && yarn cz
to automatic generate Angular style commit - Send a PR here and describe some use cases.
@ngrx-utils/store
- Introduce Pluck decorator for string select
- Select decorator support pipeable operator
- Strong typed pluck operator
- untilDestroy operator
- ngLet directive
- routerLinkMatch directive
@ngrx-utils/schematics
- ngrx-utils schematics for union Action type and Enum.
@ngrx-utils/effects, @ngrx-utils/cli - No longer been developed.