Skip to content

Commit

Permalink
fix: Add support for Angular 6 and RxJS 6
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
NgRx now has a minimum version requirement on Angular 6 and RxJS 6.
  • Loading branch information
sandangel authored and MikeRyanDev committed Mar 30, 2018
1 parent 1352d83 commit d1286d2
Show file tree
Hide file tree
Showing 91 changed files with 2,712 additions and 2,793 deletions.
206 changes: 106 additions & 100 deletions MIGRATION.md

Large diffs are not rendered by default.

54 changes: 24 additions & 30 deletions docs/effects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ RxJS powered side effect model for @ngrx/store

@ngrx/effects provides an API to model event sources as actions. Effects:

- Listen for actions dispatched from @ngrx/store
- Isolate side effects from components, allowing for more _pure_ components that select state and dispatch actions
- Provide [new sources](https://martinfowler.com/eaaDev/EventSourcing.html) of actions to reduce state based on external interactions such as network requests, web socket messages and time-based events.
* Listen for actions dispatched from @ngrx/store
* Isolate side effects from components, allowing for more _pure_ components that select state and dispatch actions
* Provide [new sources](https://martinfowler.com/eaaDev/EventSourcing.html) of actions to reduce state based on external interactions such as network requests, web socket messages and time-based events.

### Installation

Install @ngrx/effects from npm:

`npm install @ngrx/effects --save` OR `yarn add @ngrx/effects`


### Nightly builds

`npm install github:ngrx/effects-builds` OR `yarn add github:ngrx/effects-builds`
Expand All @@ -28,27 +28,28 @@ The `@Effect()` decorator provides metadata to register observable side-effects

### Actions Observable

- Represents an observable of all actions dispatched to the store.
- Emits the latest action _after_ the action has passed through all reducers.
- The `ofType` operator lets you filter for actions of a certain type in which you want to use to perform a side effect.
* Represents an observable of all actions dispatched to the store.
* Emits the latest action _after_ the action has passed through all reducers.
* The `ofType` operator lets you filter for actions of a certain type in which you want to use to perform a side effect.

## Example
1. Create an AuthEffects service that describes a source of login actions:

1. Create an AuthEffects service that describes a source of login actions:

```ts
// ./effects/auth.effects.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Action } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { Observable, of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';

@Injectable()
export class AuthEffects {
// Listen for the 'LOGIN' action
@Effect() login$: Observable<Action> = this.actions$.pipe(
@Effect()
login$: Observable<Action> = this.actions$.pipe(
ofType('LOGIN'),
mergeMap(action =>
this.http.post('/auth', action.payload).pipe(
Expand All @@ -59,26 +60,20 @@ export class AuthEffects {
)
)
);


constructor(
private http: HttpClient,
private actions$: Actions
) {}
constructor(private http: HttpClient, private actions$: Actions) {}
}
```

2. Register the EffectsModule in your application root imports. This EffectsModule *must* be added to
your root `NgModule` for the effects providers to be registered and start when your application is loaded.
2. Register the EffectsModule in your application root imports. This EffectsModule _must_ be added to
your root `NgModule` for the effects providers to be registered and start when your application is loaded.

```ts
import { EffectsModule } from '@ngrx/effects';
import { AuthEffects } from './effects/auth.effects';

@NgModule({
imports: [
EffectsModule.forRoot([AuthEffects])
]
imports: [EffectsModule.forRoot([AuthEffects])],
})
export class AppModule {}
```
Expand All @@ -92,17 +87,16 @@ import { EffectsModule } from '@ngrx/effects';
import { AdminEffects } from './effects/admin.effects';

@NgModule({
imports: [
EffectsModule.forFeature([AdminEffects])
]
imports: [EffectsModule.forFeature([AdminEffects])],
})
export class AdminModule {}
```

## API Documentation
- [Controlling Effects](./api.md#controlling-effects)
- [Filtering Actions](./api.md#oftype)
- [Non-dispatching effects](./api.md#non-dispatching-effects)
- [Initializing effect](./api.md#initializing-effect)
- [Utilities](./api.md#utilities)
- [Testing](./testing.md)

* [Controlling Effects](./api.md#controlling-effects)
* [Filtering Actions](./api.md#oftype)
* [Non-dispatching effects](./api.md#non-dispatching-effects)
* [Initializing effect](./api.md#initializing-effect)
* [Utilities](./api.md#utilities)
* [Testing](./testing.md)
85 changes: 51 additions & 34 deletions docs/effects/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,29 @@
NgModule for @ngrx/effects.

### forRoot

Registers internal @ngrx/effects services to run in your application. This is required once in your root NgModule.

Usage:

```ts
@NgModule({
imports: [
EffectsModule.forRoot([
FirstEffectsClass,
SecondEffectsClass,
])
]
imports: [EffectsModule.forRoot([FirstEffectsClass, SecondEffectsClass])],
})
export class AppModule { }
export class AppModule {}
```

### forFeature

Registers @ngrx/effects services to run with your feature modules.

**Note**: Running an effects class multiple times, either by `forRoot()` or `forFeature()`, (for example via different lazy loaded modules) will not cause Effects to run multiple times. There is no functional difference between effects loaded by `forRoot()` and `forFeature()`; the important difference between the functions is that `forRoot()` sets up the providers required for effects.

Usage:

```ts
@NgModule({
imports: [
EffectsModule.forFeature([
SomeEffectsClass,
AnotherEffectsClass,
])
]
imports: [EffectsModule.forFeature([SomeEffectsClass, AnotherEffectsClass])],
})
export class FeatureModule {}
```
Expand All @@ -43,6 +37,7 @@ export class FeatureModule {}
Stream of all actions dispatched in your application including actions dispatched by effect streams.

Usage:

```ts
import { Injectable } from '@angular/core';
import { Actions } from '@ngrx/effects';
Expand All @@ -58,6 +53,7 @@ export class SomeEffectsClass {
Filter actions by action types. Specify the action type to allow type-safe mapping to other data on the action, including payload.

Usage:

```ts
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
Expand All @@ -67,68 +63,76 @@ import { tap } from 'rxjs/operators';
export class SomeEffectsClass {
constructor(private actions$: Actions) {}

@Effect() authActions$ = this.actions$.pipe(
@Effect()
authActions$ = this.actions$.pipe(
ofType<LoginAction | LogoutAction>('LOGIN', 'LOGOUT'),
tap(action => console.log(action))
);
}
```

### Non-dispatching Effects

Pass `{ dispatch: false }` to the decorator to prevent dispatching.

Usage:

```ts
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { tap } from 'rxjs/operators';

@Injectable()
export class SomeEffectsClass {
constructor(private actions$: Actions) { }
constructor(private actions$: Actions) {}

@Effect({ dispatch: false }) logActions$ = this.actions$.pipe(
tap(action => console.log(action))
);
@Effect({ dispatch: false })
logActions$ = this.actions$.pipe(tap(action => console.log(action)));
}
```

### Initializing effect

You can execute some code that will be executed directly after the effect class is loaded.

```ts
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { defer } from 'rxjs/observable/defer';
import { defer } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class SomeEffectsClass {
constructor(private actions$: Actions) { }
constructor(private actions$: Actions) {}

@Effect({ dispatch: false }) init$: Observable<any> = defer(() => of(null)).pipe(
tap(() => console.log('init$')),
@Effect({ dispatch: false })
init$: Observable<any> = defer(() => of(null)).pipe(
tap(() => console.log('init$'))
);
}
```

If you want to trigger another action, be careful to add this effect at the end.

```ts
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { defer } from 'rxjs/observable/defer';
import { defer } from 'rxjs';
import { LoginAction, LogoutAction } from './auth';

@Injectable()
export class SomeEffectsClass {
constructor(private actions$: Actions) { }
constructor(private actions$: Actions) {}

@Effect({ dispatch: false }) authActions$ = this.actions$.pipe(
@Effect({ dispatch: false })
authActions$ = this.actions$.pipe(
ofType<LoginAction | LogoutAction>('LOGIN', 'LOGOUT'),
tap(action => console.log(action))
);
tap(action => console.log(action))
);

// Should be your last effect
@Effect() init$: Observable<action> = defer(() => {
@Effect()
init$: Observable<action> = defer(() => {
return of(new LogoutAction());
});
}
Expand All @@ -137,21 +141,30 @@ export class SomeEffectsClass {
## Controlling Effects

### OnRunEffects

By default, effects are merged and subscribed to the store. Implement the `OnRunEffects` interface to control the lifecycle of the resolved effects.

Usage:

```ts
import { Injectable } from '@angular/core';
import { Actions, Effect, OnRunEffects, EffectNotification, ofType } from '@ngrx/effects';
import {
Actions,
Effect,
OnRunEffects,
EffectNotification,
ofType,
} from '@ngrx/effects';
import { Action } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { Observable } from 'rxjs';
import { exhaustMap, takeUntil, tap } from 'rxjs/operators';

@Injectable()
export class UserEffects implements OnRunEffects {
constructor(private actions$: Actions) {}

@Effect() updateUser$: Observable<Action> = this.actions$.pipe(
@Effect()
updateUser$: Observable<Action> = this.actions$.pipe(
ofType('UPDATE_USER'),
tap(action => {
console.log(action);
Expand All @@ -161,9 +174,11 @@ export class UserEffects implements OnRunEffects {
ngrxOnRunEffects(resolvedEffects$: Observable<EffectNotification>) {
return this.actions$.pipe(
ofType('LOGGED_IN'),
exhaustMap(() => resolvedEffects$.pipe(
takeUntil(this.actions$.pipe(ofType('LOGGED_OUT')))
))
exhaustMap(() =>
resolvedEffects$.pipe(
takeUntil(this.actions$.pipe(ofType('LOGGED_OUT')))
)
)
);
}
}
Expand All @@ -172,9 +187,11 @@ export class UserEffects implements OnRunEffects {
## Utilities

### mergeEffects

Manually merges all decorated effects into a combined observable.

Usage:

```ts
import { mergeEffects } from '@ngrx/effects';

Expand Down
6 changes: 5 additions & 1 deletion docs/effects/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
## @ngrx/effects/testing

### provideMockActions

Provides a mock test provider of the `Actions` Observable for testing effects. This works well with writing
marble tests and tests using the `subscribe` method on an Observable. The mock Actions will deliver a new Observable to subscribe to for each test.

Details on marble tests and their syntax, as shown in the `hot` and `cold` methods, can be found in [Writing Marble Tests](https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md).

Usage:

```ts
import { TestBed } from '@angular/core/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { hot, cold } from 'jasmine-marbles';
import { Observable } from 'rxjs/Observable';
import { Observable } from 'rxjs';

import { MyEffects } from './my-effects';
import * as MyActions from '../actions/my-actions';
Expand Down Expand Up @@ -62,10 +64,12 @@ describe('My Effects', () => {
```

### getEffectsMetadata

Returns decorator configuration for all effects in a class instance.
Use this function to ensure that effects have been properly decorated.

Usage:

```ts
import { TestBed } from '@angular/core/testing';
import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
Expand Down
Loading

0 comments on commit d1286d2

Please sign in to comment.