Mike Sav
Mike Sav

Reputation: 15291

Sharing the $scope value between controller and directive

I have a directive that toggles a DIV I have using ng-show. Now when the DIV is visible after 5 seconds I wish it to fade out. The ng-show is toggled using a $scope variable in my controller ($scope.showPopover) which is a boolean, it is either true or false. This is my HTML:

Hello World, I am content but will go after 5 seconds!

You will notice the custom directive is on a child div as in my directive when I tried to use the element it was returning the comment produced by the ng-if. This is my directive

.directive('fadeAnimation', function ($animate) {
        'use strict';
        return{
            restrict: 'A',
            priority: 800,
            link: function (scope, element) {

                scope.$watch('showPopover', function (newValue) {

                    console.log(scope.showPopover); // same as scope.showPopover in the controller

                    if (newValue === true) {    
                        $animate.addClass(element[0].parentNode, 'fade-animiate').then(function () {
                            $animate.removeClass(element[0].parentNode, 'fade-animiate');
                            //scope.showPopover = false;
                            // scope.$apply(); // this produces  Error: [$rootScope:inprog] $digest already in progress
                        });

                    } else if (newValue === false) {
                        //scope.showPopover = false;
                        // scope.$apply(); // this produces  Error: [$rootScope:inprog] $digest already in progress
                    }

                });
            }
        };
    });

As you can see I add and remove a CSS class (with animation) to the parent element. Once this is done I would like to set the scope.showPopover boolean that is in the controller to false as this prevents me having to double click the original link that toggles the popover (as it is false, we toggle to true, the animation hides the DIV but the scope.showPopover or $scope.showPopover is still true). I have tried setting scope.showPopover = false in my directive but this is not updated in the controller. When I try and force a scope.$apply(); I get an error in my console stating Error: [$rootScope:inprog] $digest already in progress. What am I doing wrong?

I have tried setting this in the promise after I remove the css class and when I uncomment the scope.showPopover = false (in the newValue === true condition) the watch doesn't see this change and the watch breaks the next time I toggle the $scope.showPopover in the view. Nothing seems to work, I assume my approach is wrong! Any ideas? Many thanks in advance!

Upvotes: 0

Views: 152

Answers (2)

ruedamanuel
ruedamanuel

Reputation: 1930

You should try using 2-way binding in your directive

HTML

<div ng-show="showPopover" class="popover" fade-animation show-popover="showPopover">Hello World, I am content but will go after 5 seconds!</div>

DIRECTIVE

    app.directive('fadeAnimation', function() {
  return {
      restrict: 'A',
      scope: {
        showPopover: "="
      },
      link: function(scope, element, attr) {
        element.addClass('fade-animation');
        scope.$watch("showPopover", function(value) {
           if(value){
           //you should be able to flip the boolean here and see it in the controller                
           }
        });
      }
  };
});

Upvotes: 0

MamaWalter
MamaWalter

Reputation: 2113

Not sure it fit with your requirement, i used animation hooks to trigger the fade:

Javascript

app.directive('fadeAnimation', function ($timeout) {
  return {
      restrict: 'A',
      link: function(scope, element, attr) {
        element.addClass('fade-animation');
        scope.$watch(attr.ngShow, function (value) {
            if(value){
              $timeout(function(){ scope.showPopover = false; },5000);
            }
        });
      }
  };
})

CSS:

.fade-animation.ng-hide-add.ng-hide-add-active,
.fade-animation.ng-hide-remove.ng-hide-remove-active {
  -webkit-transition: all linear 1s;
  transition: all linear 1s;
}

.fade-animation {
   opacity: 1; 
}

.fade-animation.ng-hide {
   opacity: 0; 
}

DEMO

Upvotes: 0

Related Questions