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

时间:2015-04-01 15:16:37

标签: javascript angularjs angular-ui-router

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

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

}]);

2 个答案:

答案 0 :(得分:2)

我建议您创建一个服务来观察路线变化,您可以在其中注册要间谍的所有表格。然后,您的指令将处理表格的注册。

我在下面汇总了一些代码:

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

我无法测试它,所以它可能包含一些小错误 - 只是让我知道,我会检查。另请注意,我的代码缩小保存!

答案 1 :(得分:1)

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

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

&#13;
&#13;
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);
        }
    };
});
&#13;
<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>
&#13;
&#13;
&#13;