4

I have the following code

if (testNavigation() && $scope.selections.somethingChanged) {
    return false;
}

in the testNavigation I am calling modal dialog and if I answer Ok in that dialog, I re-set somethingChanged to false. My problem is that when the code is executed, the testNavigation and modal dialog is by-passed and executed later and therefore my test is not working as I need it to work. What should I change in order for my logic to properly work, e.g. first invoke my modal dialog, and proceed accordingly in the main function?

This is my testNavigation method:

var testNavigation = function()
            {                
                if ($scope.selections.somethingChanged) {
                    
                    var modal = $modal.open({
                        controller: function ($scope) {
                            $scope.okClass = 'btn-primary',
                            $scope.okLabel = resourceFactory.getResource('Labels', 'yes'),
                            $scope.cancelLabel = resourceFactory.getResource('Labels', 'cancel'),
                            $scope.title = resourceFactory.getResource('Labels', 'unsavedChanges'),
                            $scope.message = resourceFactory.getResource('Messages', 'unsavedChanges');
                        },
                        templateUrl: '/app/templates/modal'
                    });

                    modal.result.then(function () {
                        
                        $scope.selections.somethingChanged = false;                      
                        
                    });
                }
                
                return true;
            }

I'll try to add more details. I have LoadView() and New() functions in the Index page controller. In both of these functions I need to do the following:

if $scope.selections.somethingChanged = false I need to proceed with the logic.

if $scope.selections.somethingChanged = true I need to pop up a modal dialog asking if I want to go ahead and Cancel my changes or Stay on the current page. If I answer Yes, I want to go ahead with the logic.

So, that's the purpose of the separate testNavigation function. In the languages where each function call is sequential, that would work as I intended. But it doesn't work this way in AngularJS / JavaScript and I am not sure how to make it to work the way I need. We tried few ideas with $q service but didn't get the result.

3
  • 1
    What is the code inside of testNavigation(). Regardless, you will need to use a promise (or a callback). Commented Aug 17, 2015 at 20:53
  • 1
    Call testNavigation() to show the modal, and have a separate handler for when "Ok" is clicked. Commented Aug 17, 2015 at 20:53
  • I added code for testNavigation. Can you show me what do I need to change in it to achieve my goal? Thanks again. Commented Aug 17, 2015 at 20:58

2 Answers 2

2

Make testNavigation() always return a promise (either with the result of the modal, or with false straight away, when somethingChanged is false and you don't want to ask the question. Proceed when this promise is resolved:

var testNavigation = function() {                
    if ($scope.selections.somethingChanged) {        
        var modal = [...]
        return modal.result;  // returns a promise that will be resolved when the modal is closed
    } else {
        return $q.when(true); // returns a promise that will be resolved straight away with true
    }
}

// when used:

testNavigation().then(function() {
    ...do stuff...
})
Sign up to request clarification or add additional context in comments.

1 Comment

This solution at least prevents the race condition I talked about.
0

Without knowing what your test looks like, this is kind of difficult, but from what it looks like, you're creating a race condition.

You call testNavigation() which always returns true, but because $scope.selections.somethingChanged is set to false at some point in the future, $scope.selections.somethingChanged may not finish before the end of that evaluation- so while you're setting $scope.selections.somethingChanged to false in testNavigation, it may or may not be false when the second if is performed:

if( testNavigation() &&  // returns true no matter what.
    $scope.selections.somethingChanged // this is changed with a promise within testNavigation. that promise could either complete or not complete before this is evaluated with the if.
  ){
    return false;
}

var testNavigation = function() {
  if ($scope.selections.somethingChanged) {

    var modal = $modal.open({
      // details
    });

    modal.result.then(function() {
      // this is async and could take place any time between {locationA} and never.
      $scope.selections.somethingChanged = false;
    });
  //{locationA}
  }

  return true;
}

I can imagine that producing some weird results in tests.

8 Comments

This is exactly what I want to achieve. I want to ask a question and if I answer yes on this question I want to proceed.
I don't think this is correct: all this is single-threaded, so nothing can run "in between" evaluating the two conditions of the if.
@Naomi: you can only "proceed" when the modal.result.then callback returns. I'm not sure I understand what you're trying to do in the first block (with the if, where you call testNavigation()) and why you're setting somethingChanged to false... If as you say all you want to do is ask a question and then do X if the answer was yes, then can't you simply do X in that then callback?
I'll try to explain. I have an index page. From that Index page I can either click on the row to open an existing row or click on the new button. The edit form is using tabs slightly different way than the rest of the forms in our application and the usual check for changes is not working. So, I added a watch for form.$dirty and set the property I can access from the Index page. Now, in both New and Edit buttons I want to pop up the modal dialog if that property is true. If I answer Yes on the modal dialog, I need to proceed with the logic in New or Edit. So, I need a common function to call.
I added more content in my question to better explain the problem. Also, that whole solution is because I was unable to solve the other problem referenced here stackoverflow.com/questions/32016037/…
|

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.