0

I have a directive that inherits scope from its parent controller. The directive is a div element that overlays the page for three seconds then disappears unless an up/down arrow button is clicked. The div element acts as kind of a modal. This is the code on my DOM

HTML

<div ng-show="volumeVisibility">
    <display-volume-modal></display-volume-modal>
</div>

The default setting is false. When volumeVisibility === true, the directive will appear upon a button click. So far, so good. These are my two functions in the controller:

$scope.volumeVisibility = false;

$scope.timer = function(){ 
    console.log("Timer");
    $scope.volumeVisibility = false;
};

$scope.displayVolumeModal = function(){
    $scope.volumeVisibility = true;
    console.log("modal");   
};

The timeout works and sets $scope.volumeVisibility === false. However, the div does not remove itself from the page. Here is the code from the directive (I've removed the irrelevant parts):

return {
    restrict: 'E',
    scope: false,
    link: function(scope, elem, attrs){
        scope.$watch('volumeVisibility', function(newVal, oldVal){
            if (newVal === true){
                window.setTimeout(scope.timer, 3000);           
                document.addEventListener('keydown', function(e){
                    //stuff
                    switch (e.which) {              
                        case 38:
                            //stuff
                            break;
                        case 40:
                            //stuff
                            break;
                    }
                });
            }
        }, true);
    },
    templateUrl: 'public/templates/displayVolumeModal.html'
}

I've tried putting each function into the directive or the controller. What step can I take to make this directive DIV element disappear after timeout?

2
  • Can you provide scope.timer function body? Commented Jun 11, 2016 at 19:06
  • this comes to mind from the first glance: try placing your ng-show inside display-volume-modal and get rid of div Commented Jun 11, 2016 at 19:07

3 Answers 3

1

Nothing happens because no digest cycle was called.

To update sync, you have to run digest cycle. I think, in this case, you can use $timeout service instead of setTimeout.

Benefits of $timeout service:

  • unit testable
  • $digest cycle starts after function you passed to the timeout
Sign up to request clarification or add additional context in comments.

2 Comments

You got it! It was the $timeout service! Thank you!
Actually, you can use another methods to call digest cycle. Something like $evalAsync method in scope object, but I don't think it is good solution. $timeout - what you need. Also, $timeout can be easily mocked in unit tests
1

window.setTimeout(scope.timer, 3000); does not call angular digest cycle, so watch doesn't see the changes.

Use angular's $timeout service instead like this:

$timeout(scope.timer, 3000);

Internally it does the same as window.setTimeout, but makes sure, that digest will be called after.

Read more about angular digest cycle and how angular checks if some variable changed. Especially the Integration with the browser event loop chapter.

1 Comment

You got it! It was the $timeout service! Thank you!
0

If you use ng-show and ng-hide it will simply make the visibility hidden of the particular html element on which it is applied. The element will be there in the DOM, no matter if it's ng-hide or ng-show. This is why the directive is not being called.

If you want to call the directive everytime it appears on the screen, simply use ng-if instead of ng-show.

Comments

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.