3
\$\begingroup\$

I think my current structure is way too repetitive. I feel like I must be missing something that would easily make this sign up wizard work far better.

  <ol class="registerMeter">
    <li class="progress-point" ng-click="wiz('step1')"     ng-class="{active: step1.active, done: step1.done, todo: step1.todo}">Step 1</li>
    <li class="progress-point" ng-click="wiz('step2')"     ng-class="{active: step2.active, done: step2.done, todo: step2.todo}">Step 2</li>
    <li class="progress-point" ng-click="wiz('step3')"     ng-class="{active: step3.active, done: step3.done, todo: step3.todo}">Step 3</li>
</ol>
<section class="row formMain" ng-switch="step">
    <section class="row" ng-switch-default>
        <form ng-submit="registerSubmit()">                
        </form>        
    </section>
    <section ng-switch-when="step2">
        <form>

        </form>
    </section>
    <section ng-switch-when="step3">
        <form>

        </form>
    </section>
</section>


app.controller('registerCtrl', function($scope, $http, $location, FlashService){

    $scope.step1 = {active: true, done:false, todo: false};
    $scope.step2 = {active: false, done:false, todo: true};
    $scope.step3 = {active: false, done:false, todo: true};

    $scope.wiz = function(step){
        $scope.step = step;
        switch (step) {
            case 'step1':
                $scope.step1 = {active: true, done:false, todo: false};
                $scope.step2.active = false;
                $scope.step3.active = false;
                $scope.step2.todo = true;
                $scope.step3.todo = true;
                break;
            case 'step2':
                $scope.step1.active = false;
                $scope.step1.todo = true;
                $scope.step2 = {active: true, done:false, todo: false};                
                $scope.step3.active = false;
                $scope.step3.active = false;
                break;
            case 'step3':
                $scope.step1.active = false;
                $scope.step2.active = false;
                $scope.step1.todo = true;
                $scope.step2.todo = true;
                $scope.step3 = {active: true, done:false, todo: false};
                break
            default: 
                $scope.step1 = {active: true, done:false, todo: false};
                $scope.step2 = {active: false, done:false, todo: true};
                $scope.step3 = {active: false, done:false, todo: true};            
        }
    }



    $scope.registerSubmit = function(){
        $http.post()
            .success(function(data, status, headers, config){                
                $scope.step = 'step2';
                $scope.step1 = {active: false, done:true , todo:false}
                $scope.step2.active = true;
                if (data.msg !='') {
                      $scope.msgs.push(data.msg);
                  } else {
                       $scope.errors.push(data.error);
                   }
              }).error(function(data, status){
                      FlashService.show(response.flash);
                    $scope.errors.push(status);
                })
    };
});

I'm worried that the switch and ngclass statements are way more than I need. Is there a simpler way to accomplish this? This just doesn't feel DRY at all.

\$\endgroup\$
  • \$\begingroup\$ You have a lot of booleans Are they all required? Could you instead check if values the user enters in the wizard exist (not null) instead of three boolean states? \$\endgroup\$ – Sukima Feb 6 '14 at 1:29
  • \$\begingroup\$ @Sukima That's interesting. I could check if the object from the form is user interacted yet. That would only work one way though and wouldn't allow a user to go back a step. It's a long sign up form. \$\endgroup\$ – Patrick Cauley Feb 6 '14 at 3:28
  • \$\begingroup\$ In that case I think it would be better to wrap your boolean logic into a finite state machine object which manages the state the user is in. A little abstraction can help with readability. \$\endgroup\$ – Sukima Feb 6 '14 at 14:08
2
\$\begingroup\$

You can make this DRYer if you can assume that :

  • You keep naming each step stepx
  • No other variables in $scope start with step

In that case you could use a function that sets in a first step the right scope active and then the other steps inactive:

function updateScopeSteps( $scope , step )
{
   //Default to step1
   step = step || 'step1';
   //Set step
   $scope.step = step;
   //Activate step
   $scope[ step ] = {active: true, done:false, todo: false};
   //De-activate all other steps
   for( var name in $scope ){
     if( name.substring(0,4) == 'step' && name != step ){
       $scope[name].active = false;
       $scope[name].todo = true;
     }
   }
}
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.