1

Plunker

I have a table of data:

<table class="table table-hover" ng-class="dndElemClass" drag-and-drop>
  ...
</table>

My goal is to give the table a drop shadow by assigning $scope.dndElemClass = 'on-drag-enter' on the element's ondragenter event listener:

.on-drag-enter {
    -webkit-box-shadow: -3px 3px 5px 3px #ccc;
    ...
}

The onDragEnter directive is as follows:

directive('dragAndDrop', function() {
    return {
        restrict: 'A',
        controller: function($scope) {
            $scope.dndElemClass = '';
        },
        link: function($scope, elem, attr) {
            $scope.$watch('currentFolder.canUpload', function(newValue, oldValue) {
                if (newValue && Modernizr.draganddrop && window.File) {
                    elem[0].ondragenter = function(evt) {
                        evt.stopPropagation();
                        evt.preventDefault();
                        $scope.$apply(function() {
                            $scope.dndElemClass = 'on-drag-enter';
                        });
                    };
                    elem[0].ondragleave = function(evt) {
                        evt.stopPropagation();
                        evt.preventDefault();
                        $scope.$apply(function() {
                            $scope.dndElemClass = '';
                        });
                    };
                    elem[0].ondrop = function(evt) {
                        ...
                    };
                }
            });
        }
    }
})

Despite assigning the value of $scope.dndElemClass in the ondragenter and ondragleave event listeners, the <table> doesn't appear to be recognizing the value and assigning the class as no dropshadow appears.

Thus far I've tested that it does recognize the value if I set the class in the controller property of the directive where I have it assigned to blank in the above code, so I know it will accept it from the directive. With the class set in the controller as a test, if I trigger the ondragenter listener, it removes the class. I've also confirmed that the $scope.$apply() is properly assigning the value of scope.dndElemClass with logging, but for whatever reason, when set in the event listeners's $scope.$apply(), the table's ng-class attribute won't recognize the variable assignment and thinks it's empty.


UPDATE: As per Josh's comment, I cleaned up the code so that I didn't have to $apply the variable assignment in the event listener callbacks.

directive('dragAndDrop', function() {
    return {
        restrict: 'A',
        controller: function($scope) {
            $scope.dndElemClass = '';
        },
        link: function($scope, elem, attr) {
            $scope.$watch('currentFolder.canUpload', function(newValue, oldValue) {
                if (newValue && Modernizr.draganddrop && window.File) {
                    elem.bind('dragenter', function(evt) {
                        evt.stopPropagation();
                        evt.preventDefault();
                        $scope.dndElemClass = 'on-drag-enter';
                    });
                    elem.bind('dragleave', function(evt) {
                        evt.stopPropagation();
                        evt.preventDefault();
                        $scope.dndElemClass = '';
                    });
                    elem.bind('drop', function(evt) {
                        //...
                    });
                }
            });
        }
    }
})

Still no luck. I can verify it is executing the callbacks with logging, but no luck on getting the variable assignment to be recognized by the table's ng-class attribute.


UPDATE 2: I am even more confused after reading through AngularJS's documentation on ngClass. To me, I thought it was as simple as setting the name(s in an array) of the classes you want to a variable in the current controller's (or in my case, the directive's) $scope, then specify that variable's name like you would anywhere else in the element's ng-class="" attribute. But as I'm reading, it seems like it's more much complicated as people are using expressions or toggling the class name(s).

Using the idea of toggling, I forked my plunker to recreate the situation setting $scope.dndElemClass to a boolean value based on whether the user triggers dragenter or dragleave. I also included $scope.$apply() for good measure, as I am finding that I don't understand the advantage of angular.bind() over .addEventListener or .ondragenter = function() {};. Regardless, none of this has caused the table's class to get set as I would expect it to.

6
  • Why are you leaving AngularJS World to run an event only to try to re-enter it to set a scope variable? Why not simply use elem.bind('dragenter', function () {...})? Try simplifying your code and see if that solves the problem. Commented Mar 14, 2013 at 20:53
  • Wasn't familiar with Angular's .bind(). After cleaning it up and getting rid of the $apply(), still no luck. Commented Mar 15, 2013 at 14:23
  • It's probably a scope issue. Can you post a simple Plunker to demonstrate? Commented Mar 15, 2013 at 20:06
  • Sure thing, added a link at the top. Commented Mar 20, 2013 at 13:46
  • I am not using ng-class like you do. I do something like: ng-class="{ondrag-nter:dndElemClass}">. Let me know if this works for you so I can add a real answer explaining in more detail. Commented Mar 20, 2013 at 21:11

2 Answers 2

1

I am not sure if you still need an answer, but I might have fixed your plunk.

Inside the CurrentFolder controller, add

$scope.dndElemClass  = '';

Then wrap $scope.dndElemClass inside $apply.

$scope.$apply(function() { $scope.dndElemClass = 'on-drag-enter'; });

Check the complete plunk for a clearer picture.

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

this answer just fixed a similar issue I was having - setting a controller's scope.myVar from inside a directive. The ng-class was waiting for a change but nothing updated when the myVar changed. Wrapping it in that $apply was the trick! Thanks for this answer!
0

try to set class in scope then use class={{classVariable}} !!! This works for me.

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.