Это действительно очень сложная проблема, и одна из них делает использование updateOn: submit
для поддержания чистой модели до сложного представления. Есть несколько связанных проблем. Во-первых, updateOn: submit
на самом деле означает, что проверка не выполняется до подачи. На пути в форму есть начальная проверка, и это единственная проверка, доступная при перемещении по форме. Поэтому, если ваша открытая форма имеет недопустимые поля, ваша форма будет отмечена как недействительная, как только вы выйдете из поля и останетесь до тех пор, пока вы не отправите ее.
Один из возможных способов заключается в вызове открытого метода $validate
на входе управления, скажем, через ng-размытие. Это даст ручную проверку элемента управления, когда вы его покинете. Если вы посмотрите на код для встроенных проверок, они фактически проверяют на $viewValue
, а не на $modelValue
. Так что в теории это должно сработать! Но есть два вопроса. Во-первых, метод $validate
фактически заставляет обновлять модель, если $viewValue
не синхронизирован с $modelValue
. Я предполагаю, что код старше, чем идея updateOn: submit
, и они на самом деле не рассматривали сценарий, когда наличие двух синхронизаций является желаемым поведением. Другая проблема еще более фундаментальна, поскольку метод фактически использует внутреннее значение, называемое $$lastCommittedViewValue
. Я не могу понять, почему он это делает, вместо того, чтобы просто принимать фактический $viewValue
, но конечным результатом является то, что в updateOn: submit
ситуация $$lastCommittedViewValue
никогда не изменяется, поскольку viewValue передается только на submit.
Таким образом, единственный официальный документированный выход из этого не сработает. Однако, глядя на код, существует довольно простой, хотя и недокументированный способ. Метод $validate
выполняет некоторую предварительную настройку, а затем вызывает внутренний метод $$runValidators
. Это проходит через 3 возможных источника валидаторов, синтаксические анализаторы (исторический артефакт, который я думаю), и синтаксические и асинхронные валидаторы. Достаточно удобно называть это прямо с реальным $viewValue
вместо последнего зафиксированного.Настройка функции, как это в контроллере формы:
validateNoUpdate(control) {
control.$$runValidators(control.$modelValue, control.$viewValue,
function(allValid) {
console.log("In $$runValidators, allValid : ", allValid);
// Any post validation code required can be entered here
});
}
и назвать его в элементе управления вводом, например так:
<input id="newClientName" name="newClientName"
ng-maxlength="5"
ng-required="true"
ng-blur="$ctrl.validateNoUpdate(clientForm.newClientName)"
ng-model-options="{ updateOn: 'submit' }" ng-model="$ctrl.client.name">
Я обычно не рассматривают, используя недокументированный вызов, как это, но я действительно ненавижу идею клонирования объекта формы и копирования ее обратно на отмену - это просто кажется чревато потенциальными проблемами. И в этом конкретном случае Angular 1.x подходит к концу жизни, поэтому менее вероятно, что runValidators
будет сброшен или переназначен. Также обратите внимание, что, возможно, возможно восстановить в коде код runValidators
, напрямую обратившись к (посторонним) разоблаченным синтаксическим анализаторам/syncValidators и aSyncValidators. Но код выглядит немного волосатым, и я достаточно доволен, чтобы принять мои изменения с runValidators
, пока я не перенесу все это на Угловое 2.
Редактировать - Возможно, было бы проще сделать это как директиву (и это один из немногих ситуаций, когда вы могли бы еще использовать директиву над компонентом в 1.5+), следующим образом:
.directive('validateViewOnBlur', function() {
return {
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
if (!ngModel) {
return;
}
element.on('blur', function() {
ngModel.$$runValidators(ngModel.$modelValue, ngModel.$viewValue,
function(allValid) {
console.log("In $$runValidators, allValid : ", allValid);
// Any post validation code required can be entered here
});
});
}
};
Если вы хотите достичь 'cancel' поведения, лучше использовать' vm.action.body = {} 'в 'отменить'. –
Я не хочу его пустить, я хочу сохранить его старую ценность. – Yodacheese
Хорошо, когда лучше использовать 'var oldBody = angular.copy (vm.action.body);'. Затем в 'cancel' function' vm.action.body = oldBody '. Это решение не нарушит проверки. –