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

@onepointfour-npm/ngx-state-machine

v1.2.0

Published

A Mealy State Machine built to work with as an extension of Angular

Downloads

5

Readme

Ngx State Machines

ExampleDiagram

This is an attempt to use state machines as an extension of the Angular platform. The most important thing about this experiment for me, was to make sure that the actions for each state were part of the Angular component itself, and won't have to be called via a key lookup layer.


Installing

  • npm i @onepointfour-npm/ngx-state-machine --save or yarn add @onepointfour-npm/ngx-state-machine

Usage

To use the state machine in an Angular component, you have to extend the class of the component you want to use it in with the Machine base class.

import { Machine } from '@onepointfour-npm/ngx-state-machine';


export class AppComponent extends Machine implements OnInit {
 ...
}

next you will have to set up you states for the components. You do this by specifing your parameters in the arguments of you super call. The first argument will be the name of your initial state. The following arguments will be the definitions of the states that your component can be in. You can have as many states as you want.

import { Machine, StateDeclaration } from '@onepointfour-npm/ngx-state-machine';

export class AppComponent extends Machine implements OnInit {
  constructor() {
    super(
      'idle',
      new StateDeclaration('idle'),
      new StateDeclaration('fetching'),
      new StateDeclaration('done')
    );
  }
}

The StateDeclaration class can actually take up to three arguments (statename, from, to), but for now we will just use statename.

So, we now have three states in our component: an idle state, a fetching state, and a done state. Now we need to create actions for those states. To do this, we use the @StateAction decorator.

import { Machine, StateDeclaration, StateAction } from '@onepointfour-npm/ngx-state-machine';

export class AppComponent extends Machine implements OnInit {
  constructor() {
    super(
      'idle',
      new StateDeclaration('idle'),
      new StateDeclaration('fetching'),
      new StateDeclaration('done')
    );
  }

  @StateAction('idle')
  public onButtonClick(): void { ... }

  @StateAction('fetching')
  public onFetchSuccess(data: any): void { ... }

  @StateAction('done')
  public displayFetchedData(date: any): void { ... }

  @StateAction('done')
  public reset(): void { ... }
}

We now have the boilerplate of our component, so we can begin implementing a flow. To do this, let's start by defining the second and third parameters of our StateDeclaration. Those parameters are from and to. As you can probably guess, these parameters allow you to control the exact flow of your state by letting you specify what states can be activated by or can activate other states. For example, our component will look something like this.

import { Machine, StateDeclaration, StateAction } from '@onepointfour-npm/ngx-state-machine';

export class AppComponent extends Machine implements OnInit {
  constructor() {
    super(
      'idle',
      new StateDeclaration('idle', 'done', 'fetching'),
      new StateDeclaration('fetching', 'idle', 'done'),
      new StateDeclaration('done', 'fetching', 'idle')
    );
  }

  ...
}

This may look a bit ridiculous right now becuase the states for this component are so simple, but when you are dealing with a lot of states, this will be a very useful tool. Now that we have our rules set up, we can implement our logic. To do this, we will make use of the nextstate provided by the Machine class. This will be used to moved between states. In our onButtonClick function let's add the following functionality.

import { Machine, StateDeclaration, StateAction } from '@onepointfour-npm/ngx-state-machine';

export class AppComponent extends Machine implements OnInit {
  ...

  @StateAction('idle')
  public onButtonClick(): void {
    this.nextstate('fetching');

    setTimeout(() => {
        this.onFetchSuccess(JSON.stringify({ message: 'YAY! It worked' }));
    }, 5000);
  }

  ...
}

What we are doing here, is setting the new state to fetching, simulating a call to an api, and then calling the onFetchSuccess function (which is one of the functions for the fetching state). Now let's implement the rest of the functions.

import { Machine, StateDeclaration, StateAction, StateProp } from '@onepointfour-npm/ngx-state-machine';

export class AppComponent extends Machine implements OnInit {
  @StateProp('done')
  public data: any;
  ...

  @StateAction('idle')
  public onButtonClick(): void {
    this.nextstate('fetching');

    setTimeout(() => {
        this.onFetchSuccess(JSON.stringify({ message: 'YAY! It worked' }));
    }, 5000);
  }

  @StateAction('fetching')
  private onFetchSuccess(data: any): void {
      this.nextstate('done')
      console.log(data);
      this.displayFetchedData(JSON.parse(data));
  }

  @StateAction('done')
  private displayFetchedData(data: any): void {
      this.data = data;
  }

  @StateAction('done')
  public reset(): void {
      this.nextstate('idle');
      this.data = void 0;
  }
}

Now let's implement our view.

<h1>Current State: <i>{{ state }}</i></h1>

<button *ngIf="state === 'idle'" (click)="onButtonClick()">
  CLICK ME
</button>

<div *ngIf="state === 'done'">
  <br />
  {{ data | json }}
  <br />
  <br />
</div>

<button *ngIf="state === 'done'" (click)="reset()">
  RESET
</button>

To-Do

  • ~~Add decorator for state specific properties~~
  • ~~Multiple states per action or property~~
  • ~~Return to initial state method~~
  • ~~Hooks for state changes~~
  • More detailed error handling