2016-04-18 6 views
1

Я пытаюсь использовать ng-model-options = {updateOn: 'submit'}, чтобы я мог сохранить модель до ее отправки (таким образом вы можете отменить и не повлиять на модель).Проверка не работает должным образом с ng-model-options = {updateOn: 'submit'}

Проблема, которую я имею, - это проверка только проверки на ng-модель, а не на ввод формы.

Есть ли способ проверить форму перед ее обновлением модели?

HTML:

<form name="form" 
     ng-submit="vm.update(vm.action)" 
     ng-model-options="{ updateOn: 'submit' }" novalidate > 

    <label>Subject</label> 
    <input name="subject" required ng-model="vm.action.body.subject"/> 
    <div ng-messages="form.subject.$error"> 
     <div ng-message="required">You must enter a subject.</div> 
    </div> 

    <button ng-click="vm.cancel()">Cancel</button> 
    <button type="submit" ng-disabled="form.$invalid">Save</button> 
</form> 

См codepen для более четкого объяснения поведения: http://codepen.io/tknz/pen/vGjajo/?editors=1010

  • Если добавить тело, проверка будет заполнить для необходимости
  • Если удалить эту тему, необходимая процедура проверки будет проходить

Is есть способ обойти это? Или лучшее решение?

+0

Если вы хотите достичь 'cancel' поведения, лучше использовать' vm.action.body = {} 'в 'отменить'. –

+0

Я не хочу его пустить, я хочу сохранить его старую ценность. – Yodacheese

+0

Хорошо, когда лучше использовать 'var oldBody = angular.copy (vm.action.body);'. Затем в 'cancel' function' vm.action.body = oldBody '. Это решение не нарушит проверки. –

ответ

1

Это действительно очень сложная проблема, и одна из них делает использование 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 
        }); 
      }); 
     } 
    }; 
Смежные вопросы