how to make ng-required true if any of the related object field filled?

589 Views Asked by At

By default the first person's details required="true" but the rest person's form are required="true" based on any of its filed filled or not.

The current issue of the snippet is that, it is not validate when last person's any one field filled.

Demo: http://plnkr.co/edit/WUpybR1tNq5QFjlTB2E7?p=preview

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
  $scope.person = [{isRequired: true}, {isRequired: false}, {isRequired: false}, {isRequired: false}];
  $scope.members = {};
  $scope.submitForm = function() {
    console.clear();
    if (typeof $scope.members != 'undefined' && Object.keys($scope.members).length) {
      var numMembers = Object.keys($scope.members).length;
      for (i = 0; i < numMembers; i++) {
        if (Object.keys($scope.members[i]).length <= 2) {
          $scope.person[i].isRequired = true;
        }
      }
    } else {
      $scope.person = [{isRequired: true}, {isRequired: false}, {isRequired: false}, {isRequired: false}];
    }
  }
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.9"></script>
<div ng-app="plunker" ng-controller="MainCtrl" class="container">
  <form name="myForm" ng-submit="submitForm(myForm.$valid)" novalidate>
    <h4>First person</h4>
    <div class="form-group" ng-class="{ 'has-error' : (myForm.$submitted && myForm.firstnameOne.$invalid) || (!myForm.firstnameOne.$pristine && myForm.firstnameOne.$invalid)}">
      <label>First Name</label>
      <input type="text" class="form-control" name="firstnameOne" placeholder="First Name" ng-model="members[0].fname" ng-required="person[0].isRequired">
    </div>
    <div class="form-group" ng-class="{ 'has-error' : (myForm.$submitted && myForm.lastnameOne.$invalid) || (!myForm.lastnameOne.$pristine && myForm.lastnameOne.$invalid)}">
      <label>Last Name</label>
      <input type="text" class="form-control" name="lastnameOne" placeholder="Last Name" ng-model="members[0].lname" ng-required="person[0].isRequired">
    </div>
    <h4>Second person</h4>
    <div class="form-group" ng-class="{ 'has-error' : (myForm.$submitted && myForm.firstnameSecond.$invalid) || (!myForm.firstnameSecond.$pristine && myForm.firstnameSecond.$invalid)}">
      <label>First Name</label>
      <input type="text" class="form-control" name="firstnameSecond" placeholder="First Name" ng-model="members[1].fname" ng-required="person[1].isRequired">
    </div>
    <div class="form-group" ng-class="{ 'has-error' : (myForm.$submitted && myForm.lastnameSecond.$invalid) || (!myForm.lastnameSecond.$pristine && myForm.lastnameSecond.$invalid)}">
      <label>Last Name</label>
      <input type="text" class="form-control" name="lastnameSecond" placeholder="Last Name" ng-model="members[1].lname" ng-required="person[1].isRequired">
    </div>
    <h4>Last person</h4>
    <div class="form-group" ng-class="{ 'has-error' : (myForm.$submitted && myForm.firstnameThird.$invalid) || (!myForm.firstnameThird.$pristine && myForm.firstnameThird.$invalid)}">
      <label>First Name</label>
      <input type="text" class="form-control" name="firstnameThird" placeholder="First Name" ng-model="members[2].fname" ng-required="person[2].isRequired">
    </div>
    <div class="form-group" ng-class="{ 'has-error' : (myForm.$submitted && myForm.lastnameThird.$invalid) || (!myForm.lastnameThird.$pristine && myForm.lastnameThird.$invalid)}">
      <label>Last Name</label>
      <input type="text" class="form-control" name="lastnameThird" placeholder="Last Name" ng-model="members[2].lname" ng-required="person[2].isRequired">
    </div> 
    <button type="submit" class="btn btn-primary">Submit</button>
  </form>
  <br><hr>
  <h4>Data</h4>
  <pre>{{members | json}}</pre>
  <h4>Validation</h4>
  <pre>{{person | json}}</pre>
</div>

1

There are 1 best solutions below

4
On BEST ANSWER

You got it almost right - there is a minor issue with your code.

var numMembers = Object.keys($scope.members).length; // <-- length of keys
  for (i = 0; i < numMembers; i++) {  // <-- iterate over length, not actual indexes
    if (Object.keys($scope.members[i]).length <= 2) {
      $scope.person[i].isRequired = true;
    }
  }

In your code, you compute i as the index of the array created out of the keys of your $scope.members. Imagine you fill in the First and Last forms, obtaining $scope.members = {0: ..., 2: ...} keys.

Now, when you call this line var numMembers = Object.keys($scope.members).length;, you get numMembers = 2, and when in your for cycle you evaluate your if condition, for your second i, you get this: Object.keys($scope.members[1]).length, but there is not 1 key in your members variable, hence the error.

To fix this, base your for loop on the array of existing keys itself:

var members = Object.keys($scope.members);
  for (i = 0; i < members.length; i++) {
    if (Object.keys($scope.members[members[i]]).length <= 2) { // Check key length of the existing keys only.
      $scope.person[members[i]].isRequired = true;
    }
  }

Here is a working fork of your plunker.