我的未保存更改指令需要适用于所有具有不同名称的表单

My unsaved changes directive needs to work for all forms with different names

我有一个指令可以打开一个模式来提醒用户未保存的更改,我需要它来检查具有不同未知名称的脏表单。我曾尝试使用范围来访问表单名称和 this 但没有成功。我可以使用 elem[0].name 访问表单名称,但它不带有 $dirty value.

形式
<form class="form-inline" role="form" name="myFormName" confirm-on-exit>
Cool form html
</form>

app.directive('confirmOnExit', ['modalService', '$rootScope', '$stateParams', '$state', function (modalService, $rootScope, $stateParms, $state) {
return {
    restrict: 'A',       
    link: function (scope, elem, attrs, formCtrl) {

        onRouteChangeOff = $rootScope.$on('$stateChangeStart', routeChange);

        function routeChange(event, newState, newParams, fromState, fromParams) {

            if (scope.myFormName.$dirty) {
                return;
            }

            event.preventDefault();
            var modalOptions = {
                closeButtonText: 'No, I\'ll stay and save them.',
                actionButtonText: 'Yes, Leave and Ignore Changes',
                headerText: 'Unsaved Changes',
                bodyText: 'You have unsaved changes. Do you want to leave the page?'
            };

            modalService.showModal({}, modalOptions).then(function (result) {

                if (result) {
                    onRouteChangeOff(); //Stop listening for location changes
                    $state.go(newState); //Go to page they're interested in
                } else {

                    $state.go(fromState); //Stay on the page and have tab revert to fromState
                }
            });

            return;
        }
    }
};

}]);

尝试使用scope.$eval(attrs.name) 获取与name 属性中的名称关联的变量。它的行为应该与普通范围变量一样,您应该能够访问它的所有属性。

此代码段显示检查 $dirty 有效:

angular.module('test', [])
.directive('testdirective', function () {
    return {
        restrict: 'A',       
        link: function (scope, elem, attrs, formCtrl) {
            console.log(scope.$eval(attrs.name), scope.$eval(attrs.name).$dirty);
        }
    };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Open Console
<div ng-app="test">
  <form testdirective name="testform"></form>
</div>

我建议创建一个用于观察路线变化的服务,您可以在其中注册您想要 spy 的所有表格。表格的注册将由您的指令处理。

我在下面整理了一些代码:

app.directive('confirmOnExit', function (FormChanges) {
    return {
        restrict: 'A',       
        link: function (scope, elem, attrs, formCtrl) {
            FormChanges.register(scope, attrs.name);
        }
    };
}]);

app.factory('FormChanges', function (modalService, $rootScope, $state) {
    var formNames = [];
    var dirtyCallbacks = {};

    $rootScope.$on('$stateChangeStart', function (event, newState, newParams, fromState, fromParams) {
        var hasDirtyForm = false;

        // Check all registered forms if any of them is dirty
        for (var i = 0; i < formNames.length; i++) {
            var name = formNames[i];
            if (dirtyCallbacks[name] && dirtyCallbacks[name]()) {
                // got a dirty form!
                hasDirtyForm = true;
                break;
            }
        }

        if (!hasDirtyForm) {
            // Nothing is dirty, we can continue normally
            return;
        }

        // Something was dirty, show modal
        event.preventDefault();
        var modalOptions = {
            closeButtonText: 'No, I\'ll stay and save them.',
            actionButtonText: 'Yes, Leave and Ignore Changes',
            headerText: 'Unsaved Changes',
            bodyText: 'You have unsaved changes. Do you want to leave the page?'
        };

        modalService.showModal({}, modalOptions).then(function (result) {
            if (result) {
                // clear the current forms
                formNames = [];
                dirtyCallbacks = {};
                $state.go(newState, newParams); //Go to page they're interested in
            } else {
                $state.go(fromState, fromParams); //Stay on the page and have tab revert to fromState
            }
        });

        return;
    });

    $rootScope.$on('$stateChangeSuccess', function () {
        // be sure to clear the registered forms when change was successful
        formNames = [];
        dirtyCallbacks = {};
    });

    var service = {
        // Register a form by giving the scope it's contained in and its name
        register: function (scope, name) {
            scope.$on('$destroy', function () {
                // e.g. an ng-if may destroy the scope, so make sure to remove this form again
                service.remove(name);
            });
            formNames.push(name);
            dirtyCallbacks[name] = function () {
                return scope[name].$dirty;
            };
        },

        remove: function (name) {
            delete dirtyCallbacks[name];
        }
    };

    return service;
});

我无法对其进行测试,因此它可能包含一些小错误 - 请告诉我,我会检查。另请注意,我的代码是 而不是 缩小保存!