我正在尝试编写一个自定义指令,该指令根据指令中需要的其他值验证输入字段。我通过使用范围变量使用隔离范围来实现这一点。更具体地说,我想比较产品的客户价格(即其净价格)与购买价格,如果差异是负数(客户价格设置为0除外),我想让客户价格输入(及其周围形式)无效。这里是我的指令:
export class CheckMarkupDirective implements ng.IDirective {
public static create(): ng.IDirective {
return {
restrict: "A",
require: "ngModel",
scope: {
netPrice: "<",
markupAmount: "<"
},
link: (scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes, ngModelCtrl: ng.INgModelController) => {
let netPrice: number;
let markupAmount: number;
scope.$watchGroup(["netPrice", "markupAmount"], (newValues, oldValues) => {
[netPrice, markupAmount] = newValues;
if (markupAmount >= 0) {
ngModelCtrl.$setValidity("markup", true);
} else {
ngModelCtrl.$setValidity("markup", netPrice === 0);
}
ngModelCtrl.$validate();
});
}
};
}
}
这是我如何使用它AA NG型格由表单标签包围内:
<input type="text" id="customer-price" name="customerPrice"
ng-model="ctrl.product.customerPrice"
ng-change="ctrl.customerPriceChangeDetected()"
check-markup markup-amount="ctrl.product.markupAmount"
net-price="ctrl.product.netPrice" />
它的工作原理,一种时尚后,但问题是验证部分似乎是“定时错误”,这意味着如果我输入的值导致“标记”第一次变为负数,那么表单的$ invalid值设置为false。但是当下一个输入是负数时,验证就会启动并运行。我认为我的问题是我在不同的步骤之间进行了大量的计算,但是我很难知道是什么导致验证如此关闭。我想我希望有更深入的Angular JS机制知识的人有更大的胆量,并告诉我我是否做了明显错误的事情。如果我的描述有些模糊,请提前致谢并抱歉。
编辑:思想我还包括那些在NG-变化引发的方法:
public customerPriceChangeDetected(): void {
this.setNetPriceFromCustomerPrice();
this.setMarkup();
this.changeDetected();
}
private setNetPriceFromCustomerPrice(): void {
let customerPrice = this.product.customerPrice;
let vatRate = this.product.vatRate;
let netPrice = (customerPrice/(1 + vatRate));
this.product.netPrice = parseFloat(accounting.toFixed(netPrice, 2));
}
private setMarkup(): void {
let purchasePrice = this.product.purchasePrice;
let markupAmount = this.product.netPrice - purchasePrice;
this.product.markupAmount = markupAmount;
this.product.markupPercent = markupAmount/purchasePrice;
}
public changeDetected(): void {
let isValid = this.validationService ? this.validationService.isValid : false;
this.toggleSaveButton(isValid);
}
验证服务吸气基本形式返回$有效和工作完全为我所有的其他自定义验证。
编辑2:新增截图,显示了周围的NG-form标签似乎有$无效的属性设置为true ATLEAST:
编辑3: 这里的transpiled JS:
var CheckMarkupDirective = (function() {
function CheckMarkupDirective() {
}
CheckMarkupDirective.create = function() {
return {
restrict: "A",
require: "ngModel",
scope: {
netPrice: "<",
markupAmount: "<"
},
link: function (scope, element, attrs, ngModelCtrl) {
var netPrice;
var markupAmount;
scope.$watchGroup(["netPrice", "markupAmount"], function (newValues, oldValues) {
netPrice = newValues[0], markupAmount = newValues[1];
if (!markupAmount || !netPrice)
return;
if (markupAmount >= 0) {
ngModelCtrl.$setValidity("markup", true);
}
else {
ngModelCtrl.$setValidity("markup", netPrice === 0);
}
//ngModelCtrl.$validate();
});
}
};
};
return CheckMarkupDirective; }());
...这是我的HTML的削减版本:
<form autocomplete="off" class="form-horizontal" role="form" name="productDetailsForm" novalidate data-ng-init="ctrl.setForm(this,'productDetailsForm')">
<div data-ng-form="section2">
<div class="form-group">
<label for="purchase-price" class="col-sm-4 control-label">Purchase price</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="purchase-price" name="purchasePrice"
data-ng-model="ctrl.product.purchasePrice"
data-ng-change="ctrl.purchasePriceChangeDetected();"
data-decimal="Currency" />
</div>
</div>
<div class="form-group">
<label for="vat-rate" class="col-sm-4 control-label">VAT rate</label>
<div class="col-sm-4">
<select class="form-control" id="vat-rate"
data-ng-model="ctrl.product.vatRate"
data-ng-change="ctrl.vatRateChangeDetected()"
data-ng-options="vatRate.value as vatRate.text for vatRate in ctrl.vatRates"></select>
</div>
</div>
<div class="form-group" data-has-error-feedback="productDetailsForm.section2.customerPrice">
<label for="customer-price" class="col-sm-4 control-label">Customer price</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="customer-price" name="customerPrice"
data-ng-model="ctrl.product.customerPrice"
data-ng-change="ctrl.customerPriceChangeDetected();"
data-decimal="Currency"
data-check-markup
data-markup-amount="ctrl.product.markupAmount"
data-net-price="ctrl.product.netPrice" />
<invalid-feedback item="productDetailsForm.section2.customerPrice"></invalid-feedback>
<validation-feedback type="markup" item="productDetailsForm.section2.customerPrice" data-l10n-bind="ADMINISTRATION.PRODUCTS.NET_PRICE.INVALID"></validation-feedback>
</div>
<div class="col-sm-4">
<div class="form-group" style="margin-bottom: 0;">
<label for="net-price" class="col-lg-5 col-md-5 col-sm-5 col-xs-5" style="font-weight: normal; margin-top: 7px;">
<span data-l10n-bind="ADMINISTRATION.PRODUCTS.NET_PRICE"></span>
</label>
<label class="col-lg-7 col-md-7 col-sm-7 col-xs-7" style="font-weight: normal; margin-top: 7px;">
<span id="net-price">{{ ctrl.product.netPrice | currency }}</span>
</label>
</div>
</div>
</div>
<div class="form-group" data-has-error-feedback="productDetailsForm.section2.markup">
<label for="markup-amount" class="col-sm-4 col-xs-4 control-label">Markup</label>
<div class="col-sm-8 col-xs-8">
<label id="markup-percent" class="control-label" data-ng-class="{'text-danger': ctrl.product.markupPercent < 0}">
{{ ctrl.product.markupPercent * 100 | number: 2 }}%
</label>
<label id="markup-amount" class="control-label" data-ng-class="{'text-danger': ctrl.product.markupAmount < 0}">
({{ ctrl.product.markupAmount | currency }})
</label>
</div>
</div>
</div>
我已经把断点表内的指令和一些奇怪的原因,手表似乎并不触发我第一次输入一个新值到客户的价格输入。相反,我直接在changeDetected()方法内部找到自己。我现在很困惑。我认为这个问题在验证之前会触发ng-change指令。我可能有一个错误的逻辑,导致我的验证服务触发的isValid检查在指令有时间来真正改变有效性之前触发。
我'不知道明白为什么你叫'$的validate()'。此外,当标记为无效的字段由于ng-model不会更新为无效值时,不会调用ng-change。因此,尝试在表单外打印“customerPrice/markupAmount/netPrice”的值以查看值是否已刷新。 – Walfrat
嗨,感谢您花时间帮助我。我已经在手表中使用过console.log,看到每次更改客户价格输入字段的值时,markupAmount和netprice都会更新,以至于atleast的部分似乎按预期工作(?)在我看来,验证总是落后一步,因此如果我从一个有效的输入开始并将其更改为无效的输入(负面标记),表单仍然会有$ invalid = false。真烦人的部分是,与ng形式的div似乎有$ invalid = true Whick真的让我困惑。 – Kristofer