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

angular-state-machine

v1.0.1

Published

AngularJS service to implement a finite state machine.

Downloads

12

Readme

AngularJS State Machine

Forked from https://github.com/tafax/angular-state-machine by Matteo Tafani Alunno

It is an AngularJS module to implement a Finite-State Machine. It can be useful in many situations where the state of an app(or module) follows specific paths. For example, it is very useful to implement a login module in a single page web application where the entire app depends on the login state and/or on the permissions of an user. It's very simple also handling multiple challenges login or changing the user permissions/routing according to user profile. The module provides features to manage those kind of situations with a simple configuration, offering an extensible and easy-maintainable way to work.

Features

  • Create a state machine using a JSON-like configuration with a JS object.
  • Define transitions using dictionary syntax.
  • Define multiple predicates to choose which path the machine has to follow.
  • Perform an action for each state.
  • Change the configuration at any time to add new states or change the transitions.

Installation

You can download this by:

After installation, import the module in your app.

var app = angular.module('myApp', ['FSM']);

Dependecies

This module is dependency free.

Configuration

As a general consideration you need to inject the state machine provider in your app configuration.

app.config(['stateMachineProvider', function(stateMachineProvider) {
    // Your code...
}]);

Very simple FSM

We want to create a state machine to handle the user login in a single page application. Our states will be loggedIn or notLoggedIn. To perform a transition between the states we need to send a request and receive a 201 status code from the server that indicates a successful login.

stateMachineProvider.config({
    init: { // This is the initial state(the not_logged_in one, but you have to call it 'init'). It is mandatory.
        transitions: {
            201: 'loggedIn'
        }
    },
    loggedIn: {
        // Right now the loggedIn state is empty.
    }
});

Afterwards, in the app run method we have to initialize the machine.

myApp.run(['stateMachine', function(stateMachine) {
    stateMachine.initialize();
}]);

The machine is ready to receive messages. If the login was successful, a message 201 will be sent to the machine by invoking stateMachine.send('201');, so the machine now is in the loggedIn state.

Adding error handling

The previous machine is not so useful, but we can add some states to provide a more realistic usage of that configuration. Let's add a state to handle a login error that the server returns if the response code is 401.

stateMachineProvider.config({
    init: { // This is the initial state(the not_logged_in one, but you have to call it 'init'). It is mandatory.
        transitions: {
            201: 'loggedIn',
            401: 'loginError'
        }
    },
    loggedIn: {
        // Right now the loggedIn state is empty.
    },
    loginError: {
        action: ['myErrorHandler', 'params', function(myErrorHandler, params) {
            myErrorHandler.handle(params.response.code, params.response.data);
        }]
    }
});

We added a new key called action that is executed when the machine arrives in the related state. The action is handled by the AngularJS injector so you can inject each service you want to use. In this case we injected a custom error handler to manage the error. We injected also params that is a special key to retrieve the parameters passed to the method send when it is invoked. So, by calling stateMachine.send('401', {response: response});, we will change the state to loginError and the machine will call the action in which the params will be available to be used.

Predicates for the transitions

In some cases when an error returns from the server for a given HTTP status code, the server provides an application code that the app could use to manage different kind of handling. In this case we can use an application code as a transition message instead of the status code or we can use the predicate feature.

stateMachineProvider.config({
    init: { // This is the initial state(the not_logged_in one, but you have to call it 'init'). It is mandatory.
        transitions: {
            201: 'loggedIn',
            401: [{
                to: 'loginError',
                predicate: function(params) {
                    return params.data.appCode <= 4015;
                }
            }, {
               to: 'loginConfirmation',
               predicate: function(params) {
                   return params.data.appCode == 4016;
               }
            }]
        }
    },
    loggedIn: {
        // Right now the loggedIn state is empty.
    },
    loginConfirmation: {
        // Right now the loggedIn state is empty.
    },
    loginError: {
        action: ['myErrorHandler', 'params', function(myErrorHandler, params) {
            myErrorHandler.handle(params.response.code, params.response.data);
        }]
    }
});

In this case we added two transitions for a single message 401. Each one has a predicate that returns true or false depending of the application code that the server returned. If it is less than 4015 the machine goes to the loginError state, but if it is 4016 the machine goes to loginConfirmation so you can use the action to display, for example, a confirmation page to the user.

More complex FSM

The examples above are only some simplified cases that the module can handle or, better, you can manage using a state machine. Anyway, by mixing the features we saw above, you can implement more complex FSM to handle many different kind of cases.

Contributing

I love contributors :). If you think the module can be improved or you want to add a very cool feature, feel free to send a pull request at any time. Anyway, please respect the coding standard of the rest of code and remember to add the tests to cover your changes.

License

MIT