Prevent input from setting form $dirty angularjs

前端 未结 7 1422
天涯浪人
天涯浪人 2021-02-07 05:37

I have an ng form on a page. Inside the form I have several controls which need to display a save dialog when the form is dirty, ie form.$dirty = true. However there are some na

相关标签:
7条回答
  • 2021-02-07 06:09

    I ran into some problems with that implementation, so here is mine (more complex):

    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();
                        }
                    });
                }
            };
        }]);

    0 讨论(0)
  • 2021-02-07 06:15

    I used @overthink's solution, but ran into the problem mentioned by @dmitankin. However, I didn't want to attach a handler to the focus event. So instead, I endeavored to override the $pristine property itself and force it to return false always. I ended up using Object.defineProperty which is not supported in IE8 and below. There are workarounds to do this in those legacy browsers, but I didn't need them, so they are not part of my solution below:

    (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);
                }
            };
        }
    })();
    

    I am also overriding $dirty so it can't be set as dirty either.

    0 讨论(0)
  • 2021-02-07 06:16

    Angular only sets the form dirty if the control is pristine. So the trick here is to set $pristine on the control to false. You can do it in a timeout in the controller.

    see: http://plnkr.co/edit/by3qTM

    0 讨论(0)
  • 2021-02-07 06:29

    A variation on @overthink's answer with some additional validation, and inline bracket notation to protect against minification.

    "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;
                }
            }
        };
    }]);
    
    0 讨论(0)
  • 2021-02-07 06:33

    Here's a version of @acacia's answer using a directive and not using $timeout. This will keep your controllers cleaner.

    .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;
        }
      }
    });
    

    Then use it in your form like so:

    <input type="text" name="foo" ng-model="x.foo" no-dirty-check>
    
    0 讨论(0)
  • 2021-02-07 06:33

    Setting the $pristine property to false, only when initializing, works until you call $setPristine() on the form. Then your control has its $pristine back to true and changing the input's value would make your form dirty. To avoid that, set the $pristine on focus:

    link: function(scope, elm, attrs, ctrl) {
        elm.focus(function () {
            ctrl.$pristine = false;
        });
    }
    
    0 讨论(0)
提交回复
热议问题