1

Implementation Details:

I'm using ui-router to load form page in ui-view div. I referred great example by Andres Ekdahi, How can i do $dirty check on multiple forms using same directive ?

form1

 <form name="myForm" ng-controller="Controller" confirm-on-exit>

form2

<form name="iForm" ng-controller="Controller" confirm-on-exit ng-model="myModel">

app.js ( directive )

myApp.directive('confirmOnExit', function() {
        return {
            link: function($scope, elem, attrs) {
                // condition when back page is pressed 
                window.onbeforeunload = function(){
                    if ($scope.myForm.$dirty) {
                        return "The formI is dirty, do you want to stay on the page?";
                    }
                }
                // condition when user try to load other form (via icons )
                $scope.$on('$stateChangeStart', function(event, next, current) {
                    if ($scope.myForm.$dirty) {
                        if(!confirm("myForm. Do you want to continue ?")) {
                            event.preventDefault();
                        }
                    }

                    if ($scope.iForm.$dirty) {
                        if(!confirm("iform. Do you want to continue ?")) {
                            event.preventDefault();
                        }
                    }
                });
            }
        };
    });

Error:

First time on page load, the $dirty value is false. and I fill the form details and click third icon (file) and i get error for second form dirty check if ($scope.iForm.$dirty) and for $dirty in alert.

angular.js:12520 TypeError: Cannot read property '$dirty' of undefined

and

<form name="iForm" ng-controller="Controller" confirm-on-exit="" ng-model="myModel" class="ng-pristine ng-untouched ng-valid ng-scope">

Demo : Plunker

3 Answers 3

2

There's an easier way.

Just require your directive be placed on a form element and access the form controller through the link function:

myApp.directive('confirmOnExit', function() {
        return {
            require: 'form',
            link: function($scope, elem, attrs, formController) {
                // condition when back page is pressed 
                window.onbeforeunload = function(){
                    if (formController.$dirty) {
                        return "The form '" + formController.$name + "' is dirty, do you want to stay on the page?";
                    }
                }
                // condition when user try to load other form (via icons )
                $scope.$on('$stateChangeStart', function(event, next, current) {
                    if (formController.$dirty) {
                        if(!confirm(formController.$name + ". Do you want to continue ?")) {
                            event.preventDefault();
                        }
                    }
                });
            }
        };
    });
Sign up to request clarification or add additional context in comments.

Comments

1

Make you directive more simpler by taking it from name attribute of form, so that only one condition will lie inside a directive & it can be reusable in many places.

<form name="myForm" ng-controller="Controller" confirm-on-exit>

Code

var form = $scope[attrs.name]; //which will take out form name & do search that inside scope
if (form.$dirty) { //form object would always exist, to make sure you could also add one more check `form &&`
    if(!confirm("myForm. Do you want to continue ?")) {
        event.preventDefault();
    }
}

Demo here

4 Comments

Can you explain me what does $scope[attrs.name] look for ? does this apply only for form data change or any user click ?
@Mad-D that will take out form name, and will search formName inside controller scope.
Thank you sir, I think that's exactly i needed to do.
Don't call me sir, I'm just like you. Glad to help you. Thanks ;)
1

check if the form exists before you check if it is dirty. Do something like

if ($scope.myForm && $scope.myForm.$dirty) {
    if(!confirm("myForm. Do you want to continue ?")) {
        event.preventDefault();
    }
}

if ($scope.iForm && $scope.iForm.$dirty) {
    if(!confirm("iform. Do you want to continue ?")) {
        event.preventDefault();
    }
}

1 Comment

thanks, your answer is right as well. I just needed to check for form existence.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.