ng-simple-state 21.1.3 → 21.1.5
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/README.md +99 -70
- package/fesm2022/ng-simple-state.mjs +115 -181
- package/fesm2022/ng-simple-state.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ng-simple-state.d.ts +63 -72
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# NgSimpleState [](https://www.npmjs.com/package/ng-simple-state) [](https://qlty.sh/gh/nigrosimone/projects/ng-simple-state)
|
|
2
2
|
|
|
3
3
|
Simple state management in Angular with only Services and RxJS or Signal.
|
|
4
4
|
|
|
@@ -31,7 +31,6 @@ npm i ng-simple-state
|
|
|
31
31
|
| *serializeState* | A function used to serialize the state to a string. | `JSON.stringify` |
|
|
32
32
|
| *deserializeState* | A function used to deserialize the state from a string. | `JSON.parse` |
|
|
33
33
|
| *plugins* | Array of plugins to extend store functionality. | `[]` |
|
|
34
|
-
| *enableImmer* | Enable Immer-style immutable updates. | `false` |
|
|
35
34
|
| *immerProduce* | Custom Immer produce function for immutable updates. | undefined |
|
|
36
35
|
|
|
37
36
|
_Side note: each store can be override the global configuration implementing `storeConfig()` method (see "Override global config")._
|
|
@@ -1154,7 +1153,6 @@ Usage in component:
|
|
|
1154
1153
|
selector: 'app-profile',
|
|
1155
1154
|
template: `
|
|
1156
1155
|
<p>Full Name: {{ store.fullName() }}</p>
|
|
1157
|
-
<p>Is Adult: {{ store.isAdult() ? 'Yes' : 'No' }}</p>
|
|
1158
1156
|
<input [value]="firstName()" (input)="updateFirstName($event)" placeholder="First name" />
|
|
1159
1157
|
<input [value]="lastName()" (input)="updateLastName($event)" placeholder="Last name" />
|
|
1160
1158
|
`
|
|
@@ -1283,89 +1281,83 @@ const myCustomPlugin: NgSimpleStatePlugin = {
|
|
|
1283
1281
|
};
|
|
1284
1282
|
```
|
|
1285
1283
|
|
|
1286
|
-
###
|
|
1284
|
+
### Transactions
|
|
1287
1285
|
|
|
1288
|
-
|
|
1286
|
+
Execute operations with automatic rollback on error using `withTransaction`:
|
|
1289
1287
|
|
|
1290
1288
|
```ts
|
|
1291
|
-
import {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
@Injectable({ providedIn: 'root' })
|
|
1302
|
-
export class FormStore extends NgSimpleStateBaseSignalStore<FormState> {
|
|
1289
|
+
import { withTransaction } from 'ng-simple-state';
|
|
1290
|
+
|
|
1291
|
+
// Transaction with automatic rollback on error
|
|
1292
|
+
await withTransaction(store, async (tx) => {
|
|
1293
|
+
store.setState({ step: 1 });
|
|
1294
|
+
await apiCall(); // If this fails, state rolls back automatically
|
|
1295
|
+
store.setState({ step: 2 });
|
|
1296
|
+
tx.commit(); // Explicit commit (optional - auto-commits if not called)
|
|
1297
|
+
});
|
|
1303
1298
|
|
|
1304
|
-
|
|
1305
|
-
|
|
1299
|
+
// Manual rollback example
|
|
1300
|
+
await withTransaction(store, async (tx) => {
|
|
1301
|
+
store.setState({ processing: true });
|
|
1302
|
+
const result = await riskyOperation();
|
|
1303
|
+
|
|
1304
|
+
if (!result.success) {
|
|
1305
|
+
tx.rollback(); // Manually rollback to initial state
|
|
1306
|
+
return;
|
|
1306
1307
|
}
|
|
1308
|
+
|
|
1309
|
+
store.setState({ data: result.data });
|
|
1310
|
+
tx.commit();
|
|
1311
|
+
});
|
|
1312
|
+
```
|
|
1307
1313
|
|
|
1308
|
-
|
|
1309
|
-
return { name: '', email: '', phone: '', isValid: false };
|
|
1310
|
-
}
|
|
1314
|
+
### Debounced Updates
|
|
1311
1315
|
|
|
1312
|
-
|
|
1313
|
-
return this.selectState();
|
|
1314
|
-
}
|
|
1316
|
+
Rate-limit state updates with `createDebouncedUpdater`. Only the last update within the time window is applied:
|
|
1315
1317
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
batchState(() => {
|
|
1319
|
-
this.setState({ name });
|
|
1320
|
-
this.setState({ email });
|
|
1321
|
-
this.setState({ phone });
|
|
1322
|
-
this.setState({ isValid: this.validateForm(name, email, phone) });
|
|
1323
|
-
}); // Single emission with all changes
|
|
1324
|
-
}
|
|
1318
|
+
```ts
|
|
1319
|
+
import { createDebouncedUpdater } from 'ng-simple-state';
|
|
1325
1320
|
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1321
|
+
// Create a debounced updater with 300ms delay
|
|
1322
|
+
const { update, flush, cancel } = createDebouncedUpdater<MyState>(
|
|
1323
|
+
(state) => store.setState(state),
|
|
1324
|
+
300
|
|
1325
|
+
);
|
|
1330
1326
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1327
|
+
// Rapid calls - only the last one is applied after 300ms
|
|
1328
|
+
update({ searchQuery: 'a' });
|
|
1329
|
+
update({ searchQuery: 'ab' });
|
|
1330
|
+
update({ searchQuery: 'abc' }); // Only this is applied after 300ms
|
|
1334
1331
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1332
|
+
// Force immediate update
|
|
1333
|
+
flush();
|
|
1334
|
+
|
|
1335
|
+
// Cancel any pending update
|
|
1336
|
+
cancel();
|
|
1339
1337
|
```
|
|
1340
1338
|
|
|
1341
|
-
|
|
1339
|
+
### Throttled Updates
|
|
1340
|
+
|
|
1341
|
+
Limit update frequency with `createThrottledUpdater`. At most one update per time window:
|
|
1342
1342
|
|
|
1343
1343
|
```ts
|
|
1344
|
-
|
|
1345
|
-
selector: 'app-form',
|
|
1346
|
-
template: `
|
|
1347
|
-
<form (ngSubmit)="submitForm()">
|
|
1348
|
-
<input [(ngModel)]="name" name="name" placeholder="Name" />
|
|
1349
|
-
<input [(ngModel)]="email" name="email" placeholder="Email" />
|
|
1350
|
-
<input [(ngModel)]="phone" name="phone" placeholder="Phone" />
|
|
1351
|
-
<button type="submit">Save All (Batched)</button>
|
|
1352
|
-
</form>
|
|
1353
|
-
<p>Form Valid: {{ form().isValid ? 'Yes' : 'No' }}</p>
|
|
1354
|
-
`
|
|
1355
|
-
})
|
|
1356
|
-
export class FormComponent {
|
|
1357
|
-
store = inject(FormStore);
|
|
1358
|
-
form = this.store.selectForm();
|
|
1359
|
-
|
|
1360
|
-
name = '';
|
|
1361
|
-
email = '';
|
|
1362
|
-
phone = '';
|
|
1344
|
+
import { createThrottledUpdater } from 'ng-simple-state';
|
|
1363
1345
|
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1346
|
+
// Create a throttled updater with 100ms delay
|
|
1347
|
+
const { update, cancel } = createThrottledUpdater<MyState>(
|
|
1348
|
+
(state) => store.setState(state),
|
|
1349
|
+
100
|
|
1350
|
+
);
|
|
1351
|
+
|
|
1352
|
+
// First call executes immediately, subsequent calls are throttled
|
|
1353
|
+
update({ scrollPosition: 100 }); // Executes immediately
|
|
1354
|
+
update({ scrollPosition: 150 }); // Queued
|
|
1355
|
+
update({ scrollPosition: 200 }); // Replaces queued update
|
|
1356
|
+
|
|
1357
|
+
// After 100ms, { scrollPosition: 200 } is applied
|
|
1358
|
+
|
|
1359
|
+
// Cancel pending throttled update
|
|
1360
|
+
cancel();
|
|
1369
1361
|
```
|
|
1370
1362
|
|
|
1371
1363
|
### Immer-style Updates
|
|
@@ -1508,6 +1500,43 @@ Features available in Redux DevTools:
|
|
|
1508
1500
|
|
|
1509
1501
|

|
|
1510
1502
|
|
|
1503
|
+
### Integration with ng-http-caching
|
|
1504
|
+
|
|
1505
|
+
`ng-simple-state` can be used as a reactive storage backend for [ng-http-caching](https://www.npmjs.com/package/ng-http-caching). This integration allows you to manage the HTTP cache through `ng-simple-state` stores, providing full visibility and control over the cache state within your DevTools or application state.
|
|
1506
|
+
|
|
1507
|
+
1. Install `ng-http-caching`:
|
|
1508
|
+
|
|
1509
|
+
```bash
|
|
1510
|
+
npm i ng-http-caching
|
|
1511
|
+
```
|
|
1512
|
+
|
|
1513
|
+
2. Configure `ng-http-caching` to use the `ng-simple-state` adapter in your `bootstrapApplication`:
|
|
1514
|
+
|
|
1515
|
+
```ts
|
|
1516
|
+
import { provideNgHttpCaching } from 'ng-http-caching';
|
|
1517
|
+
import { withNgHttpCachingNgSimpleState } from 'ng-http-caching/ng-simple-state';
|
|
1518
|
+
|
|
1519
|
+
bootstrapApplication(AppComponent, {
|
|
1520
|
+
providers: [
|
|
1521
|
+
provideNgHttpCaching({
|
|
1522
|
+
store: withNgHttpCachingNgSimpleState(),
|
|
1523
|
+
}),
|
|
1524
|
+
// ... other providers
|
|
1525
|
+
]
|
|
1526
|
+
});
|
|
1527
|
+
```
|
|
1528
|
+
|
|
1529
|
+
You can customize the store configuration (e.g., enable persistence or change the store name) by passing a configuration object to the adapter:
|
|
1530
|
+
|
|
1531
|
+
```ts
|
|
1532
|
+
provideNgHttpCaching({
|
|
1533
|
+
store: withNgHttpCachingNgSimpleState({
|
|
1534
|
+
storeName: 'MyCacheStore',
|
|
1535
|
+
// ... other NgSimpleStateStoreConfig options
|
|
1536
|
+
}),
|
|
1537
|
+
})
|
|
1538
|
+
```
|
|
1539
|
+
|
|
1511
1540
|
## Alternatives
|
|
1512
1541
|
|
|
1513
1542
|
Aren't you satisfied? there are some valid alternatives:
|