2

I've got this listener setup on a form of mine that checks for a state transition to occur via angular router. When the listener is tripped it checks if the form is dirty, if it is it throws a window.confirm alert up saying the user may have unsaved changes.

All of that looks like this

this.setListener('form.dirty-check', this.setExitCheck);

setListener = (el, cb) => {
    if ($(el).length) {
        cb();
    } else {
        setTimeout(() => {
            this.setListener(el, cb);
        }, 500);
    }

};

setExitCheck = () => {
    this.$transitions.onStart({}, () => {
        if ($('#compForm').hasClass('ng-dirty')) {
            if (window.confirm('You may have unsaved changes! Press ok to continue, or press cancel to go back and save your work.') === false) {
                return false;
            } else {
                return true;
            }
        }
    });
};

This code is working pretty well, except for a singular bit of unexpected behaviour.

For some reason, when I hit, "Ok" to leave the page the transition will fire off just fine, but if I go back to the page and try it again, I now have to hit okay twice, and get two window.confirm alerts. If I go back a third time to try, I get three window.confirm alerts, and have to hit Ok on all three of them. I tried this up to the point of receiving 10 alerts, and have to press ok 10 times.

Once I refresh the page though, it seems to reset, and I start it all over again. Works right away, then takes two Ok's, then three, and so on.

Does anyone know what might be going on causing this incremental behaviour?

Chris
  • 443
  • 5
  • 25
  • 1
    angular won't clear listeners for you, you have to clear them manually. here you can clear listeners at `stateChangeStart `/`stateChangeSuccess` event. – Pengyy May 09 '17 at 15:35
  • See that's what I figured, but the documentation for the $transitions.onStart() method states that it returns an immediately invoked function that deregisters itself. I might be misunderstanding the spec though. Do I have to somehow call the Fn the method returns for the deregistration to occur? This is the spec for the onStart() method https://ui-router.github.io/ng1/docs/latest/classes/transition.transitionservice.html#onstart – Chris May 09 '17 at 15:43
  • 1
    yeap, I think you have to call it manually. – Pengyy May 09 '17 at 15:48
  • 1
    here is the issue about this. https://github.com/angular-ui/ui-router/issues/2893 – Pengyy May 09 '17 at 15:49
  • What would that syntax look like? I guess, what I mean is, if the function is returning a function, how do I call that? I might be overthinking it, but I can't figure out what that syntax would look like. If you wanted to throw an answer out about it, that'd be awesome, then I could vote it as the answer too! Either way thanks for your help with all this! – Chris May 09 '17 at 15:51
  • I have post an answer which will deregister it while scope is destroyed. for while using #rootScope.on, you have to clear it to. – Pengyy May 09 '17 at 16:08

1 Answers1

2

ui-router won't clear listeners automatically, so you have to clear it manually.

and $transitions.onStart returns a function which will destroy the listener's hook when it's called. documentation here(the last line).

the syntax is the same as deregister events of $rootScope, refer How can I unregister a broadcast event to rootscope in AngularJS?

$scope.onStartHandler = this.$transitions.onStart(...);

$scope.$on('destroy', function() {
  $scope.onStartHandler();
});
Community
  • 1
  • 1
Pengyy
  • 37,383
  • 15
  • 83
  • 73