ngxs-synchronizers 1.0.0-rc.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -18
- package/README.md +168 -168
- package/bundles/ngxs-synchronizers.umd.js +12 -6
- package/bundles/ngxs-synchronizers.umd.js.map +1 -1
- package/docs/api-reference.md +700 -700
- package/docs/usage-guide.md +385 -385
- package/esm2015/decorators/sync-class.js +1 -1
- package/esm2015/decorators/sync-state.js +9 -3
- package/esm2015/index.js +1 -1
- package/esm2015/module.js +1 -1
- package/esm2015/state-selector.js +5 -5
- package/esm2015/sync-store.js +1 -1
- package/esm2015/synchronizer/collection-synchronizer.js +1 -1
- package/esm2015/synchronizer/property-synchronizer.js +1 -1
- package/esm2015/synchronizer/state-synchronizer.js +1 -1
- package/esm2015/synchronizer/synchronizer-dictionary.js +1 -1
- package/esm2015/synchronizer/synchronizer.js +1 -1
- package/fesm2015/ngxs-synchronizers.js +12 -6
- package/fesm2015/ngxs-synchronizers.js.map +1 -1
- package/package.json +1 -1
- package/state-selector.d.ts +2 -2
package/LICENSE
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
Copyright (c) 2020-2021 Mychal Thompson
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
-
in the Software without restriction, including without limitation the rights
|
|
6
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
furnished to do so, subject to the following conditions:
|
|
9
|
-
|
|
10
|
-
The above copyright notice and this permission notice shall be included in all
|
|
11
|
-
copies or substantial portions of the Software.
|
|
12
|
-
|
|
13
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
Copyright (c) 2020-2021 Mychal Thompson
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
19
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
# NGXS Synchronizers
|
|
2
|
-
|
|
3
|
-
Easily keep your app's local state synchronized with your backend, databases and more! ngxs-synchronizers simplifies synchronizing your NGXS-based application state with external data sources.
|
|
4
|
-
|
|
5
|
-
* [**About**](#about)
|
|
6
|
-
* [**Features**](#features)
|
|
7
|
-
* [**Installation**](#installation)
|
|
8
|
-
* [**Quick start**](#quick-start)
|
|
9
|
-
* [**Detailed usage guide**](/docs/usage-guide.md)
|
|
10
|
-
* [**API reference**](/docs/api-reference.md)
|
|
11
|
-
|
|
12
|
-
## About
|
|
13
|
-
|
|
14
|
-
**ngxs-synchronizers** is an extension to NGXS that allows for easy synchronization between a local NGXS state and an external data source (i.e. backend service, database, JSON file, etc.) through special Angular services called _Synchronizers_. Synchronizers can be used to read and write data from an external data source, and can be used to more easily manage application state synchronization and data dependency requirements.
|
|
15
|
-
|
|
16
|
-
Check out the [quick start guide](#quick-start) if you're already familiar with NGXS and want to quickly add ngxs-synchronizers to your existing app. The [full usage guide](/docs/usage-guide.md) gives a complete walkthrough of each feature. A full [**API reference**](/docs/api-reference.md) is also available.
|
|
17
|
-
|
|
18
|
-
## Features
|
|
19
|
-
|
|
20
|
-
* **Easy to configure** - Straightforward configuration that can be used accross your whole application or targeted at specific modules.
|
|
21
|
-
* **Efficient** - ngxs-synchronizers uses RxJS for efficient updating of data. Duplicate data requests are automatically batched into single requests and all synchronization requests can be observed and cancelled. Data can be conditionally required, allowing for zero-configuration caching and lazy-loading of requests.
|
|
22
|
-
* **Easy to integrate** - ngxs-synchronizers integrates transparently with NGXS and makes it feel like part of NGXS instead of yet another library.
|
|
23
|
-
|
|
24
|
-
## Installation
|
|
25
|
-
|
|
26
|
-
ngxs-synchronizers requires @ngxs/store as a dependency. Both can be installed from npm with the following command:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm install @ngxs/store ngxs-synchronizers
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
You must import the `NgxsSyncModule` module into the root of your application.
|
|
33
|
-
|
|
34
|
-
## Quick start
|
|
35
|
-
|
|
36
|
-
This section assumes you have an existing NGXS-enabled application already set up. Please see the [usage guide](/docs/usage-guide.md) for more detailed usage information.
|
|
37
|
-
|
|
38
|
-
After installing ngxs-synchronizers, we need to make some slight modifications to our existing ```@State``` classes. Given the following example NGXS ```State``` definition:
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
import { State } from '@ngxs/store';
|
|
42
|
-
|
|
43
|
-
interface Session {
|
|
44
|
-
username: string;
|
|
45
|
-
messages: string[];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@State<Session>({
|
|
49
|
-
name: 'session',
|
|
50
|
-
defaults: null
|
|
51
|
-
})
|
|
52
|
-
@Injectable()
|
|
53
|
-
class SessionState {
|
|
54
|
-
...
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
We first need to replace the ```@State``` decorator with the ```@SyncState``` decorator from ngxs-synchronizers. Now our ```SessionState``` class should look like this:
|
|
59
|
-
|
|
60
|
-
```ts
|
|
61
|
-
import { SyncState } from 'ngxs-synchronizers';
|
|
62
|
-
|
|
63
|
-
interface Session {
|
|
64
|
-
username: string;
|
|
65
|
-
messages: string[];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@SyncState<Session>({
|
|
69
|
-
name: 'session',
|
|
70
|
-
defaults: null
|
|
71
|
-
})
|
|
72
|
-
@Injectable()
|
|
73
|
-
class SessionState {
|
|
74
|
-
...
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Next, we need to create a ```Synchronizer``` service to sync up with our app's backend service. We're going to write a property synchronizer that gets the user's latest messages from the backend. Let's assume an existing service called ```Messages``` that contains a ```get``` method for retreiving the list of messages for a given username from the backend.
|
|
79
|
-
|
|
80
|
-
### Synchronizer service example:
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
import { PropertySynchronizer } from 'ngxs-synchronizers';
|
|
84
|
-
|
|
85
|
-
@Injectable({ providedIn: 'root' })
|
|
86
|
-
export class MessagesSynchronizer implements PropertySynchronizer<Session, 'messages'> {
|
|
87
|
-
|
|
88
|
-
// We need to know the username in order to fetch the messages
|
|
89
|
-
public readonly requiredProperties = ['username'];
|
|
90
|
-
|
|
91
|
-
// messagesProvider is an existing service for retrieving user messages from the backend
|
|
92
|
-
constructor(private readonly messagesProvider: Messages) {}
|
|
93
|
-
|
|
94
|
-
public read({ username }: Session): Observable<string[]> {
|
|
95
|
-
// Get current messages for the active user
|
|
96
|
-
return this.messagesProvider.get(username);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Our newly created ```MessagesSynchronizer``` service implements the ```PropertySynchronizer``` interface and specifies that it's managing the ```messages``` property on our ```Session``` model. We are also specifying that this synchronizer relies on the latest value of the ```username``` field from our ```Session``` store. In this case, we're assuming this value already exists in our local state. However, we could also create a ```PropertySynchronizer``` for the ```username``` property itself, and it would then automatically be invoked when ```MessagesSynchronizer``` is invoked.
|
|
102
|
-
|
|
103
|
-
The ```read``` method we've implemented receives any required fields from the object that are needed to perform the request. Since we've specified we require the ```username``` field, the ```read``` method will receive a partial ```Session``` object that contains the current value for ```username``` in our local store. The method should return an ```Observable``` with a return type that corresponds to the type of the field we're synchronizing, which in this case is a ```string[]```.
|
|
104
|
-
|
|
105
|
-
Now that we've created a ```Synchronizer```, we need to tell ngxs-synchronizers about it. Let's go back to our ```SessionState``` definition and register our new synchronizer:
|
|
106
|
-
|
|
107
|
-
```ts
|
|
108
|
-
interface Session {
|
|
109
|
-
username: string;
|
|
110
|
-
messages: string[];
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
@SyncState<Session>({
|
|
114
|
-
name: 'session',
|
|
115
|
-
defaults: null,
|
|
116
|
-
synchronizers: {
|
|
117
|
-
// Register the `MessagesSynchronizer` for the `messages` property
|
|
118
|
-
messages: MessagesSynchronizer
|
|
119
|
-
}
|
|
120
|
-
})
|
|
121
|
-
@Injectable()
|
|
122
|
-
class SessionState {
|
|
123
|
-
...
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
With that, we're now ready to start using our new synchronizer.
|
|
128
|
-
|
|
129
|
-
Let's assume we have a page in our app that shows the user's messages. When the user navigates to this page we want to make sure we've fetched the user's messages so we can display them. To do this, we can use the ```SyncStore``` service to update our ```session``` store with the latest messages from the backend service:
|
|
130
|
-
|
|
131
|
-
### ```SyncStore``` example:
|
|
132
|
-
|
|
133
|
-
```ts
|
|
134
|
-
@Component({...})
|
|
135
|
-
export class MessagesPage {
|
|
136
|
-
|
|
137
|
-
public messages: string[];
|
|
138
|
-
|
|
139
|
-
constructor(store: SyncStore) {
|
|
140
|
-
// Fetch the latest messages from the backend
|
|
141
|
-
store.state<Session>(SessionState)
|
|
142
|
-
.syncProperty('messages')
|
|
143
|
-
.subscribe(messages => this.messages = messages);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
We call ```SyncStore.state``` to get the ```StateSelector``` corresponding to our ```SessionState```. Calling ```StateSelector.syncProperty``` uses the ```MessagesSynchronizer``` we defined earlier to get the latest messages from the backend.
|
|
149
|
-
|
|
150
|
-
This works well, however we might want to only fetch the messages from the backend once when the user first navigates to the page, and then offer a refresh mechanism for loading new messages, or re-fetch them periodically. We can replace the call to ```syncProperty``` with ```requireProperty```, which will only make a request to the backend if the data doesn't already exist in the local store. Otherwise it will just return the existing data in the store.
|
|
151
|
-
|
|
152
|
-
### ```requireProperty``` example:
|
|
153
|
-
|
|
154
|
-
```ts
|
|
155
|
-
@Component({...})
|
|
156
|
-
export class MessagesPage {
|
|
157
|
-
|
|
158
|
-
public messages: string[];
|
|
159
|
-
|
|
160
|
-
constructor(store: SyncStore) {
|
|
161
|
-
// Fetch the latest messages from the backend
|
|
162
|
-
store.state<Session>(SessionState)
|
|
163
|
-
.requireProperty('messages')
|
|
164
|
-
.subscribe(messages => this.messages = messages);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
1
|
+
# NGXS Synchronizers
|
|
2
|
+
|
|
3
|
+
Easily keep your app's local state synchronized with your backend, databases and more! ngxs-synchronizers simplifies synchronizing your NGXS-based application state with external data sources.
|
|
4
|
+
|
|
5
|
+
* [**About**](#about)
|
|
6
|
+
* [**Features**](#features)
|
|
7
|
+
* [**Installation**](#installation)
|
|
8
|
+
* [**Quick start**](#quick-start)
|
|
9
|
+
* [**Detailed usage guide**](/docs/usage-guide.md)
|
|
10
|
+
* [**API reference**](/docs/api-reference.md)
|
|
11
|
+
|
|
12
|
+
## About
|
|
13
|
+
|
|
14
|
+
**ngxs-synchronizers** is an extension to NGXS that allows for easy synchronization between a local NGXS state and an external data source (i.e. backend service, database, JSON file, etc.) through special Angular services called _Synchronizers_. Synchronizers can be used to read and write data from an external data source, and can be used to more easily manage application state synchronization and data dependency requirements.
|
|
15
|
+
|
|
16
|
+
Check out the [quick start guide](#quick-start) if you're already familiar with NGXS and want to quickly add ngxs-synchronizers to your existing app. The [full usage guide](/docs/usage-guide.md) gives a complete walkthrough of each feature. A full [**API reference**](/docs/api-reference.md) is also available.
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
* **Easy to configure** - Straightforward configuration that can be used accross your whole application or targeted at specific modules.
|
|
21
|
+
* **Efficient** - ngxs-synchronizers uses RxJS for efficient updating of data. Duplicate data requests are automatically batched into single requests and all synchronization requests can be observed and cancelled. Data can be conditionally required, allowing for zero-configuration caching and lazy-loading of requests.
|
|
22
|
+
* **Easy to integrate** - ngxs-synchronizers integrates transparently with NGXS and makes it feel like part of NGXS instead of yet another library.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
ngxs-synchronizers requires @ngxs/store as a dependency. Both can be installed from npm with the following command:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @ngxs/store ngxs-synchronizers
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You must import the `NgxsSyncModule` module into the root of your application.
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
This section assumes you have an existing NGXS-enabled application already set up. Please see the [usage guide](/docs/usage-guide.md) for more detailed usage information.
|
|
37
|
+
|
|
38
|
+
After installing ngxs-synchronizers, we need to make some slight modifications to our existing ```@State``` classes. Given the following example NGXS ```State``` definition:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { State } from '@ngxs/store';
|
|
42
|
+
|
|
43
|
+
interface Session {
|
|
44
|
+
username: string;
|
|
45
|
+
messages: string[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@State<Session>({
|
|
49
|
+
name: 'session',
|
|
50
|
+
defaults: null
|
|
51
|
+
})
|
|
52
|
+
@Injectable()
|
|
53
|
+
class SessionState {
|
|
54
|
+
...
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
We first need to replace the ```@State``` decorator with the ```@SyncState``` decorator from ngxs-synchronizers. Now our ```SessionState``` class should look like this:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { SyncState } from 'ngxs-synchronizers';
|
|
62
|
+
|
|
63
|
+
interface Session {
|
|
64
|
+
username: string;
|
|
65
|
+
messages: string[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@SyncState<Session>({
|
|
69
|
+
name: 'session',
|
|
70
|
+
defaults: null
|
|
71
|
+
})
|
|
72
|
+
@Injectable()
|
|
73
|
+
class SessionState {
|
|
74
|
+
...
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Next, we need to create a ```Synchronizer``` service to sync up with our app's backend service. We're going to write a property synchronizer that gets the user's latest messages from the backend. Let's assume an existing service called ```Messages``` that contains a ```get``` method for retreiving the list of messages for a given username from the backend.
|
|
79
|
+
|
|
80
|
+
### Synchronizer service example:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { PropertySynchronizer } from 'ngxs-synchronizers';
|
|
84
|
+
|
|
85
|
+
@Injectable({ providedIn: 'root' })
|
|
86
|
+
export class MessagesSynchronizer implements PropertySynchronizer<Session, 'messages'> {
|
|
87
|
+
|
|
88
|
+
// We need to know the username in order to fetch the messages
|
|
89
|
+
public readonly requiredProperties = ['username'];
|
|
90
|
+
|
|
91
|
+
// messagesProvider is an existing service for retrieving user messages from the backend
|
|
92
|
+
constructor(private readonly messagesProvider: Messages) {}
|
|
93
|
+
|
|
94
|
+
public read({ username }: Session): Observable<string[]> {
|
|
95
|
+
// Get current messages for the active user
|
|
96
|
+
return this.messagesProvider.get(username);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Our newly created ```MessagesSynchronizer``` service implements the ```PropertySynchronizer``` interface and specifies that it's managing the ```messages``` property on our ```Session``` model. We are also specifying that this synchronizer relies on the latest value of the ```username``` field from our ```Session``` store. In this case, we're assuming this value already exists in our local state. However, we could also create a ```PropertySynchronizer``` for the ```username``` property itself, and it would then automatically be invoked when ```MessagesSynchronizer``` is invoked.
|
|
102
|
+
|
|
103
|
+
The ```read``` method we've implemented receives any required fields from the object that are needed to perform the request. Since we've specified we require the ```username``` field, the ```read``` method will receive a partial ```Session``` object that contains the current value for ```username``` in our local store. The method should return an ```Observable``` with a return type that corresponds to the type of the field we're synchronizing, which in this case is a ```string[]```.
|
|
104
|
+
|
|
105
|
+
Now that we've created a ```Synchronizer```, we need to tell ngxs-synchronizers about it. Let's go back to our ```SessionState``` definition and register our new synchronizer:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
interface Session {
|
|
109
|
+
username: string;
|
|
110
|
+
messages: string[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@SyncState<Session>({
|
|
114
|
+
name: 'session',
|
|
115
|
+
defaults: null,
|
|
116
|
+
synchronizers: {
|
|
117
|
+
// Register the `MessagesSynchronizer` for the `messages` property
|
|
118
|
+
messages: MessagesSynchronizer
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
@Injectable()
|
|
122
|
+
class SessionState {
|
|
123
|
+
...
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
With that, we're now ready to start using our new synchronizer.
|
|
128
|
+
|
|
129
|
+
Let's assume we have a page in our app that shows the user's messages. When the user navigates to this page we want to make sure we've fetched the user's messages so we can display them. To do this, we can use the ```SyncStore``` service to update our ```session``` store with the latest messages from the backend service:
|
|
130
|
+
|
|
131
|
+
### ```SyncStore``` example:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
@Component({...})
|
|
135
|
+
export class MessagesPage {
|
|
136
|
+
|
|
137
|
+
public messages: string[];
|
|
138
|
+
|
|
139
|
+
constructor(store: SyncStore) {
|
|
140
|
+
// Fetch the latest messages from the backend
|
|
141
|
+
store.state<Session>(SessionState)
|
|
142
|
+
.syncProperty('messages')
|
|
143
|
+
.subscribe(messages => this.messages = messages);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
We call ```SyncStore.state``` to get the ```StateSelector``` corresponding to our ```SessionState```. Calling ```StateSelector.syncProperty``` uses the ```MessagesSynchronizer``` we defined earlier to get the latest messages from the backend.
|
|
149
|
+
|
|
150
|
+
This works well, however we might want to only fetch the messages from the backend once when the user first navigates to the page, and then offer a refresh mechanism for loading new messages, or re-fetch them periodically. We can replace the call to ```syncProperty``` with ```requireProperty```, which will only make a request to the backend if the data doesn't already exist in the local store. Otherwise it will just return the existing data in the store.
|
|
151
|
+
|
|
152
|
+
### ```requireProperty``` example:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
@Component({...})
|
|
156
|
+
export class MessagesPage {
|
|
157
|
+
|
|
158
|
+
public messages: string[];
|
|
159
|
+
|
|
160
|
+
constructor(store: SyncStore) {
|
|
161
|
+
// Fetch the latest messages from the backend
|
|
162
|
+
store.state<Session>(SessionState)
|
|
163
|
+
.requireProperty('messages')
|
|
164
|
+
.subscribe(messages => this.messages = messages);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
169
|
Now the user's messages will only be fetched from the backend the first time the user navigates to ```MessagesPage```.
|
|
@@ -394,9 +394,14 @@
|
|
|
394
394
|
configurable: false,
|
|
395
395
|
enumerable: true,
|
|
396
396
|
value: function (context, _b) {
|
|
397
|
-
var _c;
|
|
397
|
+
var _c, _d;
|
|
398
398
|
var property = _b.property, payload = _b.payload;
|
|
399
|
-
context.
|
|
399
|
+
if (context.getState() === undefined || context.getState() === null) {
|
|
400
|
+
context.setState((_c = {}, _c[property] = payload, _c));
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
context.patchState((_d = {}, _d[property] = payload, _d));
|
|
404
|
+
}
|
|
400
405
|
}
|
|
401
406
|
});
|
|
402
407
|
// Apply the @Action() decorator to the new function
|
|
@@ -406,6 +411,7 @@
|
|
|
406
411
|
function Type($class) {
|
|
407
412
|
var _a;
|
|
408
413
|
if (!updateActions.has($class)) {
|
|
414
|
+
var opts = exports.ɵa.getStoreOptions($class);
|
|
409
415
|
updateActions.set($class, (_a = /** @class */ (function (_super) {
|
|
410
416
|
__extends(_a, _super);
|
|
411
417
|
function _a() {
|
|
@@ -413,7 +419,7 @@
|
|
|
413
419
|
}
|
|
414
420
|
return _a;
|
|
415
421
|
}(UpdateAction)),
|
|
416
|
-
_a.type = "[" +
|
|
422
|
+
_a.type = "[" + opts.name + " sync] Update field",
|
|
417
423
|
_a));
|
|
418
424
|
}
|
|
419
425
|
return updateActions.get($class);
|
|
@@ -463,7 +469,7 @@
|
|
|
463
469
|
return this.store.dispatch(new PropUpdateAction(propertyName, value));
|
|
464
470
|
};
|
|
465
471
|
StateSelector.prototype.property = function (propertyName) {
|
|
466
|
-
return this.state$.pipe(operators.map(function (state) { return state[propertyName]; }));
|
|
472
|
+
return this.state$.pipe(operators.map(function (state) { return state === null || state === void 0 ? void 0 : state[propertyName]; }));
|
|
467
473
|
};
|
|
468
474
|
StateSelector.prototype.properties = function () {
|
|
469
475
|
return this.state$;
|
|
@@ -545,7 +551,7 @@
|
|
|
545
551
|
StateSelector.prototype.requireOne = function (propertyName, options) {
|
|
546
552
|
var _this = this;
|
|
547
553
|
return this.state$.pipe(operators.take(1), operators.mergeMap(function (state) {
|
|
548
|
-
if (state[propertyName]) {
|
|
554
|
+
if ((state === null || state === void 0 ? void 0 : state[propertyName]) !== undefined && (state === null || state === void 0 ? void 0 : state[propertyName]) !== null) {
|
|
549
555
|
return rxjs.of(state);
|
|
550
556
|
}
|
|
551
557
|
else {
|
|
@@ -664,7 +670,7 @@
|
|
|
664
670
|
var _this = this;
|
|
665
671
|
options = options || {};
|
|
666
672
|
if (propertyNames.length === 0) {
|
|
667
|
-
return rxjs.
|
|
673
|
+
return rxjs.EMPTY;
|
|
668
674
|
}
|
|
669
675
|
// Update each required propertyName
|
|
670
676
|
var errors = [];
|