@ridder/state
TypeScript icon, indicating that this package has built-in type declarations

1.0.4 • Public • Published

State model

  1. Description
  2. Installation
  3. Usage
  4. Methods
  5. Git repository
  6. Run tests
  7. Build
  8. Publish to npm
  9. Version

1. Description

StateModel and StateComponent are a couple of parent classes used for custom state models services in Angular applications based on RxJs library.

2. Installation

Install the module into your application and save it as a dev dependency in your package.json file

npm install ridder/state --save-dev

3. Usage

In order to use the StateModel you have to to create a custom service model in your application and extend StateModel<T>:

import { Injectable } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { StateModel } from '@ridder/state';

export interface CounterState {
  value: number;
}

@Injectable({
  providedIn: 'root'
})
export class CounterService extends StateModel<CounterState> {

  constructor() {
    super();

    // set initial value of the state if it's required
    this.resetState();
  }

  private initState: CounterState = {
    value: 0
  };

  private state: CounterState = {...this.initState};

  public getState(): ReplaySubject<CounterState> {
    return this.get();
  }

  public setState(properties: CounterState): void {
    this.state = {...this.state, ...properties};
    this.set(this.state);
  }

  public resetState(): void {
    this.setState({...this.initState});
  }

  public increment(): void {
    const newValue = this.state.value + 1;
    this.setState({...this.state, value: newValue});
  }

  public decrement(): void {
    const newValue = this.state.value - 1;
    this.setState({...this.state, value: newValue});
  }
}

Register this model service into a parent store service:

import { Injectable } from '@angular/core';
import { CounterService } from './counter.service';

@Injectable({
  providedIn: 'root'
})
export class StoreService {

  constructor(public counter: CounterService) { }
}

In the components where you want to retrieve the state data via subscribers, don't forget to extend the StateComponent parent class and use this.autoUnsubscribe() method to automatically unsubscribe the subscribers list:

import { Component, OnInit } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { StateComponent } from '@ridder/state';
import { CounterState } from '../../model/counter.service';
import { StoreService } from '../../model/store.service';

@Component({
  selector: 'app-counter',
  templateUrl: './counter.component.html',
  styleUrls: ['./counter.component.css']
})
export class CounterComponent extends StateComponent implements OnInit {
  private counter$: ReplaySubject<CounterState>; // used for async pipe
  private counterValue: number; // used as subscriber

  constructor(private store: StoreService) {
    super();
  }

  ngOnInit() {
    this.counter$ = this.store.counter.getState();

    // unsubscribe automatically on ngOdDestroy
    this.autoUnsubscribe(this.store.counter.getState()
      .subscribe((counterData: CounterState) => {
        this.counterValue = counterData.value;
      }));
  }

  increment() {
    this.store.counter.increment();
  }

  decrement() {
    this.store.counter.decrement();
  }
}

and use the data in your template as subscribers or via Angular async pipe:

<div>
  <h4>Counter value: {{counterValue}}</h4>
  <input type="button" value="Increment" (click)="increment()">
  <input type="button" value="Decrement" (click)="decrement()">

  <h4>
    Counter value (with async pipe): {{(counter$ | async).value}}
  </h4>

  <h4 *ngIf="counter$ | async as counter">
    Counter value (with async pipe and ngIf AS syntax ): {{counter.value}}
  </h4>
</div>

4. Methods

StateModel class

protected getSubject(): ReplaySubject

Creates and returns the ReplaySubject object for the current state model.

Return:
Method returns the ReplaySubject object.

protected set(data: T): void

Set/publish new data through the ReplaySubject object associated with the current state model.

Parameters:
data - data which should be published via ReplaySubject object.

Return:
Method returns nothing - void.

protected get(): ReplaySubject

Retrieves the ReplaySubject object associated with the current state model.

Return:
Method returns the ReplaySubject object associated to the given eventName.

StateComponent class

protected autoUnsubscribe(subscription: Subscription): void

Add the subscription parameter into the subscription list rxSubscriptions$ which will be unsubscribed and destroyed on ngOnDestroy() lifecycle hook event.

Parameters:
subscription - subscription which should be added into the list.

Return:
Method returns nothing - void.

public ngOnDestroy(): void

Unsubscribe all the subscriptions from the rxSubscriptions$ list and destroy them on ngOnDestroy() lifecycle hook event.

Return:
Method returns nothing - void.

5. Git repository

https://github.com/dtxprs/state

6. Run tests

To run the unit tests, use this command:

ng test --code-coverage --project=state

Current test coverage is 100%!

7. Build

To build the final package run this command:

ng build state

The build process will generate the packed sources into the dist folder.

8. Publish to npm

To publish the new version to npm, go into the dist folder:

cd ./dist/state

and publish it to npm:

npm publish --access public

9. Version

1.0.4

Package Sidebar

Install

npm i @ridder/state

Weekly Downloads

0

Version

1.0.4

License

MIT

Unpacked Size

41.4 kB

Total Files

23

Last publish

Collaborators

  • ridder