Layered form using angular ui router

I have looked at this article http://scotch.io/tutorials/javascript/angularjs-multi-step-form-using-ui-router#building-our-angular-app-app.js

and plunkr link http://plnkr.co/edit/M03tYgtfqNH09U4x5pHC?p=preview

My question is how to include form validation in this process, say for the first form where we have a name and email address, how can we validate it first and restrict the transition to the next form if the fields are empty, etc. ... or Invalid email address.

// create our angular app and inject ngAnimate and ui-router 
// =============================================================================
angular.module('formApp', ['ngAnimate', 'ui.router'])

// configuring our routes 
// =============================================================================
   .config(function($stateProvider, $urlRouterProvider) {

$stateProvider

    // route to show our basic form (/form)
    .state('form', {
        url: '/form',
        templateUrl: 'form.html',
        controller: 'formController'
    })

    // nested states 
    // each of these sections will have their own view
    // url will be nested (/form/profile)
    .state('form.profile', {
        url: '/profile',
        templateUrl: 'form-profile.html'
    })

    // url will be /form/interests
    .state('form.interests', {
        url: '/interests',
        templateUrl: 'form-interests.html'
    })

    // url will be /form/payment
    .state('form.payment', {
        url: '/payment',
        templateUrl: 'form-payment.html'
    });

// catch all route
// send users to the form page 
$urlRouterProvider.otherwise('/form/profile');
})

// our controller for the form
// =============================================================================
.controller('formController', function($scope) {

// we will store all of our form data in this object
$scope.formData = {};

// function to process the form
$scope.processForm = function() {
    alert('awesome!');  
};

});

      

+3


source to share


1 answer


So the simple answer is that you can just use angularjs validation mechanisms every time you are about to go to the next step. This works because in this example we are changing the contents of the entire form every time we change a step on the form. Because of this, if you name a form, for example "myMultiStepForm", you can use myMultiStepForm. $ Valid to see if the form is valid. Therefore, whenever the user is about to change this step, you can call a function to check if the form is valid. For example:

Form with form name:

<form name="myMultiStepForm" id="signup-form" ng-submit="processForm()">
    <!-- our nested state views will be injected here -->
    <div id="form-views" ui-view></div>
</form>

      

Button to go to the next section:

<a ng-click="goToNextSection(myMultiStepForm.$valid)" class="btn btn-block btn-info">
    Next Section <span class="glyphicon glyphicon-circle-arrow-right"></span>

      

Go to next section function:

$scope.goToNextSection=function(isFormValid) {
      // If form is valid go to next section
      if(isFormValid) {
        $state.go(nextState($state.current.name));
      }
};

      

Additional notes to improve this and clarify the answer:

First of all it seems to me that you are starting a new project with forms, so I would go with the latest version of angularjs (at the moment this is the 3rd candidate release 3) as it makes several improvements with regard to how we can work with forms (for example , it improves the validation mechanisms). Since this is a release candidate, they fix bugs most often and the API should be stable. You can read about it here .

Here is a plunkr link with a validated example http://plnkr.co/edit/y7XL9lGxB3wZTIAcxUVS?p=preview

This example is far from complete. I just added validation to the email field and changed the behavior of the next button to illustrate the validation of the form validation. I am using angularjs 1.3 validation (you can change it to 1.2 if you like, but that will be a lot more logic), I added that the validation is on the email field and only works for the first step. So if you try to click further, you won't be able to until you enter a valid email address. Then you can click next, and it will take you to the next one (which is where I left off with checking, so the rest of the example is pointless right now).

This is how I added email validation to the field:



<div class="form-group">
    <label for="email">Email</label>
    <input type="email" class="form-control" name="email" ng-model="formData.email" required>
    <div ng-messages="myMultiStepForm.email.$error" ng-if="formStepSubmitted || myMultiStepForm.email.$touched">
      <div ng-message="required">The email is required</div>
      <div ng-message="email">Not a valid email</div>
    </div>
</div>

      

An email is required and it must be a valid email address. Otherwise, you will get an error if you put in an invalid value or try to submit the form.

To include form validation in the process, you simply add the validation rules you want and for each call to the Next Step button, you validate the current version of the form and only progress if it is valid.

To do this, I changed the button to go to the next step so that instead of ui-sref it was ng-click:

<a ng-click="goToNextSection(myMultiStepForm.$valid)" class="btn btn-block btn-info">
    Next Section <span class="glyphicon glyphicon-circle-arrow-right"></span>
</a>

      

Note that I am also passing myMultiStepForm. $ valid, myMultiStepForm is the name I gave this form. $ valid will be true if the form is valid and false otherwise.

Then, in my controller, I have a function that checks if the form is valid and only allows state change in that case:

$scope.goToNextSection=function(isFormValid) {
      // set to true to show all error messages (if there are any)
      $scope.formStepSubmitted = true;
      if(isFormValid) {
        // reset this for next form
        $scope.formStepSubmitted = false;

        // mark the step as valid so we can navigate to it via the links
        updateValidityOfCurrentStep(true /*valid */);

        // we only go to the next step if the form is valid
        $state.go(nextState($state.current.name));
      } else {
        // mark the step as valid so we can navigate to it via the links
        updateValidityOfCurrentStep(false /*not valid */);
      }
    };

      

Given that the user can use the links at the top to navigate, you can also intercept the stateChangeStart event and see if the previous step is valid and only allow navigation if the previous step is valid.

.value('formSteps', [
  {uiSref: 'form.profile', valid: false},
  {uiSref: 'form.interests', valid: false},
  {uiSref: 'form.payment', valid: false}

  ])
.run([
            '$rootScope',
            '$state',
            'formSteps',
            function($rootScope, $state, formSteps) {

              // Register listener to watch route changes
                $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {

                    var canGoToStep = false;
                    // only go to next if previous is valid
                    var toStateIndex = _.findIndex(formSteps, function(formStep) {
                      return formStep.uiSref === toState.name;

                    });

                    if(toStateIndex === 0) {
                      canGoToStep = true;
                    } else {
                      canGoToStep = formSteps[toStateIndex - 1].valid;
                    }

                    // Stop state changing if the previous state is invalid
                    if(!canGoToStep) {
                        // Abort going to step
                        event.preventDefault();
                    }
                });


            }


        ])

      

Note that I created a value called formSteps, which is an array that has all the steps correct. This confidence is updated in the controller whenever you hit the next step. You can also do this when you change the value of the field so that the validity of the form step is not affected by a user click.

+9


source







All Articles