diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a638849..98f89a1a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,7 +33,7 @@ jobs: # fallback to using the latest cache if no exact match is found - v1-dependencies- - - run: yarn install + - run: yarn install --frozen-lockfile - save_cache: paths: diff --git a/.gitignore b/.gitignore index 5e19eb54..d4f0a933 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ lerna-debug.log yarn-debug.log yarn-error.log .vscode +.node-version diff --git a/.yarnrc b/.yarnrc index 01fd7100..1333f4e0 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1 +1 @@ ---add.exact true \ No newline at end of file +--add.exact true diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..1c4d7b05 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,804 @@ +# 9.0.0 + +## Breaking Changes + +- Updates to Redux 4 typedefs. +- Updates to RxJs 6 import paths. +- Updates to Angular 6. + +# 7.1.1 + +## Bug Fixes + +- #508 (thanks to @ratoaq2) +- #463 (thanks to @draccoz) + +# 7.1.0 + +## Features + +- Add a way to return a false value from a method decorated with `@dispatch` to allow conditionally preventing a dispatch. [PR#497](https://github.com/angular-redux/store/pull/497) + +```ts +@dispatch() +selectTab(tab) { + return this.active.id !== tab.id ? { type: .... } : false; +} +``` + +- Add a way to access the decorated instance inside of transformer for `@select$` [PR#500](https://github.com/angular-redux/store/pull/500) + +```ts +@Input() public anotherInput: string; + +@select$(['selector'], (obs$, inst) => obs$.filter(x => x.name === inst.anotherInput)) +public selectedObs: Observable; +``` + +Shout out to contributors: + +- [@rart](https://github.com/rart) +- [@MaKCbIMKo](https://github.com/MaKCbIMKo) + +# 7.0.2 - Fixing Publish + +- There are no functional changes / fixes in this release. + +There was accidental publish to the `@latest` tag with an experimental fix for the v6 branch that got pushed out with the incorrect tag. + +For some clarity: + +- v7+ - currently only works with Angular 5+ +- v6+ - works with Angular 4 and earlier, and v5. +- v8 - this was an accidental version bump - and that package is now deprecated. + +# Which Version to use? + +## Angular 5+ + +Use `@angular-redux/store@^7` - this version supports Angular 5, and also changes to using lettable operators. + +Any new major releases will released on the v7 branch and with the `@latest` tag for final publishes. + +## Angular 4 or lower + +Use `@angular-redux/store@^6` - This supports Angular 4 and earlier. + +# Support for `@angular-redux/store@6`? + +Where possible, I will be maintaining and applying any fixes / enhancements for v7 into v6 where it does not introduce a breaking change. + +I made a few mistakes trying to publish fixes / etc to two major versions, which caused some releases to get tagged incorrectly and caused some confusion. Sorry for any confusion this has caused, and will do better on avoiding this in the future, and being more transparent with the releases that are going out. + +# 6.6.0 - Angular 5 Support + +- Add Angular 5+ as peer dependency + +# 7.0.0 - Angular 5 Upgrade + +- Update dependencies to Angular 5 +- Update RxJS to 5.5.2 and use lettable operators +- Update peer dependencies to only Angular 5+ + +note: This version requires Angular 5, the code generated by the compiler is not compatible with Angular v4. + +# 6.6.0-1 + +- Update peer dependency to include Angular 5, _note_ - this is a beta release, if you run into any issues with Angular 5 please let me know. This release is still using an older version of angular to build / compile, but seems to work with Angular 5. + +Working on a V7 release that upgrades to be built/use Angular 5 core/compiler/etc which produces builds that are not backwards compatable with Angular 4. More details will be available soon. + +# 6.5.7 + +- Fixed issue with AppRef.tick being called recurisvly [#443](https://github.com/angular-redux/store/pull/443) + +# 6.5.6 + +- Turn tsconfig checks to 11. +- Minor code cleanup - no feature changes. + +# 6.5.5 + +- Update toolchain to typescript 2.4. +- Fix for https://github.com/angular-redux/store/issues/434. + +# 6.5.4 + +- Fix for https://github.com/angular-redux/store/issues/427: memory leaks introduced in 6.3.0. + +** You'll want to grab this update! ** + +# 6.5.3 + +- Handle `@WithSubStore`, `.configureSubStore` boundary cases for when the base path + doesn't exist in the store yet. + +# 6.5.2 + +- Docgen updates. + +# 6.5.1 + +- Allow `@WithSubStore`'s base path to be dynamic. + +# 6.5.0 + +- Enabled fractal store features for the decorator interface. See + https://github.com/angular-redux/store/blob/master/articles/fractal-store.md for details. + +# 6.4.5 + +- Fix a boundary condition where `MockNgRedux` could get instantiated + twice under certain conditions. +- Adjust exposed interfaces of `MockNgRedux` and `NgRedux` to make them + structurally compatible (both assignable to the `NgRedux` type) (issue #419) +- Update to TypeScript 2.3.4 + +# 6.4.4 + +- Improve packaging of `testing` submodule for people working in strict mode (thanks @ialibhay)! + +# 6.4.3 + +- Reset `MockNgRedux.mockInstance` as part of `MockNgRedux.reset()`. + +# 6.4.2 + +- Fixed some issues with MockNgRedux and the select dectorators. See https://github.com/angular-redux/store/issues/413 for details. + +# 6.4.1 + +- Fixed a memory leak with `@select`, `@select$`. See https://github.com/angular-redux/example-app/issues/34 for details. + +# 6.4.0 + +## Features + +- Added 'fractal store' support. + +You can now create an encapsulated 'sub-store' that only operates on a section of the global Redux store: + +```typescript +const subStore = ngRedux.configureSubStore( + ['path', 'to', 'somewhere'], + localReducer, +); +``` + +Substore has the same interface as `NgRedux`: `select`, `dispatch` etc; +however when these functions are called on a substore instance, they +are scoped to the data under `path.to.somewhere`. + +See [the docs](https://github.com/angular-redux/store/blob/master/articles/fractal-store.md) for more info. + +# 6.3.0 + +## Fixes + +- Fixed issues with middlewares that allow dispatching of things other than just raw actions + (e.g. redux-thunk) [#386, #264]. +- Fixed issues with enhancers that change the way `Store.subscribe` and listeners work (e.g. redux-batch) [#372] + +## Features + +- Added the `@select$` decorator which allows you to attach observable operator chains + directly to `@select`. For example: + +```typescript +import { select$ } from 'angular-redux/store'; + +export const debounceAndTriple = obs$ => obs$.debounce(300).map(x => 3 * x); + +class Foo { + @select$(['foo', 'bar'], debounceAndTriple) + readonly debouncedFooBar$: Observable; +} +``` + +- Added the `@dispatch` decorator which allows auto-dispatch for your action creators. + For example: + +```typescript +import { Injectable } from '@angular/core'; +import { Action } from 'redux'; + +@Injectable() +export class AnimalActions { + static readonly LOAD_ANIMALS = 'LOAD_ANIMALS'; + + // Calling loadAnimals will now automagically dispatch the action. + @dispatch() + loadAnimals = (animalType: AnimalType): Action => ({ + type: AnimalActions.LOAD_ANIMALS, + meta: { animalType }, + }); + + // ... +} +``` + +# 6.2.2 + +- Reset `MockNgRedux.mockInstance` as part of `MockNgRedux.reset()`. + +# 6.2.1 + +## Fixes + +Issue #370 + +## Misc. + +- More code cleanup +- Auto-generated API documentation. + +# 6.2.0 - NgReduxTestingModule + +## Features + +- Added `NgReduxTestingModule`, `MockNgRedux` to help unit test components and + services that select from the store. See [here](https://github.com/angular-redux/store/blob/master/articles/intro-tutorial.md#unit-testing-selections) + for details. +- Expose `PathSelector`, `FunctionSelector`, and `PropertySelector` types in `index.d.ts`. + +## Misc. + +- Simplified build toolchain +- Simplified unit testing toolchain +- Consolidated repo-specific examples in to the [example-app](https://github.com/angular-redux/example-app) repo. + +# 6.1.0 - Angular 4 Support + +Both version 2 and 4 of Angular are now supported. However Angular 2 support +is deprecated and will be removed in the next major version. + +# 6.0.1 + +Documentation updates; no code change. Added a 'getting started' tutorial. + +# 6.0.0 - The big-rename. + +Due to the impending release of Angular4, the name 'ng2-redux' no longer makes +a ton of sense. The Angular folks have moved to a model where all versions are +just called 'Angular', and we should match that. + +After discussion with the other maintainers, we decided that since we have to +rename things anyway, this is a good opportunity to collect ng2-redux and its +related libraries into a set of scoped packages. This will allow us to grow +the feature set in a coherent but decoupled way. + +As of v6, the following packages are deprecated: + +- ng2-redux +- ng2-redux-router +- ng2-redux-form + +Those packages will still be available on npm for as long as they are being used. + +However we have published the same code under a new package naming scheme: + +- @angular-redux/store (formerly ng2-redux) +- @angular-redux/router (formerly ng2-redux-router) +- @angular-redux/form (formerly ng2-redux-form). + +We have also decided that it's easier to reason about things if these packages +align at least on major versions. So everything has at this point been bumped +to 6.0.0. + +# Breaking changes + +Apart from the rename, the following API changes are noted: + +- @angular-redux/store: none. +- @angular-redux/router: none. +- @angular-redux/form: `NgReduxForms` renamed to `NgReduxFormModule` for consistency. + +# 5.1.1 + +# 4.2.4 + +# 3.3.10 + +### Fixes + +Applied fix addressing #309 - select function called even if state does not change. + +# 5.1.0 + +### Features + +You can now get an observable to the root state by passing no arguments to +`ngRedux.select`: + +```typescript +private this.rootState$: Observable; + +constructor(ngRedux: NgRedux) { + this.rootState$ = ngRedux.select(); +} +``` + +### Changes + +`ngRedux.dispatch()` has been tweaked to always run in the Angular zone. This +should prevent unexpected weirdness when dispatching from callbacks to 3rd-party +libraries. See #259 for further discussion. + +### Misc. + +- Refactored the example app a bit to split out the different selector demos instead + of lumping most of them into the counter component. +- Miscellaneous documentation updates. + +# 5.0.0 + +- Fix for the `ERROR in NgReduxModule is not an NgModule` error thrown by Angular CLI. +- Remove deprecations. +- Breaking changes associated with Angular 2.4+. + +### Breaking Changes + +- Minimum Angular peer dependency is now 2.4.0 +- Removed support for the `connect` pattern: it's simply not a good fit for Angular. + You should be using the `select` pattern now. +- Remove deprecated constructor arg for `NgRedux`. +- Minimum Angular peer dependency is now 2.4.0 +- `NgReduxModule.forRoot` is no more. Now just import `NgReduxModule` directly. + +#### Old Way: + +```typescript +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { NgReduxModule } from 'ng2-redux'; + +@NgModule({ + declarations: [AppComponent], + imports: [NgReduxModule.forRoot(), BrowserModule], + providers: [], + bootstrap: [AppComponent], +}) +class AppModule { + // etc. +} +``` + +#### New Way: + +```typescript +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { NgReduxModule } from 'ng2-redux'; + +@NgModule({ + declarations: [AppComponent], + imports: [NgReduxModule, BrowserModule], + providers: [], + bootstrap: [AppComponent], +}) +class AppModule { + // etc. +} +``` + +# 4.2.4 + +Recovery release that restores the functionality of 4.2.2. Use this release +if you're on Angular < 2.2. If your on Angular >= 2.3, you'll need to use +ng2-redux@5.0.0-beta.0 (see v5.x branch for the changelog) to consume the +fix for #282 (due to a breaking change in Angular). + +# 4.2.1, 4.2.3 + +Botched releases - don't use. Apologies; I've added a `prepublish` script to `npm` +to prevent this from happening again. + +# 4.2.1 + +### Fixes: + +- #281 (DevToolsExtension missing from providers list) + +# 4.2.0 + +### Fixes: + +- #221 (type error with redux-thunk) + +# 4.1.0 + +### Fixes: + +- #228 ('generic' error with AoT) +- #251 (No provider for DevToolsExtension) + +# 4.0.0 + +### Features + +- Better support for Angular CLI +- NgModule interface changes to better support Angular 2's ahead-of-time compiler (AoT) + +### Fixes + +- Update build to use ngc - metadata.json is now produced +- Introduced NgReduxModule +- Fix AoT related bugs #247, #235, #228 + +### Breaking Change: Using NgReduxModule + +```js +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { AppComponent } from './app.component'; +import { NgReduxModule, NgRedux } from 'ng2-redux'; +import { IAppState } from './appstate'; +import { rootReducer } from './store'; + +@NgModule({ + declarations: [AppComponent], + imports: [NgReduxModule, BrowserModule], + providers: [], + bootstrap: [AppComponent], +}) +export class AppModule { + constructor(ngRedux: NgRedux) { + ngRedux.configureStore(rootReducer, {}); + } +} +``` + +**before** + +```js +import { select } from 'ng2-redux'; +export class MyComponent { + @select() thing$: Observable; +} +``` + +**after** + +```js +import { NgRedux } from 'ng2-redux'; +export class MyComponent { + thing$: Observable; + constructor(private ngRedux:NgRedux) { + + } + ngOnInit() { + this.thing$ = this.ngRedux.select (n => n.thing); + } +} +``` + +# 3.3.9 + +### Fixes + +- Temp update to npm build to uninstall typings for chai/sinon-chai so `/// ` doesn't get added to files. + +# 3.3.8 + +### Fixes + +- Manual fix of build to remove chai type reference + +# 3.3.7 + +### Features + +- Improved error if trying to dispatch before store is configured - #118, #198 + +### Fixes + +- Relax Zone JS version - #189, #187 +- Fix DevTools being out of sync for actions dispatched from tool, #192 + +### Chores/Misc + +- Upgrade to TypeScript 2 - #189, #190 +- Add Code Coverage - #193, #206, #207 + +# 3.3.5 + +### Fixes + +- Update redux peer dependency to 3.5.0 + - observable shim which we depend on was introduced in 3.5.0, not 3.4.0 + +# 3.3.4 + +### Chore + +- Update to RC5 (#184, fixes #183) +- Include src in npm package (#182, fixes #180) + +### Fixes + +- Fix window in Universal (#185, fixes #172) + +# 3.3.3 + +### Fixes + +- Fix window is undefined in Universal (#178, fixes #172) + +# 3.3.2 + +### Fixes + +- Change seamless immutable integration to not need conditional require (#169) + +# 3.3.1 + +### Fixes + +- Argument to DevTools enhancer is now optional (#164) +- Decorator deletes key on target, not `this`. (#168, fixes #166) + +# 3.3.0 + +### Features + +- [DevToolsExtension - convience wrapper for dev tools](https://github.com/angular-redux/store/blob/master/articles/redux-dev-tools.md) (#115) +- [Select - seamless support for ImmutableJS](https://github.com/angular-redux/store/blob/master/articles/immutable-js.md) (#160) + +### Fixes + +- Able to use `@select` in services +- Behavior of `select` with chained dispatches, (fixes #149, #153) + +# 3.2.0 + +### Features + +- Added a `provideStore()` function which lets you pass in a already created + store. It can be used as this: + +Create your store: + +```typescript +// store.ts + +import { + applyMiddleware, + Store, + combineReducers, + compose, + createStore, +} from 'redux'; +import thunk from 'redux-thunk'; +import reduxLogger from 'redux-logger'; + +import { myReducer } from './reducers/my-reducer'; + +const rootReducer = combineReducers({ + myReducer, +}); + +export const store = createStore( + rootReducer, + compose(applyMiddleware(thunk, reduxLogger)), +) as Store; +``` + +Create your App and call `provideStore` with your newly created store: + +```typescript +// app.ts + +import { NgRedux } from 'ng2-redux'; +import { store } from './store.ts'; + +interface IAppState { + // ... +} +@Component({ + // ... etc. +}) +class App { + constructor(private ngRedux: NgRedux) { + this.ngRedux.provideStore(store); + } + + // ... +} +``` + +# 3.1.0 + +### Features + +- Added a 'path' option to `ngRedux.select()` and `@select()`. Now you can + do stuff like `@select(['foo', 'bar'])` to select `state.foo.bar` into + an observable. + +- Add ability to provide custom comparer to @select decorator to keep consistent with ngRedux.select + +```js +import { is } from 'immutablejs'; + +export class SomeComponent { + @select((n = n.some.selector), is) + someSelector$: Observable; +} +``` + +### Features + +# 3.0.8 + +### Fix + +- AppliicationRef is optional dependency, fixes#127 + +# 3.0.0 + +### Features + +#### Select Decorator + +This release introduces the new decorator interface. You can now use +`@select` to create an observable from a slice of store state. + +See 'the select pattern' in [README.md](README.md#the-select-pattern) +for a complete description of how to use this new decorator. + +#### Simpler Redux DevTools Integration + +You no longer need to manually subscribe and `ApplicationRef.tick()` +for Redux DevTools to work; we do this automatically for you. + +### Breaking Changes + +#### Bootstrapping + +We've changed how bootstrapping `ng2-redux` works. The `provider` +function has gone away in favour of making NgRedux a first-class +`@Injectable`. + +You now configure your store in the constructor of your top-level +app component instead of prior to bootstrapping. This allows the +store to be configured with middleware and enhancers that rely on +Angular 2 services, which previously was unnecessarily difficult. + +##### Old way: + +**bootstrap.ts:** + +```typescript +import { bootstrap } from '@angular/platform-browser-dynamic'; +import { createStore, applyMiddleware, compose } from 'redux'; +import { NgRedux } from 'ng2-redux'; +const createLogger = require('redux-logger'); +const persistState = require('redux-localstorage'); +import { rootReducer } from './reducers'; +import { App } from './app'; + +// Confusing and hard to use with dependency injection. +const middleware = [createLogger()]; +const enhancers = [persistState('counter', { key: 'example-app' })]; +const store = compose( + applyMiddleware(middleware), + ...enhancers, +)(createStore)(rootReducer); + +bootstrap(App, [provide(store)]); +``` + +**app.ts** + +```typescript +import { Component } from '@angular/core'; +import { NgRedux } from 'ng2-redux'; + +@Component({ + // ... +}) +export class App { + constructor(private ngRedux: NgRedux) {} +} +``` + +##### New way: + +**bootstrap.ts:** + +```typescript +import { bootstrap } from '@angular/platform-browser-dynamic'; +import { NgRedux } from 'ng2-redux'; +import { App } from './app'; + +bootstrap(App, [Ng2Redux]); +``` + +**app.ts** + +```typescript +import { Component } from '@angular/core'; +import { NgRedux } from 'ng2-redux'; +import { reduxLogger } from 'redux-logger'; +import { initialState, rootReducer } from './reducers'; + +@Component({ + // ... +}) +export class App { + constructor(private ngRedux: NgRedux) { + const middleware = [reduxLogger]; + const enhancers = [persistState('counter', { key: 'example-app' })]; + + // Easier to understand, and can use middleware or enhancers from DI. + ngRedux.configureStore(rootReducer, initialState, middleware, enhancers); + } +} +``` + +#### Example App Updates + +The example app has been updated to use `@select` and a +DI-aware action creator service (`counter-actions.ts`). It now also +shows examples of using middleware and enhancers from the Redux +community: `redux-logger` and `redux-localstorage`. + +# 2.2.2 + +### Features + +- **Type definitions**: + - Ported to typescript + - Supports typed stores / reducers + - Uses offical Redux type definitions +- **Type Injectable**: + - Able to inject `NgRedux` into your component by type, and not need `@Inject('ngRedux')` + - `@Inject('ngRedux')` still works + +```typescript +import { NgRedux } from 'ng2-redux'; +// ... +export class MyComponent { + constructor(private ngRedux: NgRedux) {} +} +``` + +- **State as Observable**: Ability to expose parts of your state as an observable. + +```typescript +select(selector: string | number | symbol | ((state: RootState) => S), comparer?: (x: any, y: any) => boolean): Observable; + wrapActionCreators: (actions: any) => (dispatch: Redux.Dispatch) => Redux.ActionCreator<{}> | Redux.ActionCreatorsMapObject; +``` + +Example use: + +```typescript +import { NgRedux } from 'ng2-redux'; +// ... +export class MyComponent implements OnInit { + countByKey$: Observable; + countByFunc$: Observable; + + constructor(private ngRedux: NgRedux) { + this.countByKey$ = this.ngRedux.select('count'); + this.countByFunc$ = this.ngRedux.select(state => state.count); + } +} +``` + +Also have the ability to provide a custom compare function. + +```typescript +import { is, Map } from 'immutable'; +import { NgRedux } from 'ng2-redux'; + +// ... +export class MyComponent implements OnInit { + person$: Observable>; + + constructor(private ngRedux: ngRedux) { + // even if the reference of the object has changed, + // if the data is the same - it wont be treated as a change + this.person$ = this.ngRedux.select(state => state.people.get(0), is); + } +} +``` diff --git a/packages/form/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md similarity index 100% rename from packages/form/ISSUE_TEMPLATE.md rename to ISSUE_TEMPLATE.md diff --git a/README.md b/README.md index 735cc03c..dec00a3a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# @angular-redux +# Angular Redux [![CircleCI](https://circleci.com/gh/angular-redux/platform/tree/master.svg?style=svg)](https://circleci.com/gh/angular-redux/platform/tree/master) @@ -12,4 +12,4 @@ ## Examples -- [Example Application](packages/example-app) +- [Example Application](https://github.com/angular-redux/platform/blob/master/packages/example-app) diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..526abf18 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,13 @@ +[![CircleCI](https://circleci.com/gh/angular-redux/platform/tree/master.svg?style=svg)](https://circleci.com/gh/angular-redux/platform/tree/master) + +[Redux](https://redux.js.org/) bindings for [Angular](https://angular.io/) applications. + +# Packages + +- [@angular-redux/store](store/) - Bindings between Redux and Angular +- [@angular-redux/form](form/) - Bindings between Angular Forms and your Redux state +- [@angular-redux/router](router/) - Bindings between Angular Router and your Redux state + +# Examples + +- [Example Application](https://github.com/angular-redux/platform/blob/master/packages/example-app) diff --git a/docs/_navbar.md b/docs/_navbar.md new file mode 100644 index 00000000..fbf35a4d --- /dev/null +++ b/docs/_navbar.md @@ -0,0 +1,5 @@ +- [Store](store/) +- [Form](form/) +- [Router](router/) +- [Changelog](changelog) +- [Contributing](contributing) diff --git a/docs/form/README.md b/docs/form/README.md new file mode 100644 index 00000000..5281738a --- /dev/null +++ b/docs/form/README.md @@ -0,0 +1,299 @@ +[![npm version](https://img.shields.io/npm/v/@angular-redux/form.svg)](https://www.npmjs.com/package/@angular-redux/form) +[![downloads per month](https://img.shields.io/npm/dm/@angular-redux/form.svg)](https://www.npmjs.com/package/@angular-redux/form) + +This library is a thin layer of connective tissue between Angular 2+ forms and +Redux. It provides unidirectional data binding between your Redux state and +your forms elements. It builds on existing Angular functionality like +[NgModel](https://angular.io/docs/ts/latest/api/forms/index/NgModel-directive.html) +and +[NgControl](https://angular.io/docs/ts/latest/api/forms/index/NgControl-class.html) + +This supports both [Template driven forms](https://angular.io/guide/forms) and [Reactive driven forms](https://angular.io/guide/reactive-forms). + +# Template Driven + +For the simplest use-cases, the API is very straightforward. Your template +would look something like this: + +```html +
+ +
+``` + +The important bit to note here is the `[connect]` directive. This is the only thing +you should have to add to your form template in order to bind it to your Redux state. +The argument provided to `connect` is basically a path to form state inside of your +overall app state. So for example if my Redux app state looks like this: + +```json +{ + "foo": "bar", + "myForm": { + "address": "1 Foo St." + } +} +``` + +Then I would supply `myForm` as the argument to `[connect]`. If myForm were nested +deeper inside of the app state, you could do something like this: + +```html +
...
+``` + +Note that ImmutableJS integration is provided seamlessly. If `personalInfo` is an +immutable Map structure, the library will automatically use `get()` or `getIn()` to +find the appropriate bits of state. + +Then, in your application bootstrap code, you need to add a provider for +the class that is responsible for connecting your forms to your Redux state. +There are two ways of doing this: either using an `Redux.Store` object or +an `NgRedux` object. There are no substantial differences between these +approaches, but if you are already using +[@angular-redux/store](https://github.com/angular-redux/platform/blob/master/packages/store) or you wish to integrate +it into your project, then you would do something like this: + +```typescript +import { NgReduxModule } from '@angular-redux/store'; +import { NgReduxFormModule } from '@angular-redux/form'; + +@NgModule({ + imports: [ + BrowserModule, + ReactiveFormsModule, + FormsModule, + NgReduxFormModule, + NgReduxModule, + ], + bootstrap: [MyApplicationComponent], +}) +export class ExampleModule {} +``` + +Or if you are using Redux without `@angular-redux/store`, then your bootstrap call would look +more like this (substitute your own store creation code): + +```typescript +import { provideReduxForms } from '@angular-redux/form'; + +const storeCreator = compose(applyMiddleware(logger))(createStore); +const store = create(reducers, {}); + +@NgModule({ + imports: [BrowserModule, ReactiveFormsModule, FormsModule, NgReduxFormModule], + providers: [provideReduxForms(store)], + bootstrap: [MyApplicationComponent], +}) +export class ExampleModule {} +``` + +The essential bit of code in the above samples is the call to `provideReduxForms(...)`. +This configures `@angular-redux/form` and provides access to your Redux store or NgRedux +instance. The shape of the object that `provideReduxForms` expects is very +basic: + +```typescript +export interface AbstractStore { + /// Dispatch an action + dispatch(action: Action & { payload? }): void; + + /// Retrieve the current application state + getState(): RootState; + + /// Subscribe to changes in the store + subscribe(fn: () => void): Redux.Unsubscribe; +} +``` + +Both `NgRedux` and `Redux.Store` conform to this shape. If you have a more +complicated use-case that is not covered here, you could even create your own store +shim as long as it conforms to the shape of `AbstractStore`. + +# How the bindings work + +The bindings work by inspecting the shape of your form and then binding to a Redux +state object that has the same shape. The important element is `NgControl::path`. +Each control in an Angular 2 form has a computed property called `path` which uses +a very basic algorithm, ascending the tree from the leaf (control) to the root +(the `
` element) and returning an array containing the name of each group or +array in the path. So for example, let us take a look at this form that lets the +user provide their full name and the names and types of their children: + +```html + + + +
+``` + +Our root `
` element has a `connect` directive that points to the state element +`form1`. This means that the children within your form will all be bound to some +bit of state inside of the `form1` object in your Redux state. Then we have a child +input which is bound to a property called `fullname`. This is a basic text box. If +you were to inspect it in the debugger, it would have a `path` value like this: + +``` +['form1', 'fullname'] +``` + +And therefore it would bind to this piece of Redux state: + +```json +{ + "form1": { + "fullname": "Chris Bond" + } +} +``` + +So far so good. But look at the array element inside our form, in the `