Change class on mouseover in directive

105,421

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: enter image description here

on hover: enter image description here

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>

jsfiddle example

Share:
105,421

Related videos on Youtube

Rob Paddock
Author by

Rob Paddock

Updated on July 05, 2022

Comments

  • Rob Paddock
    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
    Rob Paddock about 11 years
    Sorry 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
    DusanV about 11 years
    you can use ng-class to dynamically assign a class to an element - docs.angularjs.org/api/ng.directive:ngClass, or, you can use a regular class attribute.
  • Aaron Campbell
    Aaron Campbell about 8 years
    Limitation: 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
    Aaron Campbell about 8 years
    Limitation: the hover scope variable has to be uniquely named, which isn't always trivial, especially on ng-repeated elements.
  • Aaron Campbell
    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 changing hoverClass: '@' to '=' or '&'). For example: hover-class="{{ myBool ? 'active' : '' }}"
  • ryanve
    ryanve over 7 years
    I needed something similar and published it on npm npmjs.com/package/hover-class
  • Bas Goossen
    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
    JGallardo over 4 years
    voting down because it is not in javascript content. The approach however is valid, but would be best as a comment.