Click here to Skip to main content
15,892,927 members
Articles / AngularJs

Series 2: Build an Angular 1 Multi-Step Wizard using UI-Router 1.0 – Part 1

Rate me:
Please Sign up or sign in to vote.
1.44/5 (2 votes)
31 Jan 2017CPOL5 min read 10.3K   4  
This is the first part of Introducing Angular Multi-Step Wizard using UI-Router Series 2.

This is the first part of Introducing Angular Multi-Step Wizard using UI-Router Series 2. You will learn how to build a multi-step wizard using the following technologies:

The source code for this tutorial series is published on GitHub. Demo application is hosted in Microsoft Azure.

Part 1: Create a SPA in UI-Router 1.0 with Angular 1.5+ component-based architecture

In the previous tutorial series, we created the Multi-Step Wizard in UI-Router legacy v 0.x for Angular 1. In this tutorial, we will continue to use Visual Studio Code to build the initial structure of the Single-Page Application (SPA) using UI-Router 1.0 with Angular 1.5+ component-based architecture.

Client-Side Technologies

The application structure, styles, and patterns follow the recommendations outlined in John Papa’s Angular 1 Style Guide. The application idea is inspired by Scotch.io’s tutorial.

Task 1. Set up the Project Structure

I prefer to organize my project based on features/modules. Building a maintainable, scalable, and well-organized application should start from the beginning. Using DRY and SRP patterns, we will create smaller code files that each handle one specific job. This approach has helped me personally to locate, enhance, and debug requested features from clients quickly.

Let’s creating folders and copying files to C:\_tutorials\ng-multi-step-wizard-ui-router1 from GitHub as listed below:

ng-multi-step-wizard-ui-router1         // Project folder      
    |--app
        |--address                      // Address feature
        |--form                         // Form feature
        |--personal                     // Personal feature
        |--result                       // Result feature
        |--work                         // Work feature
    |--content                          
        |--css
            |--riliwan-rabo.css
            |--style.css
        |--images
            |--favicon.ico

Task 2. Create startup page

  1. Add the index.html file to the ng-multi-step-wizard-ui-router1 folder.

  2. Replace the code in this file with the following:

    <!DOCTYPE html>
    <html lang="en" ng-app="wizardApp">
    <head>
        <meta charset="utf-8" />
    	<meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="description" content="">
        <meta name="author" content="">
    
        <title>Multi-Step Wizard using AngularJS 1.5+ And UI-Router 1.0 by Cathy Wun</title>
    
        <!-- CSS Files -->
        <link rel="icon" type="image/png" href="content/images/favicon.ico" />
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
    	<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.css" />
        <link rel="stylesheet" href="content/css/riliwan-rabo.css" />
        <link rel="stylesheet" href="content/css/style.css" />
        
        <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
        <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
        <!--[if lt IE 9]>
            <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
            <script src="//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
        <![endif]-->
    
    </head>
    <body>
    
        <!-- views will be injected here -->
        <section style="background:#efefe9;">
            <div class="container">
                <div ui-view></div>
            </div>
            
        </section>
    
        <!-- Vendor js libraries -->
        <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/1.0.0-rc.1/angular-ui-router.min.js"></script>
        
        <!-- Bootstrapping -->
        <script src="app/app.module.js"></script>
    
        <!-- Wizard - Form feature -->
        <script src="app/form/form.component.js"></script>
        <script src="app/form/form.controller.js"></script>
        <script src="app/form/formData.value.js"></script>
    
        <!-- Wizard - Personal feature -->
        <script src="app/personal/personal.component.js"></script>
        <script src="app/personal/personal.controller.js"></script>
    
        <!-- Wizard - Work feature -->
        <script src="app/work/work.component.js"></script>
        <script src="app/work/work.controller.js"></script>
    
        <!-- Wizard - Address feature -->
        <script src="app/address/address.component.js"></script>
        <script src="app/address/address.controller.js"></script>
    
        <!-- Wizard - Result feature -->
        <script src="app/result/result.component.js"></script>
        <script src="app/result/result.controller.js"></script>
    
    </body>
    </html>

    The index.html file serve as our startup page. It loads all our resources (.css and .js) and adds a ui-view directive of UI-Router to inject our views. It also uses ng-app directive to designate wizardApp as the root module of our Angular application.

Task 3. Create our application and routes

The app.module.js file creates our angular app and configures state-based routes. It is defined inside our root module named wizardApp,

  1. Add the app.module.js file to the app folder.

  2. Replace the code in this file with the following:

    (function() {
        'use strict';
    
        // Creating our angular app and inject ui-router 
        // =============================================================================
        var app = angular.module('wizardApp', ['ui.router'])
    
        // Configuring our states 
        // =============================================================================
        app.config(['$stateProvider', '$urlRouterProvider',
    
            function($stateProvider, $urlRouterProvider) {
    
                // For any unmatched url, redirect to /wizard/personal
                $urlRouterProvider.otherwise('/form/personal');
        
                $stateProvider
                    // PARENT STATE: form state
                    .state('form', {
                        url: '/form',
                        component: 'formComponent'
                    })
            
                    // NESTED STATES: child states of 'form' state 
                    // URL will become '/form/personal'
                    .state('form.personal', {
                        url: '/personal',
                        component: 'personalComponent'
                    })
            
                    // URL will become /form/work
                    .state('form.work', {
                        url: '/work',
                        component: 'workComponent'
                    })
            
                    // URL will become /form/address
                    .state('form.address', {
                        url: '/address',
                        component: 'addressComponent'
                    })
    
                    // URL will become /form/result
                    .state('form.result', {
                        url: '/result',
                        component: 'resultComponent'
                    })
            }
        ]);
           
    })();

    Line 6 is loading our app-specific module (ui.router) in the app.

  3. Lines 19 – 47 have our state-based routes created. Each state has its own url and component.

    The form state is the parent state to the following child states:

    • form.personal
    • form.work
    • form.address
    • form.result

    When one of the child states is active, the parent state is implicitly active as well. Child state will route to its component. The child component is placed inside its parent’s ui-view.

    Explaining UI-Router

Task 4. Create the Form feature

The Form feature contains the following files:

  • form.component.js: is a component controls the view, the controller, and input data for the Form
  • formData.value.js: contains input data
  • form.controller.js: is a controller contains the properties and functions that are bound to the Form view. It also contains the presentation logic for the Form view, and is the glue between the data and the view.
  • form.html: is an AngularJS HTML template that defines the view for the Form

Task 5. Add component to the Form feature

  1. Add the form.component.js file to the form folder.

  2. Replace the code in this file with the following:

     

    (function () {
        'use strict';
     
        angular
            .module('wizardApp')
            .component('formComponent', {
                templateUrl:  'app/form/form.html',
                controller: 'FormController',
                controllerAs: 'vm'
            })
    })();
  3. The FormComponent is defined inside our root module named wizardApp. It has its own templateUrl (view file) and controller.

Task 6. Add data model to the Form feature

  1. Add the formData.value.js to the form folder.

  2. Replace the code in this file with the following:

    (function () {
        'use strict';
     
        angular
            .module('wizardApp')
            .value('FormDataModel', FormDataModel);
     
        function FormDataModel() {
            this.firstName = '';
            this.lastName = '';
            this.email = '';
            this.work = 'Code';
            this.street = '';
            this.city = '';
            this.state = '';
            this.zip = '';
        }
    })();

    The FormDataModel is defined inside a root module named wizardApp. It contains all input data.

Task 7. Add controller and view to the Form feature

  1. Add the form.controller.js file to the form folder.

  2. Replace the code in this file with the following:

    (function () {
        'use strict';
     
        angular
            .module('wizardApp')
            .controller('FormController', FormController);
     
        FormController.$inject = ['FormDataModel'];
     
        function FormController(FormDataModel) {
            var vm = this;
            vm.title = 'Multi-Step Wizard';
            // we will store all of our form data in this object
            vm.formData = new FormDataModel();
    
            vm.$onInit = activate;
            vm.getData = getData;
            
            ////////////////
    
            function activate() {
                console.log(vm.title + ' loaded!');
            }
    
            function getData() {
                return vm.formData;
            }
        }
    })();

     

    The FormController is defined inside our root module named wizardApp. We will store our data into formData object. After the form feature has been loaded successfully, we use the console.log() method to write Multi-Step Wizard loaded! into the browser console. To see the result, activate the browser console with F12, and select Console in the menu.

  3. Add the form.html file to the form folder.

  4. Replace the code in this file with the following:

    <div class="row">
        <div class="board">
            <!-- Circular Tab Area -->
            <div class="board-inner" id="status-buttons">
                <ul class="nav nav-tabs" id="myTab">
                    <div class="liner"></div>
    
                    <!-- circular user icon -->
                    <li>
                        <a ui-sref-active="active" ui-sref=".personal" data-toggle="tab" title="personal">
                            <span class="round-tabs one">
                                
                            </span>
                        </a>
                    </li>
    
                    <!-- circular tasks icon -->
                    <li>
                        <a ui-sref-active="active" ui-sref=".work" data-toggle="tab" title="work">
                            <span class="round-tabs two">
                                
                            </span> 
                        </a>
                    </li>
    
                    <!-- circular home icon -->
                    <li>
                        <a ui-sref-active="active" ui-sref=".address" data-toggle="tab" title="address">
                            <span class="round-tabs three">
                                
                            </span>
                        </a>
                    </li>
    
                    <!-- circular ok icon -->
                    <li>
                        <a ui-sref-active="active" ui-sref=".result" data-toggle="tab" title="result">
                            <span class="round-tabs four">
                                
                            </span>
                        </a>
                    </li>
                    
                </ul>
                <div class="clearfix"></div>
            </div>
            <!-- End Circular Tab Area -->
    
            <!-- Content Area -->
            <div class="tab-content">
                <!-- Nested view  -->
                <div ui-view></div>
            </div>
            <!-- End Content Area -->
        </div>
    
        <!-- For Debugging: show our formData as it is being typed -->
        <pre>{{ vm.formData | json }}</pre>
    
    </div>

    The form.html uses Bootstrap for quick styling and building responsive layouts. It also provides circular tab menus to navigate to different view. To highlight active circular tab menus, we add ui-sref-active directive of UI-Router to them. The active class will be activated if the current state matches the state in ui-sref.

  5. We have the following circular icons in tab menu:

    • user
    • tasks
    • home
    • ok

    Clicking Tab Bar

  6. Lines 9-15 assign the circular user icon to the Personal tab. When you click the user icon in the tab menu, the Personal view will be placed in the content area of the form view:

    Clicking Personal Tab

  7. Lines 18-24 assign the circular tasks icon to the Work tab. When you click the circular tasks icon in the tab menu, the Work view will be placed in the content area of the form view:

    Clicking Work Tab

  8. Lines 27-33 assign the circular home icon to the Address tab. When you click the circular home icon in the tab menu, the Address view will be placed in the content area of the form view:

    Clicking Address Tab

  9. Lines 36-42 assign the circular ok icon to the Result tab. When you click the circular ok icon in the tab menu, the Result view will be placed in the content area of the form view:

    Clicking Result Tab

  10. Line 58 will always display our formData object in real time.

    Showing Form Data as it typed

In the next tutorial, we will build the Personal, Work, Address, and Result Features using UI-Router 1.0 with Angular 1.5+ component-based architecture.

The source code for this tutorial series is published on GitHub. Demo application is hosted in Microsoft Azure.

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --