5

Я внедрил настраиваемую директиву ввода - counter с возможностью сброса. Директива имеет require: "ngModel".

Я сбрасываю первоначальное состояние директивы ngModel с $setPristine(). В отличие от $setDirty(), $setPristine() не касается состояния родительской формы $pristine.

Q: Как «уведомить» родительская форма, что эта директива уже не «грязный», таким образом, что родительская форма может иметь сбросить его $pristine состояние?

Имейте в виду, что просто позвонить form.$setPristine() недостаточно, поскольку в форме могут быть другие «грязные» элементы управления, о которых моя директива не будет (и не должна) знать.

Это ссылка функция директивы:

link: function(scope, element, attrs, ngModel){ 

    var original; 

    ngModel.$render = function(){ 
    original = scope.counter = ngModel.$viewValue; 
    }; 

    scope.up = function(){ 
    ngModel.$setViewValue(++scope.counter); 
    }; 

    scope.reset = function(){ 
    scope.counter = original; 
    ngModel.$setViewValue(scope.counter); 
    ngModel.$setPristine(); // this sets $pristine on the directive, but not the form 
    }; 
} 

А вот как он используется:

<div ng-form="form"> 
    <counter ng-model="count"></counter> 
</div> 

plunker

+0

Я не эксперт, но уверены ли вы, что считаете это правильным? если вам нужно сбросить форму со своего счетчика, возможно, вы должны включить ее в директиву? или ваш счетчик должен выставить функцию для сброса, и это будет вызвано сбросом формы? – MamaWalter

+0

Я только хочу уведомить родительскую форму, что эта директива больше не «грязная».Форма, в идеале, должна управлять своим грязным состоянием. Я * мог * также «потребовать:«^form »', но что мне тогда делать? Я не уверен, что понимаю второе предложение об открытии функции, которую вызывается сбросом формы. –

+0

вы можете показать нам всю вашу декларацию директивы. – levi

ответ

3

На угловых 1.3.x, нет встроенного в растворе.

form.$setPristine() комплекты нетронутые на всех его дочерних элементах управления. (link to code)

ngModel.$setPristine() только устанавливает $ нетронутым на себя (link to code)

Одним из способов решения этой проблемы является создание директивы, которая живет рядом с form директивы и угоняет form.$setDirty отслеживать подсчет грязного управления. Это, вероятно, лучше всего сделать на этапе предварительной ссылки (т. Е. До того, как дочерние элементы управления начнут регистрироваться).

app.directive("pristinableForm", function() { 
    return { 
    restrict: "A", 
    require: ["pristinableForm", "form"], 
    link: function(scope, element, attrs, ctrls) { 
     var me = ctrls[0], 
     form = ctrls[1]; 
     me.form = form; 
     me.dirtyCounter = 0; 
     var formSetDirtyFn = form.$setDirty; 
     form.$setDirty = function() { 
     me.dirtyCounter++; 
     formSetDirtyFn(); 
     }; 
    }, 
    controller: function() { 
     this.$notifyPristine = function() { 
     if (this.dirtyCounter === 0) return; 
     if (this.dirtyCounter === 1) { 
      this.dirtyCounter = 0; 
      if (this.form) this.form.$setPristine(); 
     } else { 
      this.dirtyCounter--; 
     } 
     }; 
    } 
    }; 
}); 

Затем директива пользовательский ввод должен require: ["ngModel", "^pristinableForm"] и вызвать pristinableForm.$notifyPristine() в функции сброса:

scope.reset = function(){ 
    if (ngModel.$dirty){ 
    scope.counter = original; 
    ngModel.$setViewValue(scope.counter); 
    ngModel.$setPristine(); 
    pristinableForm.$notifyPristine(); 
    } 
}; 

Использование является:

<div ng-form="form" pristinable-form> 
    <counter ng-model="count1"></counter> 
    <counter ng-model="count2"></counter> 
    <input ng-model="foo" name="anotherControl"> 
</div> 

plunker

+0

Звучит немного сложно на мой вкус. Не могли бы вы проверить мой родственный вопрос https://stackoverflow.com/questions/48528957/re-set-all-forms-to-pristine-status-from-the-bottom-up – Naomi

0

Это не так хорошее решение. Итерации через элементы управления, прикрепленные к форме, и проверьте, есть ли еще грязный.

Я использовал метод объяснения here, чтобы получить элементы управления.

Plunker

app.directive("counter", function(){ 
    return { 
    require: "ngModel", 
    template: '<button ng-click="up()">{{counter}}</button><button ng-click="reset()">reset</button>', 
    link: function(scope, element, attrs, ngModel){ 

     var original; 

     ngModel.$render = function(){ 
     original = scope.counter = ngModel.$modelValue; 
     }; 

     scope.up = function(){ 
     ngModel.$setViewValue(++scope.counter); 
     }; 

     scope.reset = function(){ 
     scope.counter = original; 
     ngModel.$setViewValue(scope.counter); 
     ngModel.$setPristine(); 

     // check if one of the controls attached to the form is still dirty 
     var dirty = false; 
     angular.forEach(scope.form, function(val, key) { 
      if (key[0] != '$') { 
       if (val.$dirty) { 
       dirty = true; 
       } 
      } 
     }); 
     if(!dirty) scope.form.$setPristine(); 


     }; 
    } 
    }; 
}); 
+0

Спасибо за помощь, но я прямо заявил, что просто вызов '$ setPristine()' в форме не сокращает его, так как форма может содержать другие дочерние элементы управления, которые могут быть грязными. Кроме того, лучший способ сделать это: «require:»^form »', а не предполагать, что 'scope.form' существует. –

+0

ОК, я думаю, я понимаю, не уверен, что для этого есть встроенное решение. – MamaWalter

+0

Я отредактировал свой ответ с «грязным» решением. – MamaWalter

Смежные вопросы