修改以下是此问题的plunk
我有一个会计交易的主要详细信息表格。主部分只包含两个字段名称和类型。细节部分可以有两个或更多条目,每个条目都有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">
</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> </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">
</div>
</div>
</form>
<style type="text/css">
.error {
color: red;
}
</style>
<pre>{{transactionForm.entryForm|json}}</pre>
</div>
我要求当焦点在最后一个条目的Credit输入时,新条目应该自动添加到UI。我是通过在我的控制器上使用addRow
和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
之后保存数据(目前是保存节目的警报)。如果我没有使用超时,那么表单无效,所以我必须等待200ms才能在删除最后一行后检查表单$valid
标志。但令我惊讶的是,当我从create function中删除最后一行时,外部entryForm
没有附加transactionForm
。另一方面,如果我使用UI上的删除按钮删除条目,则entryForm
位于主transactionForm
内。谁能解释为什么会这样。我在最后添加<pre>{{transactionForm|json}}</pre>
以查看它何时以及何时在主表单上不可用。我创建了一个plunk来表明我的意思。只需在主部分的两个输入字段中添加一些数据,在两个条目的accountid字段中输入一些数据,当您到达第二个(最后)条目的Credit输入时,将自动添加一个新条目。忽略该行,然后按下“创建”按钮。最后一个条目将被删除,数据将保存,但entryForm
将不再存在。我不确定我做错了什么。
答案 0 :(得分:1)
所以,这里的一个问题是你对表单是否有效的定义取决于最后一行的状态。
最后一行可能有以下几种:
您正尝试删除最后一行,然后重新评估表单的有效性。
另一种方法 - 如果表格处于$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
仅在行不是新的时候应用,否则$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));
};