Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ngrx/effects

Package Overview
Dependencies
Maintainers
3
Versions
144
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ngrx/effects - npm Package Compare versions

Comparing version 1.1.1 to 2.0.0-beta.1

actions.d.ts

7

effects.d.ts

@@ -1,5 +0,4 @@

import 'rxjs/add/observable/merge';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
export declare function mergeEffects(...instances: any[]): Observable<any>;
export declare function connectEffectsToStore(store: Store<any>, effects: any[]): () => Promise<boolean>;
export declare function Effect(): PropertyDecorator;
export declare function getEffectKeys(instance: any): string[];
export declare function mergeEffects(instance: any): Observable<any>;
"use strict";
require('rxjs/add/observable/merge');
var Observable_1 = require('rxjs/Observable');
var metadata_1 = require('./metadata');
var util_1 = require('./util');
function mergeEffects() {
var instances = [];
for (var _i = 0; _i < arguments.length; _i++) {
instances[_i - 0] = arguments[_i];
var merge_1 = require('rxjs/observable/merge');
var METADATA_KEY = '@ngrx/effects';
function Effect() {
return function (target, propertyName) {
if (!Reflect.hasOwnMetadata(METADATA_KEY, target)) {
Reflect.defineMetadata(METADATA_KEY, [], target);
}
var effects = Reflect.getOwnMetadata(METADATA_KEY, target);
Reflect.defineMetadata(METADATA_KEY, effects.concat([propertyName]), target);
};
}
exports.Effect = Effect;
function getEffectKeys(instance) {
var target = Object.getPrototypeOf(instance);
if (!Reflect.hasOwnMetadata(METADATA_KEY, target)) {
return [];
}
var observables = util_1.flatten(instances).map(function (i) { return metadata_1.getEffectKeys(i).map(function (key) {
if (typeof i[key] === 'function') {
return i[key]();
return Reflect.getOwnMetadata(METADATA_KEY, target);
}
exports.getEffectKeys = getEffectKeys;
function mergeEffects(instance) {
var observables = getEffectKeys(instance).map(function (key) {
if (typeof instance[key] === 'function') {
return instance[key]();
}
return i[key];
}); });
return Observable_1.Observable.merge.apply(Observable_1.Observable, util_1.flatten(observables));
return instance[key];
});
return merge_1.merge.apply(void 0, observables);
}
exports.mergeEffects = mergeEffects;
function connectEffectsToStore(store, effects) {
return function () {
mergeEffects.apply(void 0, effects).subscribe(store);
return Promise.resolve(true);
};
}
exports.connectEffectsToStore = connectEffectsToStore;

@@ -1,5 +0,3 @@

export { Effect } from './metadata';
export { mergeEffects } from './effects';
export { runEffects } from './ng2';
export { StateUpdate, StateUpdates } from './state-updates';
export { toPayload, all } from './util';
export { Effect, mergeEffects } from './effects';
export { Actions } from './actions';
export { EffectsModule } from './module';
"use strict";
var metadata_1 = require('./metadata');
exports.Effect = metadata_1.Effect;
var effects_1 = require('./effects');
exports.Effect = effects_1.Effect;
exports.mergeEffects = effects_1.mergeEffects;
var ng2_1 = require('./ng2');
exports.runEffects = ng2_1.runEffects;
var state_updates_1 = require('./state-updates');
exports.StateUpdates = state_updates_1.StateUpdates;
var util_1 = require('./util');
exports.toPayload = util_1.toPayload;
exports.all = util_1.all;
var actions_1 = require('./actions');
exports.Actions = actions_1.Actions;
var module_1 = require('./module');
exports.EffectsModule = module_1.EffectsModule;
{
"name": "@ngrx/effects",
"version": "1.1.1",
"version": "2.0.0-beta.1",
"description": "Side effect model for @ngrx/store",

@@ -16,19 +16,16 @@ "main": "index.js",

"typings": "typings install",
"clean": "npm-run-all clean:*",
"clean:release": "rm -rf ./release",
"clean:typings": "rm -rf ./typings",
"prebuild": "npm-run-all clean typings karma",
"build": "npm-run-all build:cjs build:es6",
"build:cjs": "tsc --p tsconfig.es5.json --diagnostics --pretty",
"build:es6": "tsc -m es2015 --outDir ./release/esm --target ES6 -d --diagnostics --pretty",
"prepare": "npm-run-all prepare:*",
"prepare:es6": "cp -R ./release/esm ./release/npm",
"prepare:package": "cp ./{package.json,README.md,LICENSE} ./release/npm",
"clean": "rimraf ./release",
"prebuild": "npm-run-all clean karma",
"build": "npm-run-all build:*",
"build:cjs": "ngc",
"build:esm": "ngc -p tsconfig.es2015.json",
"build:ts": "cpy src/*.ts release/src",
"prepare": "cpy ./{package.json,README.md,CHANGELOG.md,LICENSE} ./release",
"test": "npm-run-all clean typings karma",
"karma": "karma start --single-run",
"karma:watch": "karma start",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
"postbuild": "npm run prepare",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"preversion": "npm run test",
"version": "npm run changelog && git add CHANGELOG.md"
"version": "npm run changelog && git add CHANGELOG.md",
"postversion": "npm run prepare"
},

@@ -41,3 +38,3 @@ "authors": [

"rxjs": "5.0.0-beta.6",
"@angular/core": "^2.0.0-rc.1",
"@angular/core": "^2.0.0-rc.5",
"@ngrx/store": "^2.0.0"

@@ -48,6 +45,9 @@ },

"@angular/compiler": "^2.0.0-rc.1",
"@angular/compiler-cli": "^0.5.0",
"@angular/core": "^2.0.0-rc.1",
"@angular/platform-browser": "^2.0.0-rc.1",
"@angular/platform-browser-dynamic": "^2.0.0-rc.1",
"@angular/platform-server": "^2.0.0-rc.5",
"@ngrx/core": "^1.0.0",
"@types/jasmine": "^2.2.31",
"conventional-changelog-cli": "^1.1.1",

@@ -71,4 +71,3 @@ "core-js": "^2.2.2",

"tslint": "^3.6.0",
"typescript": "^1.8.9",
"typings": "^0.7.12",
"typescript": "^2.0.0",
"webpack": "^1.12.14",

@@ -75,0 +74,0 @@ "zone.js": "^0.6.8"

@@ -15,26 +15,34 @@ # @ngrx/effects

## Effects
In @ngrx/effects, effects are _sources of actions_. You use the `@Effect()` decorator to hint which observables on a service are action sources, and @ngrx/effects automatically connects your action sources to your store
In @ngrx/effects, effects are _sources of actions_. You use the `@Effect()` decorator to hint which observables on a service are action sources, and @ngrx/effects automatically merges your action streams letting you subscribe them to store.
To help you compose new action sources, @ngrx/effects exports a `StateUpdates` observable service that emits a `StateUpdate` object, containing the current state and dispatched action, for each state update.
To help you compose new action sources, @ngrx/effects exports an `Actions` observable service that emits every action dispatched in your application.
__*Note: Even if there are no changes in your state, every action will cause state to update!*__
### Example
1. Create an AuthEffects service that describes a source of login actions:
```ts
import { Injectable } from '@angular/core';
import { Injectable, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Action } from '@ngrx/store';
import { StateUpdates, Effect } from '@ngrx/effects'
import { Subscription } from 'rxjs/Subscription';
import { Action, Store } from '@ngrx/store';
import { Actions, Effect, mergeEffects } from '@ngrx/effects';
@Injectable()
export class AuthEffects {
constructor(private http: Http, private updates$: StateUpdates<any>) { }
export class AuthEffects implements OnDestroy {
subscription: Subscription;
@Effect() login$ = this.updates$
constructor(
private http: Http,
private actions$: Actions,
private store: Store<State>
) {
// Merge all effects and subscribe them to the store
this.subscription = mergeEffects(this).subscribe(store);
}
@Effect() login$ = this.actions$
// Listen for the 'LOGIN' action
.whenAction('LOGIN')
.ofType('LOGIN')
// Map the payload into JSON to use as the request body
.map(update => JSON.stringify(update.action.payload))
.map(action => JSON.stringify(action.payload))
.switchMap(payload => this.http.post('/auth', payload)

@@ -46,165 +54,25 @@ // If successful, dispatch success action with result

);
// You MUST implement an ngOnDestroy method for your effects to
// automatically start. Use ngOnDestroy to cleanup running effects.
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
```
2. Run your effects during application bootstrap:
2. Provide your service in your component's providers array or in an `NgModule` providers array to automatically start your effects:
```ts
import { runEffects } from '@ngrx/effects';
import { AuthEffects } from './effects/auth';
bootstrap(App, [
provideStore(reducer),
runEffects(AuthEffects)
]);
```
@NgModule({
providers: [ AuthEffects ]
})
export class AppModule { }
```
### Dynamically Running Effects
The `@Effect()` decorator provides metadata to hint which observables on a class should be connected to `Store`. If you want to dynamically run an effect inject the effect class and subscribe the effect to `Store` manually:
```ts
@Injectable()
export class AuthEffects {
@Effect() login$ = this.updates$
.whenAction('LOGIN')
.mergeMap(...)
}
@Component({
providers: [
AuthEffects
]
})
export class SomeCmp {
subscription: Subscription;
constructor(store: Store<State>, authEffects: AuthEffects) {
this.subscription = authEffects.login$.subscribe(store);
}
}
```
Unsubscribe to stop the effect:
```ts
ngOnDestroy() {
this.subscription.unsubscribe();
}
```
#### Starting Multiple Effects
If you don't want to connect each source manually, you can use the `mergeEffects()` helper function to automatically merge all decorated effects across any number of effect services:
```ts
import { OpaqueToken, Inject } from '@angular/core';
import { mergeEffects } from '@ngrx/effects';
const EFFECTS = new OpaqueToken('Effects');
@Component({
providers: [
provide(EFFECTS, { multi: true, useClass: AuthEffects }),
provide(EFFECTS, { multi: true, useClass: AccountEffects }),
provide(EFFECTS, { multi: true, useClass: UserEffects })
]
})
export class SomeCmp {
constructor(@Inject(EFFECTS) effects: any[], store: Store<State>) {
mergeEffects(effects).subscribe(store);
}
}
```
### Testing Effects
To test your effects mock out your effect's dependencies and use the `MockStateUpdates` service to send actions and state changes to your effect:
```ts
import {
MOCK_EFFECTS_PROVIDERS,
MockStateUpdates
} from '@ngrx/effects/testing';
describe('Auth Effects', function() {
let auth: AuthEffects;
let updates$: MockStateUpdates;
beforeEach(function() {
const injector = ReflectiveInjector.resolveAndCreate([
AuthEffects,
MOCK_EFFECTS_PROVIDERS,
// Mock out other dependencies (like Http) here
]);
auth = injector.get(AuthEffects);
updates$ = injector.get(MockStateUpdates);
});
it('should respond in a certain way', function() {
// Add an action in the updates queue
updates$.sendAction({ type: 'LOGIN', payload: { ... } });
auth.login$.subscribe(function(action) {
/* assert here */
});
});
});
```
You can use `MockStateUpdates@sendAction(action)` to send an action with an empty state, `MockStateUpdates@sendState(state)` to send a state change with an empty action, and `MockStateUpdates@send(state, action)` to send both a state change and an action. Note that `MockStateUpdates` is a replay subject with an infinite buffer size letting you queue up multiple actions / state changes to be sent to your effect.
### Migrating from store-saga
@ngrx/effects is heavily inspired by store-saga making it easy to translate sagas into effects.
#### Rewriting Sagas
In store-saga, an `iterable$` observable containing state/action pairs was provided to your saga factory function. Typically you would use the `filter` operator and the `whenAction` helper to listen for specific actions to occur. In @ngrx/effects, an observable named `StateUpdates` offers similar functionality and can be injected into an effect class. To listen to specific actions, @ngrx/effects includes a special `whenAction` operator on the `StateUpdates` observable.
Before:
```ts
// ... other needed imports here ...
import { createSaga, whenAction, toPayload } from 'store-saga';
const login$ = createSaga(function(http: Http) {
return iterable$ => iterable$
.filter(whenAction('LOGIN'))
.map(iteration => JSON.stringify(iteration.action.payload))
.mergeMap(body => http.post('/auth', body)
.map(res => ({
type: 'LOGIN_SUCCESS',
payload: res.json()
}))
.catch(err => Observable.of({
type: 'LOGIN_ERROR',
payload: err.json()
}))
);
}, [ Http ]);
```
After:
```ts
// ... other needed imports here ...
import { Effect, toPayload, StateUpdates } from '@ngrx/effects';
@Injectable()
export class AuthEffects {
constructor(private http: Http, private updates$: StateUpdates<State>) { }
@Effect() login$ = this.updates$
.whenAction('LOGIN')
.map(update => JSON.stringify(update.action.payload))
.mergeMap(body => this.http.post('/auth', body)
.map(res => ({
type: 'LOGIN_SUCCESS',
payload: res.json()
}))
.catch(err => Observable.of({
type: 'LOGIN_ERROR',
payload: err.json()
}))
);
}
```
WIP
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc