Ad

Create An Angularjs Web Form That Duplicates But Doesn't Clone

I have "attempted" to build an Angularjs web form that duplicates the input fields upon clicking the add button and removes newly added fields upon clicking the "close button" which seems to work okay. Great, right!?

http://plnkr.co/edit/jUulJQ52m9QEZLkG086B

However, the duplicate forms created after clicking the add button are exact clones of each other or the original. So, when there are two forms on the screen and data entered into form 1, it is duplicated on form 2 and visa versa.

My question:

How do I continue down the path of having the ability to duplicate the elements, really, within the "fieldset" element of the form, but without it being cloned?

Following are snippets of my HTML and AngularJs file. I have wracked my head on this for a while now and keep ending up in the same spot.....A fresh set of eyes and/or any suggestions would be great!

Thanks!

Index.html

<body>
  <div class="container-fluid">
    <div class="row">
      <div class="col-md-4"></div>
      <div class="col-md-4" ng-controller="formCtrl">
        <h1>Expense Form</h1>
        <form class="form-horizontal" id="itvExpenseForm" name="ExpenseForm" ng-repeat="field in table.fields track by $index" novalidate>
          <fieldset id="innerForm" ng-model="table.fields[$index]">
            <legend>
              <span>{{$index + 1}}.</span>
            </legend>
            <div class="form-group" ng-controller="quarterListCtrl">
              <label for="ddlQuarters" class="col-sm-4 control-label">Year Quarter:</label>
              <div class="col-sm-8">
                <select class="form-control" name="Quarters" id="ddlQuarters" ng-model="formData.quarter">
                  <option value="">---Please select---</option>
                  <option ng-repeat="q in quarters">{{q.name}}</option>
                </select>
              </div>
            </div>
            <div class="form-group">
              <label for="ddlDate" class="col-sm-4 control-label">Purchase Date:</label>
              <div class="col-sm-8">
                <input class="form-control" id="ddlDate" type="date" ng-model="formData.date" required>
              </div>
            </div>

            <div class="form-group">
              <div class="col-lg-10 col-lg-offset-2">
                <button id="removeMore" aria-hidden="false" ng-click="removeForm($index)" ng-show="table.fields.length > 1">Close</button>
                <button id="addMore" aria-hidden="true" ng-click="addNewForm()">Add</button>
              </div>
            </div>
          </fieldset>
        </form>
        <div class="form-group">
          <div class="col-lg-10 col-lg-offset-2">
            <button type="submit" class="btn btn-success" ng-click="submitForm()">Submit</button>
          </div>
        </div>
      </div>
      <div class="col-md-4"></div>
    </div>
  </div>
</body>

App.JS

    var app = angular.module('app', []);
app.controller('quarterListCtrl', function($scope, $http) {
  $scope.quarters = quarters;
});
app.controller('accountsListCtrl', function($scope, $http) {
  $scope.accounts = accounts;
});
app.controller('locationsListCtrl', function($scope, $http) {
  $scope.locations = locations;
});

app.controller('formCtrl', function($scope, $http) {
  $scope.formData = {};

  var formCount = 1;

  $scope.table = {
    fields: []
  };
  // create first form on page load
  $scope.table.fields.push(formCount);

  // adds new field to table array which adds to page
  $scope.addNewForm = function() {
    formCount++;
    $scope.table.fields.push(formCount);
  };
  // removes field from table array which removes form
  $scope.removeForm = function(myIndex) {
    if ($scope.table.fields.length > 1) {
      $scope.table.fields.splice(myIndex, 1);
      formCount;
    }
  };
});

var accounts = [{
  'name': 'Account One',
  'acct no': 123456789,
  'id': 1
}, {
  'name': 'Account Two',
  'acct no': 987654321,
  'id': 2
}];

var quarters = [{
  'name': 'Fall',
  'id': 1
}, {
  'name': 'Winter',
  'id': 2
}, {
  'name': 'Spring',
  'id': 3
}, {
  'name': 'Summer',
  'id': 4
}, ];

var locations = [{
  'name': 'Here',
  'id': 1
}, {
  'name': 'There',
  'id': 2
}, {
  'name': 'Everywhere',
  'id': 3
}];
Ad

Answer

As mentioned already, your formData is reference by all the elements in your array so a change in one element affects all of them.

To make things simpler, you don't need a formCount. Just have an array of formData and make use of angular.copy. So your controller becomes:

app.controller('formCtrl', function ($scope, $http) {
    $scope.forms = [];

    // create first form on page load
    $scope.forms.push({});

    // adds new field to table array which adds to page
    $scope.addNewForm = function (formToCopy){
        $scope.forms.push(angular.copy(formToCopy));
    };
    // removes field from table array which removes form
    $scope.removeForm = function (formToRemove) {
        var formIndex = $scope.forms.indexOf(formToRemove);
        if (formIndex > -1) {
            $scope.forms.splice(formIndex, 1);
        }
    };
});

See forked plunker for full markup changes but the main points are to change references from table.fields to just forms and pass the formData object to addNewForm and removeForm. So your ng-repeat becomes:

<form class="form-horizontal" name="ExpenseForm" ng-repeat="formData in forms track by $index" novalidate>

You can't use ng-model on a fieldset, so this doesn't do anything:

<fieldset id="innerForm" ng-model="table.fields[$index]">

Also, I would avoid using the id attribute on repeated elements otherwise there will be multiple elements with the same id on the page. You could opt for a dynamic id like id="innerForm-{{$index}}" but it's really not necessary in this case.

Ad
source: stackoverflow.com
Ad