Skip to content

Commit 9299491

Browse files
authored
breaking changes: update to Angular/RxJS/Ngrx v6 v6.0.0-beta.1 (johnpapa#147)
* tweak collection reducer methods * refactor: NgrxDataModule no longer calls store/effects .forFeature, Inspired by inability to build because of issue angular/angular#23609 * other refactors to satisfy RxJS v6, fix and add tests, and clear many lint errors. * feat: add optional label to EntityAction and EntityActionFactory
1 parent 31690de commit 9299491

File tree

142 files changed

+7307
-5061
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

142 files changed

+7307
-5061
lines changed

Diff for: angular.json

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
{
2+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3+
"version": 1,
4+
"newProjectRoot": "projects",
5+
"projects": {
6+
"app": {
7+
"root": "",
8+
"sourceRoot": "src",
9+
"projectType": "application",
10+
"architect": {
11+
"build": {
12+
"builder": "@angular-devkit/build-angular:browser",
13+
"options": {
14+
"outputPath": "dist/app",
15+
"index": "src/index.html",
16+
"main": "src/main.ts",
17+
"tsConfig": "src/tsconfig.app.json",
18+
"polyfills": "src/polyfills.ts",
19+
"stylePreprocessorOptions": {
20+
"includePaths": ["src/styles"]
21+
},
22+
"assets": ["src/assets", "src/favicon.ico"],
23+
"styles": [
24+
"src/styles/theme.scss",
25+
"src/styles/mixin.scss",
26+
"src/styles/styles.scss"
27+
],
28+
"scripts": []
29+
},
30+
"configurations": {
31+
"production": {
32+
"optimization": true,
33+
"outputHashing": "all",
34+
"sourceMap": false,
35+
"extractCss": true,
36+
"namedChunks": false,
37+
"aot": true,
38+
"extractLicenses": true,
39+
"vendorChunk": false,
40+
"buildOptimizer": true,
41+
"fileReplacements": [
42+
{
43+
"replace": "src/environments/environment.ts",
44+
"with": "src/environments/environment.prod.ts"
45+
}
46+
]
47+
}
48+
}
49+
},
50+
"serve": {
51+
"builder": "@angular-devkit/build-angular:dev-server",
52+
"options": {
53+
"browserTarget": "app:build"
54+
},
55+
"configurations": {
56+
"production": {
57+
"browserTarget": "app:build:production"
58+
}
59+
}
60+
},
61+
"extract-i18n": {
62+
"builder": "@angular-devkit/build-angular:extract-i18n",
63+
"options": {
64+
"browserTarget": "app:build"
65+
}
66+
},
67+
"test": {
68+
"builder": "@angular-devkit/build-angular:karma",
69+
"options": {
70+
"main": "src/test.ts",
71+
"karmaConfig": "./karma.conf.js",
72+
"polyfills": "src/polyfills.ts",
73+
"tsConfig": "src/tsconfig.spec.json",
74+
"scripts": [],
75+
"styles": [
76+
"src/styles/theme.scss",
77+
"src/styles/mixin.scss",
78+
"src/styles/styles.scss"
79+
],
80+
"assets": ["src/assets", "src/favicon.ico"]
81+
}
82+
},
83+
"lint": {
84+
"builder": "@angular-devkit/build-angular:tslint",
85+
"options": {
86+
"tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"],
87+
"exclude": ["**/node_modules/**"]
88+
}
89+
}
90+
}
91+
},
92+
"app-e2e": {
93+
"root": "",
94+
"sourceRoot": "",
95+
"projectType": "application",
96+
"architect": {
97+
"e2e": {
98+
"builder": "@angular-devkit/build-angular:protractor",
99+
"options": {
100+
"protractorConfig": "./protractor.conf.js",
101+
"devServerTarget": "app:serve"
102+
}
103+
},
104+
"lint": {
105+
"builder": "@angular-devkit/build-angular:tslint",
106+
"options": {
107+
"tsConfig": ["e2e/tsconfig.e2e.json"],
108+
"exclude": ["**/node_modules/**"]
109+
}
110+
}
111+
}
112+
}
113+
},
114+
"defaultProject": "app",
115+
"schematics": {
116+
"@schematics/angular:component": {
117+
"prefix": "app",
118+
"styleext": "scss"
119+
},
120+
"@schematics/angular:directive": {
121+
"prefix": "app"
122+
}
123+
}
124+
}

Diff for: .angular-cli.json renamed to angular.old.angular-cli.json

+6-11
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,19 @@
77
{
88
"root": "src/client",
99
"outDir": "dist/app",
10-
"assets": [
11-
"assets",
12-
"favicon.ico",
13-
{
14-
"allowOutsideOutDir": true,
15-
"glob": "**/*.*",
16-
"input": "../server/",
17-
"output": "../server/"
18-
}
19-
],
10+
"assets": ["assets", "favicon.ico"],
2011
"index": "index.html",
2112
"main": "main.ts",
2213
"polyfills": "polyfills.ts",
2314
"test": "test.ts",
2415
"tsconfig": "tsconfig.app.json",
2516
"testTsconfig": "tsconfig.spec.json",
2617
"prefix": "app",
27-
"styles": ["styles/theme.scss", "styles/mixin.scss", "styles/styles.scss"],
18+
"styles": [
19+
"styles/theme.scss",
20+
"styles/mixin.scss",
21+
"styles/styles.scss"
22+
],
2823
"stylePreprocessorOptions": {
2924
"includePaths": ["styles"]
3025
},

Diff for: docs/entity-actions.md

+121-24
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,39 @@ The [`EntityService`](entity-service.md) dispatches an `EntityAction` to the _ng
55
## _Action_ and _EntityAction_
66

77
A vanilla
8-
[_ngrx `Action`_](https://github.com/ngrx/platform/blob/master/docs/store/actions.md) is a message.
8+
[_ngrx `Action`_](https://github.com/ngrx/platform/blob/master/docs/store/actions.md) is a message.
99
The message describes an operation that can change state in the _store_.
1010

1111
The _action_'s `type` identifies the operation.
1212
It's optional `payload` carries the message data necessary to perform the operation.
1313

1414
An [`EntityAction`](../lib/src/actions/entity-action.ts) is a super-set of the _ngrx `Action`_.
15-
It has additional properties that guide _ngrx-data_'s handling of the action. Here's the full interface.
15+
It has additional properties that guide _ngrx-data_'s handling of the action. Here's the full interface.
1616

1717
```
1818
export interface EntityAction<P = any> extends Action {
1919
readonly type: string;
2020
readonly entityName: string;
2121
readonly op: EntityOp;
2222
readonly payload?: P;
23+
readonly label?: string;
2324
error?: Error;
2425
}
2526
```
2627

27-
* `type` - action name, typically generated from the `entityName` and the `op`
28+
* `type` - action name, typically generated from the `label` and the `op`
2829
* `entityName` - the name of the entity type
2930
* `op` - the name of an entity operation
3031
* `payload?` - the message data for the action.
32+
* `label?` - the label to use within the generated type. If not specified, the `entityName` is the label.
3133
* `error?` - an unexpected action processing error.
3234

33-
3435
The `type` is the only property required by _ngrx_. It is a string that uniquely identifies the action among the set of all the types of actions that can be dispatched to the store.
3536

3637
_Ngrx-data_ doesn't care about the `type`. It pays attention to the `entityName` and `op` properties.
3738

38-
The `entityName` is the name of the entity type.
39-
It identifies the _entity collection_ in the _ngrx-data_ cache to which this action applies.
39+
The `entityName` is the name of the entity type.
40+
It identifies the _entity collection_ in the _ngrx-data_ cache to which this action applies.
4041
This name corresponds to [_ngrx-data metadata_](entity-metadata.md) for that collection.
4142
An entity interface or class name, such as `'Hero'`, is a typical `entityName`.
4243

@@ -47,63 +48,158 @@ that the _ngrx-data_ library can perform.
4748
The `payload` is conceptually the body of the message.
4849
Its type and content should fit the requirements of the operation to be performed.
4950

51+
The optional `label` appears in the generated `type` text when the `EntityActionFactory` creates this `EntityAction`.
52+
53+
The `entityName` is the default label that appears between brackets in the formatted `type`,
54+
e.g., `'[Hero] ngrx-data/query-all'`.
55+
5056
The `error` property indicates that something went wrong while processing the action. [See more below](#action-error).
5157

5258
## _EntityAction_ consumers
5359

5460
The _ngrx-data_ library ignores the `Action.type`.
5561
All _ngrx-data_ library behaviors are determined by the `entityName` and `op` properties alone.
5662

57-
The _ngrx-data_ [`EntityReducer`](../lib/src/reducers/entity-reducer.ts) redirects an action to an `EntityCollectionReducer` based on the `entityName`
63+
The _ngrx-data_ [`EntityReducer`](../lib/src/reducers/entity-reducer.ts) redirects an action to an `EntityCollectionReducer` based on the `entityName`
5864
and that reducer processes the action based on the `op`.
5965

6066
The [`EntityEffects`](../lib/src/effects/entity-effects.ts) intercepts an action if its `op` is among the small set of persistence `EntityAction.op` names.
6167
The effect picks the right _data service_ for that action's `entityName`, then tells the service to make the appropriate HTTP request and handle the response.
6268

63-
6469
## Creating an _EntityAction_
6570

6671
You can create an `EntityAction` by hand if you wish.
67-
The _ngrx-data_ library considers _any action_ with an `entityName` and `op` properties to be an `EntityAction`.
72+
The _ngrx-data_ library considers _any action_ with an `entityName` and `op` properties to be an `EntityAction`.
6873

69-
The `EntityActionFactory.create()` method helps you create a consistently well-formed `EntityAction` instance
70-
whose `type` is a string composed from the `entityName` and the `op`.
74+
The `EntityActionFactory.create()` method helps you create a consistently well-formed `EntityAction` instance
75+
whose `type` is a string composed from the `label` (the `entityName` by default) and the `op`.
7176

7277
For example, the default generated `Action.type` for the operation that queries the server for all heroes is `'[Hero] ngrx-data/query-all'`.
7378

74-
>The `EntityActionFactory.create()` method calls the factory's `formatActionType()` method
75-
to produce the `Action.type` string.
79+
> The `EntityActionFactory.create()` method calls the factory's `formatActionType()` method
80+
> to produce the `Action.type` string.
7681
>
77-
>Because _ngrx-data_ ignores the `type`, you can replace `formatActionType()` with your own method if you prefer a different format
78-
or provide and inject your own `EntityActionFactory`.
82+
> Because _ngrx-data_ ignores the `type`, you can replace `formatActionType()` with your own method if you prefer a different format
83+
> or provide and inject your own `EntityActionFactory`.
84+
85+
Note that **_each entity type has its own \_unique_ `Action` for each operation\_**, as if you had created them individually by hand.
86+
87+
## Labeling the EntityAction
88+
89+
A well-formed action `type` can tell the reader what changed and
90+
who changed it.
91+
92+
The _ngrx-data_ library doesn't look at the type of an `EntityAction`,
93+
only its `entityName` and `entityOp`.
94+
So you can get the same behavior from several different actions,
95+
each with its own informative `type`, as long as they share the same
96+
`entityName` and `entityOp`.
97+
98+
The optional `label` parameter of the `EntityActionFactory.create()` method makes
99+
it easy to produce meaningful _EntityActions_.
100+
101+
You don't have to specify a label. The `entityName` is the default label that appears between brackets in the formatted `type`,
102+
e.g., `'[Hero] ngrx-data/query-all'`.
103+
104+
Here's an example that uses the injectable `EntityActionFactory` to construct the default "query all heroes" action.
105+
106+
```
107+
const action = entityActionFactory<Hero>(
108+
'Hero', EntityOp.QUERY_ALL, null, 'Load Heroes On Start'
109+
);
110+
111+
store.dispatch(action);
112+
```
113+
114+
Thanks to the _ngrx-data **effects**_, this produces _two_ actions in the log, the first to initiate the request and the second with the successful response:
115+
116+
```
117+
[Hero] ngrx-data/query-all
118+
[Hero] ngrx-data/query-all-success
119+
```
120+
121+
This default `entityName` label identifies the action's target entity collection.
122+
But you can't understand the _context_ of the action from these log entries. You don't know who dispatched the action or why.
123+
The action `type` is too generic.
124+
125+
You can create a more informative action by providing a label that
126+
better describes what is happening and also make it easier to find
127+
where that action is dispatched by your code.
128+
129+
For example,
130+
131+
```
132+
const action = entityActionFactory<Hero>(
133+
'Hero', EntityOp.QUERY_ALL, null, 'Load Heroes On Start'
134+
);
135+
136+
store.dispatch(action);
137+
```
138+
139+
The action log now looks like this:
140+
141+
```
142+
[Load Heroes On Start] ngrx-data/query-all
143+
[Load Heroes On Start] ngrx-data/query-all-success
144+
```
145+
146+
### Handcrafted EntityAction
147+
148+
You don't have to create entity actions with the `EntityActionFactory`.
149+
Any action object with an `entityName` and `op` property is
150+
an entity action, as explained [below](#where-are-the-entityactions).
79151

80-
Note that **_each entity type has its own _unique_ `Action` for each operation_**, as if you had created them individually by hand.
152+
The following example creates the initiating "query all heroes" action by hand.
153+
154+
```
155+
const action = {
156+
type: 'some/arbitrary/action/type',
157+
entityName: 'Hero',
158+
op: EntityOp.QUERY_ALL
159+
};
160+
161+
store.dispatch(action);
162+
```
163+
164+
It triggers the HTTP request via _ngrx-data effects_, as in the previous examples.
165+
166+
Just be aware that _ngrx-data effects_ uses the `EntityActionFactory` to create the second, success Action.
167+
Without the `label` property, it produces a generic success action.
168+
169+
The log of the two action types will look like this:
170+
171+
```
172+
some/arbitrary/action/type
173+
[Hero] ngrx-data/query-all-success
174+
```
175+
176+
<a id="where-are-the-entityactions"></a>
81177

82178
## Where are the _EntityActions_?
83179

84180
In an _ngrx-data_ app, the _ngrx-data_ library creates and dispatches _EntityActions_ for you.
85181

86-
_EntityActions_ are largely invisible when you call the [`EntityService`](entity-service.md) API.
182+
_EntityActions_ are largely invisible when you call the [`EntityService`](entity-service.md) API.
87183
You can see them in action with the
88184
[ngrx store dev-tools](https://github.com/ngrx/platform/tree/master/docs/store-devtools).
89185

90186
## Why this matters
91187

92-
In an ordinary _ngrx_ application, you hand-code every `Action` for every _state_ in the store
93-
as well as the [reducers](https://github.com/ngrx/platform/blob/master/docs/store/actions.md#action-reducers)
188+
In an ordinary _ngrx_ application, you hand-code every `Action` for every _state_ in the store
189+
as well as the [reducers](https://github.com/ngrx/platform/blob/master/docs/store/actions.md#action-reducers)
94190
that process those _actions_.
95191

96192
It takes many _actions_, a complex _reducer_, and the help of the [@ngrx/effects](https://github.com/ngrx/platform/blob/master/docs/effects/README.md) package to manage queries and saves for a _single_ entity type.
97193

98194
The [@ngrx/entity](https://github.com/ngrx/platform/blob/master/docs/entity/README.md) package makes the job considerably easier.
99195

100-
>The _ngrx-data_ library internally delegates much of the heavy lifting to _@ngrx/entity_.
196+
> The _ngrx-data_ library internally delegates much of the heavy lifting to _@ngrx/entity_.
101197
102198
But you must still write a lot of code for each entity type.
103-
You're expected to create _eight actions_ per entity type and
199+
You're expected to create _eight actions_ per entity type and
104200
write a _reducer_ that responds to these eight actions by calling eight methods of an [@ngrx/entity _EntityAdapter_](https://github.com/ngrx/platform/blob/master/docs/entity/adapter.md#adapter-collection-methods).
105201

106-
These artifacts only address the _cached_ entity collection.
202+
These artifacts only address the _cached_ entity collection.
107203

108204
You may write as many as _eighteen additional actions_ to support a typical complement of asynchronous CRUD (Create, Retrieve, Update, Delete) operations. You'll have to dispatch them to the store where you'll process them with more _reducer_ methods and _effects_ that you must also hand code.
109205

@@ -113,8 +209,8 @@ That's a lot of code to write, test, and maintain.
113209
With the help of _ngrx-data_, you don't write any of it.
114210
_Ngrx-data_ creates the _actions_ and the _dispatchers_, _reducers_, and _effects_ that respond to those actions.
115211

116-
117212
<a name="action-error"></a>
213+
118214
## _EntityAction.error_
119215

120216
The presence of an `EntityAction.error` property indicates that something bad happened while processing the action.
@@ -131,9 +227,10 @@ _Ngrx-data_ traps an error thrown by an `EntityCollectionReducer` and sets the `
131227
The `error` property is important when the errant action is a _persistence action_ (such as `SAVE_ADD_ONE`).
132228
The `EntityEffects` will see that such an action has an error and will return the corresponding failure action (`SAVE_ADD_ONE_ERROR`) immediately, without attempting an HTTP request.
133229

134-
>This is the only way we've found to prevent a bad action from getting through the effect and triggering an HTTP request.
230+
> This is the only way we've found to prevent a bad action from getting through the effect and triggering an HTTP request.
135231
136232
<a name="entity-cache-actions"></a>
233+
137234
## EntityCache-level actions
138235

139236
A few actions target the entity cache as a whole.

0 commit comments

Comments
 (0)