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 CHANGED
@@ -1,4 +1,4 @@
1
- # NgSimpleState [![Build Status](https://app.travis-ci.com/nigrosimone/ng-simple-state.svg?branch=main)](https://app.travis-ci.com/nigrosimone/ng-simple-state) [![Coverage Status](https://coveralls.io/repos/github/nigrosimone/ng-simple-state/badge.svg?branch=main)](https://coveralls.io/github/nigrosimone/ng-simple-state?branch=main) [![NPM version](https://img.shields.io/npm/v/ng-simple-state.svg)](https://www.npmjs.com/package/ng-simple-state) [![Maintainability](https://api.codeclimate.com/v1/badges/1bfc363a95053ecc3429/maintainability)](https://codeclimate.com/github/nigrosimone/ng-simple-state/maintainability)
1
+ # NgSimpleState [![NPM version](https://img.shields.io/npm/v/ng-simple-state.svg)](https://www.npmjs.com/package/ng-simple-state) [![Maintainability](https://qlty.sh/gh/nigrosimone/projects/ng-simple-state/maintainability.svg)](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
- ### Batch Updates
1284
+ ### Transactions
1287
1285
 
1288
- Group multiple state updates into a single emission to improve performance:
1286
+ Execute operations with automatic rollback on error using `withTransaction`:
1289
1287
 
1290
1288
  ```ts
1291
- import { Injectable, Signal } from '@angular/core';
1292
- import { NgSimpleStateBaseSignalStore, NgSimpleStateStoreConfig, batchState } from 'ng-simple-state';
1293
-
1294
- export interface FormState {
1295
- name: string;
1296
- email: string;
1297
- phone: string;
1298
- isValid: boolean;
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
- storeConfig(): NgSimpleStateStoreConfig<FormState> {
1305
- return { storeName: 'FormStore' };
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
- initialState(): FormState {
1309
- return { name: '', email: '', phone: '', isValid: false };
1310
- }
1314
+ ### Debounced Updates
1311
1315
 
1312
- selectForm(): Signal<FormState> {
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
- // Batch multiple updates - only one emission at the end
1317
- updateAllFields(name: string, email: string, phone: string): void {
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
- // Regular updates (each triggers an emission)
1327
- setName(name: string): void {
1328
- this.setState({ name });
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
- setEmail(email: string): void {
1332
- this.setState({ email });
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
- private validateForm(name: string, email: string, phone: string): boolean {
1336
- return name.length > 0 && email.includes('@') && phone.length >= 10;
1337
- }
1338
- }
1332
+ // Force immediate update
1333
+ flush();
1334
+
1335
+ // Cancel any pending update
1336
+ cancel();
1339
1337
  ```
1340
1338
 
1341
- Usage in component:
1339
+ ### Throttled Updates
1340
+
1341
+ Limit update frequency with `createThrottledUpdater`. At most one update per time window:
1342
1342
 
1343
1343
  ```ts
1344
- @Component({
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
- submitForm(): void {
1365
- // All updates batched into single emission
1366
- this.store.updateAllFields(this.name, this.email, this.phone);
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
  ![Redux DevTools](https://github.com/nigrosimone/ng-simple-state/blob/main/projects/ng-simple-state-demo/src/assets/dev-tool.gif?raw=true)
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: