npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@state-management/ngx-state-machine

v1.0.6

Published

An Angular wrapper for simple-state-machine library, integrates the simple-state-machine with Angular’s dependency injection system

Downloads

281

Readme

ngx-state-machine

npm version Build Status MIT License

ngx-state-machine is an Angular wrapper for the simple-state-machine library. It integrates the state machine into Angular applications by making the StateMachine injectable as a service. You can find the complete documentation of the core library, here: Simple State Machine Documentation

About This Project

Managing state in Angular applications often involves using complex libraries or relying on services with shared state. ngx-state-machine simplifies state management by integrating simple-state-machine with Angular’s dependency injection system.

This project is part of the state-management suite, which includes:

By decoupling state management from UI components, ngx-state-machine promotes cleaner, more maintainable, and testable Angular code. Since the state can be modified from within a Command only, this will result in business logic moving out of UI components into command classes.

Implementation Example

  • Sample Angular project that you can clone. It is a fully working example with unit tests, showcasing the use of ngx-state-machine.

Features

State management code, that is lot less scary, easy to read, easy to trace, and very easy to change and unit test.

Traceability:

This single most important feature that we wanted to design correctly is traceability of code. When trying to identify an issue, we should be able to go through the code, and identify the cause, without having to open ten different files. We should be able to use the IDE's "find references" or even the simple Find (Ctrl + F) feature to quickly identify what StateKeys are changed by which Commands.

This is invaluable while identifying issues in code. This also reduces the dependency on debugging tools and time spent in debugging.

Most importantly the state management code looks a lot less scary, it is easy to read, and it is very easy to change and unit test.

Important Technical Features:

  • State Injection: Makes StateMachine injectable as a singleton service.
  • Command Dispatching: Allows encapsulating state modification code within Commands. Dispatch commands to modify global state. State can only be changed as part of execution of business logic contained in Command class.
  • Observability: Allow UI components to reactively observe state changes.

Compatibility

  • This package will work with Angular 12.x and above. It has been tested with Angular 18.x.
  • For unit testing, this library supports Jest 26.x and higher.

Installation

Install via npm:

npm install @state-management/ngx-state-machine

OR

yarn add @state-management/ngx-state-machine

Usage

Adding StateManagement

There are two ways to add the State Management module to your application.

Option 1: Add the NgxStateMachineModule to your Angular application:

import { NgModule } from '@angular/core';
import { NgxStateMachineModule } from '@state-management/ngx-state-machine';

@NgModule({
  imports: [
    NgxStateMachineModule
  ],
})
export class AppModule {}

Option 2: For standalone components, include it as provider:

import { Component } from '@angular/core';
import {provideStateMachine} from '@state-management/ngx-state-machine';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [NgxStateMachineModule], 
  // NOTE: you do not need "providers", if you use option 1: Add the NgxStateMachineModule
  providers: [provideStateMachine()],
  template: '<router-outlet></router-outlet>',
})
export class AppComponent {
    constructor(private stateMachine: StateMachine) {
    }
}

StateKeys.constants.ts

Create a constants file to store all state keys, for easy tracing of state changes in application

import {StateKey} from '@state-management/ngx-state-machine';

export class StateKeyConstants {
    // NOTE: the generics, "<number>" of the StateKey defines the data type of the value stored against this key.
    public static readonly COUNTER_KEY = new StateKey<number>('counter');
}

Command class

Create a Command, to perform application logic, and update the state.

Note: Only Command can change the state.
import {Command} from '@state-management/ngx-state-machine'
import {StateKeyConstants} from './constants/state-keys.constants';

export interface UpdateCounterParam {changeBy: number}

// NOTE: the generics, "<UpdateCounterParam>" of the Command defines the data type of the parameter of `execute` method.
export class UpdateCounter extends Command<UpdateCounterParam> {
  execute(params:UpdateCounterParam) {
    const currentValue = this.getLatest(StateKeyConstants.COUNTER_KEY) || 0 ;
    // NOTE: only Command can change the state.
    this.putState(StateKeyConstants.COUNTER_KEY, currentValue + params.changeBy);
    
    // Note: Call your service class here, to execute logic, or make API calls.
  }
}

Dispatch the command

Use the injected StateMachine to dispatch Command from UI.
StateMachine will execute the command, and its logic will change the state.

Note: Only Command can change the state.
import { Component } from '@angular/core';
import {StateMachine} from '@state-management/ngx-state-machine';
import {UpdateCounter} from '../commands/update-counter.command';

@Component({
  selector: 'app-counter-control',
  standalone: true,
  template: `
  <div>
      <button (click)="increment()">Increment</button>
      <button (click)="decrement()">Decrement</button>
  </div>`,
  styleUrl: './counter-control.component.scss'
})
export class CounterControlComponent {
  constructor(private stateMachine: StateMachine) {
  }

  increment(): void {
    // NOTE: the construtor argument of Command, will be passed as argument to its "execute" method.
    this.stateMachine.dispatch(new UpdateCounter({changeBy: 1}));
  }

  decrement(): void {
    this.stateMachine.dispatch(new UpdateCounter({changeBy: -1}));
  }

}

Listen to state changes

Use the injected StateMachine to observe state changes and render UI accordingly.

import {Component} from '@angular/core';
import {StateKeyConstants} from '../constants/state-keys.constants';
import {AsyncPipe} from '@angular/common';
import {Observable} from 'rxjs';
import {StateMachine} from '@state-management/ngx-state-machine';

@Component({
  selector: 'app-counter-display',
  standalone: true,
  imports: [AsyncPipe],
  template: ` <p>counter value is: {{(counter$|async)}}</p> `
})
export class CounterDisplayComponent {
  protected counter$:Observable<number> | undefined;

  constructor(private stateMachine: StateMachine) {
    // Use the injected StateMachine to observe state changes.
    this.counter$ = this.stateMachine.observe(StateKeyConstants.COUNTER_KEY);
  }
  
}

API Documentation

The ngx-state-machine is an Angular-specific wrapper for the core library, simple-state-machine. It does not add any new classes or interfaces. This wrapper allows injecting the StateMachine as a service into Angular components. You can find the API documentation of the core library, here: Simple State Machine Documentation

Contributing

We welcome contributions! Please open an issue or submit a pull request if you’d like to improve the library.

How to Contribute

1. Fork the Repository:

Visit the state-machine-react GitHub repository. Click the "Fork" button to create a copy of the repository under your GitHub account.

2. Clone the Fork:

git clone https://github.com/state-management/state-machine-react.git
cd state-machine-react

3. Create a Feature Branch:

git checkout -b feature/add-react-wrapper-feature

4. Make Your Changes:

Add or update code, write tests, and ensure the changes are well-documented. Run Tests Locally, Ensure all existing and new tests pass e:

npm install
npm test

5. Commit and Push Your Changes:

Write a clear and concise commit message:

git add .
git commit -m "Add new wrapper feature to state-machine-react"
git push origin feature/add-react-wrapper-feature

6. Create a Pull Request:

Go to your fork on GitHub and click the “New Pull Request” button. Provide a description of your changes and any additional context.