防止输入设置$ dirty angularjs

时间:2013-06-13 14:03:55

标签: angularjs

我在页面上有一个表格。在表单内部,我有几个控件,当表单很脏时需要显示一个保存对话框,即表单。$ dirty = true。但是,我不希望弄脏表单的形式有一些导航控件。假设我无法将控件移出表单。

请参阅:http://plnkr.co/edit/bfig4B

如何使表格中的选择框不变脏?

7 个答案:

答案 0 :(得分:25)

这是使用指令而不使用$ timeout的@ acacia的答案版本。这将使您的控制器更清洁。

.directive('noDirtyCheck', function() {
  // Interacting with input elements having this directive won't cause the
  // form to be marked dirty.
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$pristine = false;
    }
  }
});

然后在您的表单中使用它:

<input type="text" name="foo" ng-model="x.foo" no-dirty-check>

答案 1 :(得分:13)

我使用了@ overthink的解决方案,但遇到了@dmitankin提到的问题。但是,我不想将处理程序附加到焦点事件。所以相反,我努力覆盖$ pristine属性本身并强制它始终返回false。我最终使用了IE8及以下版本不支持的Object.defineProperty。在这些旧版浏览器中有workarounds来执行此操作,但我不需要它们,因此它们不属于我的解决方案:

(function () {
    angular
        .module("myapp")
        .directive("noDirtyCheck", noDirtyCheck);

    function noDirtyCheck() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function (scope, elem, attrs, ctrl) {
                var alwaysFalse = {
                    get: function () { return false; },
                    set: function () { }
                };
                Object.defineProperty(ctrl, '$pristine', alwaysFalse);
                Object.defineProperty(ctrl, '$dirty', alwaysFalse);
            }
        };
    }
})();

我也在重写$ dirty,所​​以它也不能设置为脏。

答案 2 :(得分:12)

将$ pristine属性设置为false,仅在初始化时才有效,直到您在窗体上调用$ setPristine()为止。然后你的控件将其原始状态恢复为真,并且更改输入的值将使您的表单变脏。 为避免这种情况,请将$ pristine设置为焦点:

link: function(scope, elm, attrs, ctrl) {
    elm.focus(function () {
        ctrl.$pristine = false;
    });
}

答案 3 :(得分:7)

如果控件是原始的,则Angular仅将表单设置为脏。所以这里的诀窍是将控件上的$ pristine设置为false。您可以在控制器中超时执行此操作。

请参阅:http://plnkr.co/edit/by3qTM

答案 4 :(得分:1)

这是我的最终答案。当输入与之交互时,基本上angular会在内部调用 NgModelController $setDirty()函数,所以只需覆盖它!

app.directive('noDirtyCheck', function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: postLink
  };
  function postLink(scope, iElem, iAttrs, ngModelCtrl) {
    ngModelCtrl.$setDirty = angular.noop;
  }
})

答案 5 :(得分:0)

@ overthink答案的变体,带有一些额外的验证,以及内联括号表示,以防止缩小。

"use strict";

angular.module("lantern").directive("noDirtyCheck", [function () {
    return {
        restrict: "A",
        require: "ngModel",
        link: function (scope, elem, attrs, ngModelCtrl) {
            if (!ngModelCtrl) {
                return;
            }

            var clean = (ngModelCtrl.$pristine && !ngModelCtrl.$dirty);

            if (clean) {
                ngModelCtrl.$pristine = false;
                ngModelCtrl.$dirty = true;
            }
        }
    };
}]);

答案 6 :(得分:0)

我遇到了一些实现问题,所以这是我的(更复杂):

&#13;
&#13;
app.directive('noDirtyCheck', [function () {
        // Interacting with input elements having this directive won't cause the
        // form to be marked dirty.
        // http://stackoverflow.com/questions/17089090/prevent-input-from-setting-form-dirty-angularjs
        return {
            restrict: 'A',           
            require: ['^form', '^ngModel'],

            link: function (scope, element, attrs, controllers) {
                var form = controllers[0];
                
                var currentControl = controllers[1];

                var formDirtyState = false;

                var manualFocus = false;

                element.bind('focus',function () {
                    manualFocus = true;
                    if (form) {                        
                        window.console && console.log('Saving current form ' + form.$name + ' dirty status: ' + form.$dirty);
                        formDirtyState = form.$dirty; // save form's dirty state
                    }
                 });
                
                element.bind('blur', function () {
                    if (currentControl) {
                        window.console && console.log('Resetting current control (' + currentControl.$name + ') dirty status to false (called from blur)');
                        currentControl.$dirty = false; // Remove dirty state but keep the value
                        if (!formDirtyState && form && manualFocus) {
                            window.console && console.log('Resetting ' + form.$name + ' form pristine state...');
                            form.$setPristine();
                        }
                        manualFocus = false;
                        //          scope.$apply();
                    }
                });
            }
        };
    }]);
&#13;
&#13;
&#13;