Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a form that is spread over multiple tabs. Originally, I used the tabset directive from ui-bootstrap, but then came the requirement to deep link to a specific tab, so I thought I'd use nested views from ui-router.

The problem I have is that the parent form is only valid when all the sub-forms are valid, but using ui-router states, only one sub-form is loaded at a time.

Here's an example to clarify

index.html

<!DOCTYPE html>
<html ng-app="app">
<head>
  <script src="//code.angularjs.org/1.3.0-beta.5/angular.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
  <script src="script.js"></script>
</head>
<body class="container-fluid">
  <div ui-view>
    <ul class="list-unstyled">
      <li><a ui-sref="edit.basic">Basic</a></li>
      <li><a ui-sref="edit.extended">Extended</a></li>
    </ul>
  </div>
</body>
</html>

script.js

angular.module('app', ['ui.router']).
config(function($stateProvider) {
  $stateProvider.state('edit', {
    abstract: true,
    url: '/edit/',
    templateUrl: 'edit.html',
    controller: function($scope) {
      $scope.model = {};
    }
  }).
  state('edit.basic', {
    url: '/basic',
    templateUrl: 'basic.html'
  }).
  state('edit.extended', {
    url: '/extended',
    templateUrl: 'extended.html'
  });
});

edit.html

<div class="row" ng-form="editForm">
  <div class="col-xs-12">
    <ul class="nav nav-tabs">
      <li ui-sref-active="active">
        <a ui-sref="edit.basic">Basic</a>
      </li>
      <li ui-sref-active="active">
        <a ui-sref="edit.extended">Extended</a>
      </li>
    </ul>
  </div>
  <div class="col-xs-12" ui-view></div>
  <div class="col-xs-12">
    <button type="button" class="btn btn-primary" ng-disabled="editForm.$invalid">Save</button>
  </div>
  <div class="col-xs-12">
    <hr>
    <tt>model = {{model}}</tt><br>
    <tt>editForm.$valid = {{editForm.$valid}}</tt><br>
    <tt>editForm.basicForm.$valid = {{editForm.basicForm.$valid}}</tt><br>
    <tt>editForm.extendedForm.$valid = {{editForm.extendedForm.$valid}}</tt>
  </div>
</div>

basic.html

<div ng-form="basicForm">
  <div class="form-group">
    <label for="textProperty">Text Property</label>
    <input type="text" class="form-control" name="textProperty" id="textProperty" ng-model="model.textProperty" required>
  </div>
</div>

extended.html

<div ng-form="extendedForm">
  <div class="form-group">
    <label for="numericProperty">Numeric Property</label>
    <input type="number" class="form-control" name="numericProperty" id="numericProperty" ng-model="model.numericProperty" required>
  </div>
  <div class="form-group">
    <label for="dateProperty">Date Property</label>
    <input type="date" class="form-control" name="dateProperty" id="dateProperty" ng-model="model.dateProperty" required>
  </div>
</div>

I am beginning to believe that this approach is not suitable for my purpose. Instead of using nested views, I should continue to use the tabset and use a state parameter to activate the appropriate tab.

I'm interested to know how others would solve it.

UPDATE 1:

Here is one solution I came up with that uses the ui-bootstrap tabset but doesn't use nested ui-router states and instead parameterises the active tab.

UPDATE 2:

Here is a solution which uses nested states along with a validator service following the suggestion of Santiago Rebella

UPDATE 3:

Here is an alternate solution to update 2 which uses a validator object on the parent state's scope for comparison

share|improve this question

1 Answer 1

up vote 2 down vote accepted

You could try to do it in the way you state just passing to a service some kind of attributes like step1, step2, etc and go adding true or whatever your success value you may use, so once all those attributes are true, in your ng-disabled or the way you are building your form, is allowed to be submitted.

Maybe previous formsteps you could be storing the values of the inputs in an object in your service. I think in this way you could a multi-page form.

share|improve this answer
1  
Thanks for your suggestion. I have implemented an example using a service to manage the validation state and updated the question with a link to it. –  gwhn Aug 27 '14 at 10:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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