7

I have table with ng-repeat for table rows. I want to make inline editing and validation of data from single row, but it is impossible to use form or ng-form inside table. For inline editing I use inputs with ng-show inside td. So, I have two questions:

  1. Is it correct approach for inline editing? (using hidden inputs inside td).

  2. How can I validate data from row?

Update: I want for table row something like "form submitting" and add error class for table cells with wrong data.

I'm new to angular.

4 Answers 4

19

NG-Form works on elements that are not a HTML form. So, you should be able to use the built ng-form validations inside a table. It seems to track the forms properly per row for me.

https://docs.angularjs.org/api/ng/directive/form

 <tr ng-repeat="market in markets | orderBy:'name'" ng-form name="myForm">
   <td>{{market.id}}</td>
   <td ng-class="{'has-error': !myForm.minimum.$valid}">
     <input type="number" name="minimum" min="0" max="10000" ng-model="market.minimum" />
   </td>
   <td ng-class="{'has-error': !myForm.cash.$valid}">
    <input type="number" ng-model="market.cash" min="0" name="cash" />
  </td>
  <td>
    <input type="submit" ng-disabled="!myForm.$valid" ng-click="save(market)"/>
  </td>
</tr>
Sign up to request clarification or add additional context in comments.

1 Comment

This is close, and much more in line with the original question's desires (imo), but there is one issue. With your code the "myForm" is on the $scope, so as multiple rows are added only the last will really 'stick'. I took your example and instead did name="market.myForm" and (in the inputs) "!market.myForm.$valid" and things worked as expected.
7

I create example with simple validation to your second question:

View:

<div ng-controller="MyCtrl">
    <table class="table table-condensed">
        <thead>
            <tr>
                <th>Id</th>
                <th>Firstname</th>
                <th>Lastname</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="item in items">
                <td>{{item.id}}</td>
                <td><input ng-model="item.firstName" ng-class="{ error: !item.firstName }"/></td>
                <td><input ng-model="item.lastName" ng-class="{ error: !item.lastName }"/></td>
                <td><input ng-model="item.email" ng-pattern="emailRegExp" ng-class="{ error: !item.email }"/></td>
                <td><button ng-disabled="!item.lastName || !item.firstName || !item.email"/>Submit</td>
            </tr>
        </tbody>
    </table>
</div>

Controller:

function MyCtrl($scope) {
    $scope.items = [
        {
            id: 1,
            firstName: 'Ivan',
            lastName: 'Ivanov',
            email: '[email protected]'
        },
        {
            id: 2,
            firstName: 'Petr',
            lastName: 'Petrov',
            email: '[email protected]'
        }
    ];

    $scope.emailRegExp = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/; 
}

Please, see jsfiddle :)

Jsfiddle

For your question in comment about date validation:

I see two ways for do it:

1) In yor controller you create $scope.dateRegExp = "/^\d{2}([./-])\d{2}\1\d{4}$/" and into the view you using it with ng-pattern="dateRegExp"

2) You can use ng-change="" directive:

View:

<tr ng-repeat="item in items">
    <td><input ng-model="item.date" ng-change="validateDate(itemDate)" ng-class="{ error: dateInputError }"/></td>

Controller:

$scope.dateInputError = false;

$scope.validateDate = function(date) {
   if(//some validation){
      $scope.dateInputError = true; //true - it means error style shows
   }
};

4 Comments

Thanks, your example is awesome, how can I make validation in the controller? I have more then two fields and need to check also date for correct format. So view will be huge.
Cool, thanks for update. Can I use any controller's method for validation?
Is it right way to validate data? ($scope.emailRegExp) Maybe it is better to use some validation method, where I would check all data?
you are checking the data again on the button? There must be another approach where it checks whether the input control is valid. like input.valid ? enable : disable
2

Approaches for this problem (incremental):

  1. (optional) Don't use a table. use nested lists and force it with css to look like a table.

  2. Do it in the Angularish way: use a custom directive on the table cells/rows (whatever) the directive should watch the cell content for changes and then run a any custom validation and logic you have.

Comments

2
  1. I don't think you need to hide your inputs in tds, you could just use CSS to make them fill the td, with no border for example.

  2. As @alonisser said, the angular-way is to create a directive to handle that. To solve my similar case, I created a 'super' table directive which provide my table template and handle its behavior. About the template: I wrapped the table into a form ;)

HTML example:

<form name="tableform">
    <table>
      <tbody>
        <tr class="tr-rawdata" ng-repeat="row in tableData track by $index" ng-model="row">
          <td ng-repeat="cell in row track by $index">
            <input type="text" ng-model="row[$index]">
          </td>
        </tr>
      </tbody>
    </table>
</form>

directive example:

angular.module('myApp').directive('superTable', function() {
  return {
    restrict: 'A',
    templateUrl: 'partials/super-table.html',
    link: function($scope, $elem, $attrs) {

      $elem.on('blur', function(e) {
        //do something
      });
    }
  }
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.