Change class on mouseover in directive
Solution 1
In general I fully agree with Jason's use of css selector, but in some cases you may not want to change the css, e.g. when using a 3rd party css-template, and rather prefer to add/remove a class on the element.
The following sample shows a simple way of adding/removing a class on ng-mouseenter/mouseleave:
<div ng-app>
<div
class="italic"
ng-class="{red: hover}"
ng-init="hover = false"
ng-mouseenter="hover = true"
ng-mouseleave="hover = false">
Test 1 2 3.
</div>
</div>
with some styling:
.red {
background-color: red;
}
.italic {
font-style: italic;
color: black;
}
See running example here: jsfiddle sample
Styling on hovering is a view concern. Although the solution above sets a "hover" property in the current scope, the controller does not need to be concerned about this.
Solution 2
I have run into problems in the past with IE and the css:hover selector so the approach that I have taken, is to use a custom directive.
.directive('hoverClass', function () {
return {
restrict: 'A',
scope: {
hoverClass: '@'
},
link: function (scope, element) {
element.on('mouseenter', function() {
element.addClass(scope.hoverClass);
});
element.on('mouseleave', function() {
element.removeClass(scope.hoverClass);
});
}
};
})
then on the element itself you can add the directive with the class names that you want enabled when the mouse is over the the element for example:
<li data-ng-repeat="item in social" hover-class="hover tint" class="social-{{item.name}}" ng-mouseover="hoverItem(true);" ng-mouseout="hoverItem(false);"
index="{{$index}}"><i class="{{item.icon}}"
box="course-{{$index}}"></i></li>
This should add the class hover and tint when the mouse is over the element and doesn't run the risk of a scope variable name collision. I haven't tested but the mouseenter and mouseleave events should still bubble up to the containing element so in the given scenario the following should still work
<div hover-class="hover" data-courseoverview data-ng-repeat="course in courses | orderBy:sortOrder | filter:search"
data-ng-controller ="CourseItemController"
data-ng-class="{ selected: isSelected }">
providing of course that the li's are infact children of the parent div
Solution 3
This is my solution for my scenario:
<div class="btn-group btn-group-justified">
<a class="btn btn-default" ng-class="{'btn-success': hover.left, 'btn-danger': hover.right}" ng-click="setMatch(-1)" role="button" ng-mouseenter="hover.left = true;" ng-mouseleave="hover.left = false;">
<i class="fa fa-thumbs-o-up fa-5x pull-left" ng-class="{'fa-rotate-90': !hover.left && !hover.right, 'fa-flip-vertical': hover.right}"></i>
{{ song.name }}
</a>
<a class="btn btn-default" ng-class="{'btn-success': hover.right, 'btn-danger': hover.left}" ng-click="setMatch(1)" role="button" ng-mouseenter="hover.right = true;" ng-mouseleave="hover.right = false;">
<i class="fa fa-thumbs-o-up fa-5x pull-right" ng-class="{'fa-rotate-270': !hover.left && !hover.right, 'fa-flip-vertical': hover.left}"></i>
{{ match.name }}
</a>
</div>
default state:
on hover:
Solution 4
I think it would be much easier to put an anchor
tag around i
. You can just use the css :hover
selector. Less moving parts makes maintenance easier, and less javascript to load makes the page quicker.
This will do the trick:
<style>
a.icon-link:hover {
background-color: pink;
}
</style>
<a href="#" class="icon-link" id="course-0"><i class="icon-thumbsup"></id></a>
Related videos on Youtube
Rob Paddock
Updated on July 05, 2022Comments
-
Rob Paddock about 2 years
I am having trouble working out how to get a class to change on a nested directive.
This is the outer ng-repeat
<div data-courseoverview data-ng-repeat="course in courses | orderBy:sortOrder | filter:search" data-ng-controller ="CourseItemController" data-ng-class="{ selected: isSelected }">
Below is the inner ng-repeat which is using another directive
<li data-ng-repeat="item in social" class="social-{{item.name}}" ng-mouseover="hoverItem(true);" ng-mouseout="hoverItem(false);" index="{{$index}}"><i class="{{item.icon}}" box="course-{{$index}}"></i></li>
Here is the directive im calling for the hover event
ecourseApp.directive("courseoverview", function() { return { restrict : 'A', replace: true, /*scope: { index: '@' },*/ transclude: true, templateUrl: "views/course-overview.html", link: function link(scope, element, attrs) { scope.switched = false; //hover handler scope.hoverItem = function(hovered){ if (hovered) { element.addClass('hover'); $('#course-0 figure').addClass('tint') } else element.removeClass('hover'); }; } }});
This needs
$('#course-0 figure').addClass('tint')
to change the calling item. -
Rob Paddock about 11 yearsSorry this is not what im looking for. Basically I Have a list of items that are produced in my first ng-repeat using a directive to display them. In that directive there is another hg-repeat using another directive, i want to add a class on the specific item from the first loop
-
DusanV about 11 yearsyou can use
ng-class
to dynamically assign a class to an element - docs.angularjs.org/api/ng.directive:ngClass, or, you can use a regularclass
attribute. -
Aaron Campbell about 8 yearsLimitation: this solution does not allow the hover-class to be further conditioned; e.g. you can't do
ng-class="{active: isHovering && myBool}"
. -
Aaron Campbell about 8 yearsLimitation: the
hover
scope variable has to be uniquely named, which isn't always trivial, especially onng-repeat
ed elements. -
Aaron Campbell about 8 years^ This limitation can be resolved by using an AngularJS expression for the class name that resolves to a string (either with
{{}}
or by changinghoverClass: '@'
to'='
or'&'
). For example:hover-class="{{ myBool ? 'active' : '' }}"
-
ryanve over 7 yearsI needed something similar and published it on npm npmjs.com/package/hover-class
-
Bas Goossen almost 7 years@AaronCampbell: Each repeated object created by ng-repeat lives in it's own scope. So as long as you init the hover variable on the element the variable scope is individual for each object. (i edited the above example to include this).
-
JGallardo over 4 yearsvoting down because it is not in javascript content. The approach however is valid, but would be best as a comment.