0

编辑这是这个问题的关键

我有一个会计交易的主明细表。主部分只包含两个字段名称和类型。详细信息部分可以有两个或多个条目,每个条目都有 AccountId、Debit 和 Credit 字段。表单看起来像
在此处输入图像描述
您可以看到每个条目都有一个删除按钮,因此如果我们有两个以上的条目,我们可以随机删除任何条目。表单 html 如下所示

<body data-ng-app="transactions">
    <div data-ng-controller="transactionsController">
        <form role="form" name="transactionForm" novalidate data-ng-submit="create()">
            <div class="row">
                <div class="col-md-2">
                    &nbsp;
                </div>
                <div class="col-md-4">
                    <h2 class="form-login-heading">Create Transaction</h2>
                    <div data-ng-repeat="error in errors" class="alert alert-danger">
                        {{error[0]}}
                    </div>
                    <input type="text" name="name" class="form-control" placeholder="Name" data-ng-model="transaction.Name" required autofocus>
                    <div>
                        <span class="error" data-ng-show="transactionForm.name.$error.required && submitted">Please enter Name</span>
                    </div>
                    <input type="text" name="type" class="form-control" placeholder="Type" data-ng-model="transaction.Type" required>
                    <div>
                        <span class="error" data-ng-show="transactionForm.type.$error.required && submitted">Please enter Type</span>
                    </div>
                    <!--<input type="text" readonly name="number" class="form-control" placeholder="Number" data-ng-model="transaction.Number">
                    <input type="checkbox" data-ng-model="transaction.IsFinalized" /> <label>Finalize</label>-->


                    <table>
                        <tr>
                            <th>Account</th>
                            <th>Debit</th>
                            <th>Credit</th>
                            <th>&nbsp;</th>
                        </tr>
                        <tr data-ng-form="entryForm" data-ng-repeat="entry in transaction.Entries track by $index">
                            <td>
                                <input required name="accountId" data-ng-model="entry.AccountId" class="form-control" />
                                <span class="error" data-ng-show="entryForm.accountId.$error.required && submitted">Please select an account</span>
                            </td>
                            <td>
                                <input type="text" name="debit" data-ng-required="!entry.CreditAmount" class="form-control" placeholder="Debit" data-ng-model="entry.DebitAmount">
                                <span class="error" data-ng-show="entryForm.debit.$error.required && submitted">Debit is required</span>
                            </td>
                            <td>
                                <input type="text" data-ng-focus="checkAddRow($index)" name="credit" data-ng-required="!entry.DebitAmount" class="form-control" placeholder="Credit" data-ng-model="entry.CreditAmount">
                                <span class="error" data-ng-show="entryForm.credit.$error.required && submitted">Credit is required</span>
                            </td>
                            <td><button data-ng-show="transaction.Entries.length>2" class="btn btn-md btn-info " type="button" data-ng-click="deleteRow($index)">delete</button></td>




                        </tr>
                        <tr>
                            <td>Total</td>
                            <td><input readonly name="totalDebit" type="text" class="form-control" placeholder="Total Debit" data-ng-value="totalDebit()"></td>
                            <td><input readonly name="totalCredit" compare-to="totalDebit" type="text" class="form-control" placeholder="Total Credit" data-ng-value="totalCredit()"></td>
                        </tr>
                        <tr>
                            <td></td>
                            <td><b>Difference</b></td>
                            <td>
                                <input name="difference" readonly type="text" class="form-control" data-ng-value="difference()">
                                <!--<span class="error" data-ng-show="submitted && !differencezero">Difference should be 0</span>-->
                            </td>
                        </tr>
                    </table><br />
                    <button class="btn btn-md btn-info" type="submit">Create</button>
                    <button class="btn btn-md btn-info" data-ng-show="transaction.Entries.length<15" type="button" data-ng-click="addRow()">Add Row</button>
                    <div data-ng-hide="message == ''" class="alert alert-danger">
                        {{message}}
                    </div>
                </div>
                <div class="col-md-4">

                </div>
                <div class="col-md-2">
                    &nbsp;
                </div>
            </div>
        </form>
        <style type="text/css">
            .error {
                color: red;
            }
        </style>

        <pre>{{transactionForm.entryForm|json}}</pre>
    </div>

我的要求是,当焦点放在最后一个条目的信用输入上时,新条目应该自动添加到 UI 中。我通过在我的控制器上使用addRowand方法来做到这一点。checkAddRow这些方法如下

$scope.checkAddRow = function (index) {
                if (index == $scope.transaction.Entries.length - 1) {
                    $scope.addRow();
                }
            }

            $scope.addRow = function () {
                entry = {
                    EntryTime: '',
                    DebitAmount: '',
                    CreditAmount: '',
                    AccountId: ''
                };
                $scope.transaction.Entries.push(entry);
                console.log($scope.transactionForm);
            }

            $scope.deleteRow = function (index) {
                $scope.transaction.Entries.splice(index, 1);
                console.log($scope.transactionForm);
            }

同样,这部分很好并且运行良好。但我有另一个要求,如果最后一个条目没有被使用,它不应该导致表单无效。它应该从transaction.Entries收集中删除,其余数据应该正常保存。为了实现这一点,我create定义了$scope如下所示的函数

$scope.create = function () {
                $scope.submitted = true;
                if ($scope.transactionForm.entryForm && $scope.transactionForm.entryForm.$invalid && $scope.transactionForm.entryForm.$pristine) {

                    $timeout(function () {
                        $scope.deleteRow($scope.transaction.Entries.length - 1);
                    });

                    $timeout(function () {
                        console.log('From time out', $scope.transactionForm.$valid);
                        console.log($scope.transactionForm.$valid);
                        if (!$scope.transactionForm.$valid) return;

                        alert('data saved!');
                        console.log($scope.transactionForm);
                        //$scope.transactionForm.name.focus();
                    }, 200);

                }
                else {
                    if ($scope.transactionForm.$valid) {
                        alert('data saved 2');
                    }
                }

            }

你可以看到什么create功能在做什么。它正在检查entryForm (ng-form)主窗体中是否存在(transactionForm),然后检查是否entryForm存在$invalid$pristine如果所有这些标志都为真,那么我删除最后一个条目$scope.transaction.Entries并保存数据(当前显示数据已保存的警报)$timeout。如果我不使用超时,那么表单是无效的,所以我必须等待 200 毫秒才能$valid在删除最后一行后检查表单标志。entryForm但令我惊讶的是,当我从 create 函数中删除最后一行时,外部没有附加transactionForm. 另一方面,如果我使用 UI 上存在的删除按钮删除条目,entryForm则存在于 maintransactionForm中。谁能解释为什么会这样。我已经添加了<pre>{{transactionForm|json}}</pre>最后查看它何时可用,何时在主窗体上不可用。我创建了一个plunk来说明我的意思。只需在 master 部分的两个输入字段中添加一些数据,在两个条目的 accountid 字段中输入一些数据,当您到达第二个(最后一个)条目的 Credit 输入时,将自动添加一个新条目。忽略该行,只需按下创建按钮。最后一个条目将被删除,数据将保存,但entryForm将不再存在。我不确定我做错了什么。

4

1 回答 1

1

因此,这里的一个问题是您对表单是否有效的定义取决于最后一行的状态。

最后一行可以是以下品种:

  1. 从后端获取的行,但不是新的 --> 只有在无效时才应该无效
  2. 行是新的并且 $pristine --> 不应该无效
  3. row 是新的,但 $dirty (仍然是最后一个)--> 只有在无效时才应该无效

您正在尝试删除最后一行,然后重新评估表单的有效性。

$pristine以另一种方式处理它 - 如果它处于状态,不要让最后一行使表单无效:

这是一个简化的示例:

<form name="transactionForm" ng-submit="submit()" novalidate>
  <table>    
    <tr ng-form="entryForm" ng-repeat="transaction in transactions">

      <td><input ng-model="transaction.account" 
                 ng-required="transaction !== newLastEntry || entryForm.$dirty"></td>

      <td><input ng-model="transaction.amount" 
                 ng-required="transaction !== newLastEntry || entryForm.$dirty"
                 ng-focus="addEntryIfLast($last)" type="number"></td>
    </tr>
  </table>
</form>

注意$scope.newLastEntry这里。它设置为新的空(也是最后一个)条目。当您添加一个新的空行时会发生这种情况:

function addEmptyEntry(){
  $scope.newLastEntry = {};
  $scope.transactions.push($scope.newLastEntry);
}

因此,ng-required仅当 row 不是 new last 或 else 时才应用$dirty

然后,在提交时,您可以删除最后一个条目,如果它处于$pristine状态并且确实是新的最后一个条目(而不是之前存在的任何条目):

$scope.submit = function(){
  var itemsToSubmit = angular.copy($scope.transactions);

  if ($scope.transactionForm.$invalid) return;

  if ($scope.transactionForm.entryForm && 
      $scope.transactionForm.entryForm.$pristine && 
      $scope.transactions[$scope.transactions.length - 1] === $scope.newLastEntry) {

    itemsToSubmit.splice(itemsToSubmit.length - 1);
  }
  console.log(JSON.stringify(itemsToSubmit));
};

笨蛋

于 2014-12-27T07:22:50.727 回答