Search code examples
angularjscookiesangular-ui-routerangularjs-components

AngularJS 1.6.1: What is the best way to store form-data locally for a large, multi-step form?


Hi I have a pretty large (and growing) AngularJS form that consists of several pages of inputs. On the back end there is only a single post endpoint that saves to the db. I am currently using $cookies to locally save the data from prior steps in case the user wants to go back and edit something. Is it dangerous or a bad idea to do it this way? It seems to work really well so far but I am concerned I am doing something stupid that I don't know about.

I am using components and angular-ui-router to route views like this:

namespace NewClientForm {
angular
    .module('app', ['ui.bootstrap', 'ngCookies', 'ui.router', 'google.places', 'cwill747.phonenumber'])
    .config(function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/clientInfo');
        $stateProvider
            .state('clientInfo', {
                url: '/clientInfo',
                template: '<h3>Client Info</h1></br><clientinfo></clientinfo>'
            })
            .state('billing', {
                url: '/billing',
                template: '<h3>Billing</h1></br><billing></billing>'
            })
            .state('licensing', {
                url: '/licensing',
                template: '<h3>Licensing</h1></br><licensing></licensing>'
            })
            .state('users', {
                url: '/users',
                template: '<h3>Add Users</h1></br><users></users>'
            })
            .state('quoting', {
                url: '/quoting',
                template: '<h3>Quoting Preferences</h1></br><quoting></quoting>'
            });
    })
    .component('billing', {
        templateUrl: 'app/form/templates/billing.html',
        bindings: {},
        controller: 'FormController'
    })
    .component('clientinfo', {
        templateUrl: 'app/form/templates/clientInfo.html',
        bindings: {},
        controller: 'FormController'
    })
    .component('licensing', {
        templateUrl: 'app/form/templates/licensing.html',
        bindings: {},
        controller: 'FormController'
    })
    .component('users', {
        templateUrl: 'app/form/templates/users.html',
        bindings: {},
        controller: 'FormController'
    })
    .component('spinner', {
        templateUrl: 'app/form/templates/spinner.html',
        bindings: {},
        controller: 'FormController'
    })
    .component('quoting', {
    templateUrl: 'app/form/templates/quoting.html',
    bindings: {},
    controller: 'FormController'
});};

Then I am using the putObject method on $cookies to save the data like this:

Controller:

save = (name: string, obj: any, configObj: any, state: string) => {
        this.$cookies.putObject(name, obj, configObj);
        this.$log.debug(this.$cookies.getAll());
        this.$state.go(state);
    };

View:

<button class="btn btn-primary" ng-if="!clientInfoForm.$invalid"
        style="float:right;" 
        ng-click="$ctrl.save('clientInfo', $ctrl.clientInfo, {expires:$ctrl.expireDate}, 'billing')">
        Next
</button>

Lastly, I am using $cookies.getObject in my function to populate my ng-model(s) from the $cookie:

populateFromCookie = () => {
        this.clientInfoCookie = this.$cookies.getObject('clientInfo');            
        if (this.clientInfoCookie) {
            if (this.clientInfoCookie.hasOwnProperty('FirstName')) {
                this.clientInfo.FirstName = this.clientInfoCookie.FirstName;
            };
            if (this.clientInfoCookie.hasOwnProperty('LastName')) {
                this.clientInfo.LastName = this.clientInfoCookie.LastName;
            };
            if (this.clientInfoCookie.hasOwnProperty('title')) {
                this.clientInfo.title = this.clientInfoCookie.title;
            };
        };
    };  

Any constructive criticism or suggestions on how I could improve this would be much appreciated. Thanks!


Solution

  • I have dealt with exactly the same situation and with a lot of data I found using sessionStorage was the best solution for me.

    Have a look at this post on What is the max size of localStorage values?

    Simply serialize to store and de-serialize on retrieval and your good to go.

    Is it dangerous or a bad idea to do it this way?

    If you are dealing with sensitive information, of course you want to get it to the server as soon as you can and then remove it from your chosen method of storage.

    If a user is entering data, they would expect their data to be there for the duration of their session in most cases anyway. sessionStorage is good as it will only be accessible while and by the window that created it is open.