0
votes

I'm trying to make a 5-point scale. I would like the user to select how they feel about a statement by choosing a value from 1 (strongly disagree) to 5 (strongly agree) on the scale.

I have made the scale using multiple Div's. I use 1 div for each number on the scale. When a user hovers the mouse over a part of the scale, all previous divs will get highlighted. For example, the user hovers over "3 - Agree", divs 1, 2 and 3 will have their background colours updated:

    $(function() {

    // set up values and text
    var scaletext = {
        1: 'Strongly Disagree',
        2: 'Disagree',
        3: 'Neutral',
        4: 'Agree',
        5: 'Strongly Agree'
    };

    var colors = ["red", "darkorange", "yellow", "lightgreen", "green"];

    $('.scale').hover(function() {

        var $this = $(this);

        $this.prevAll('.scale').addBack().each(function(i) {
            $(this).css("background", colors[i])
        })

        $this.siblings('.scale-text').html(scaletext[$this.data('scale')]);

    // on mouse off of hover, set everything back to blank
    }, function() {

        var $this = $(this);

        $this.prevAll('.scale').addBack().css('background-color', '');
        $this.siblings('.scale-text').html("No Rating");

});

When the user hovers off the scale, the scale resets itself and all background elements turn back to white.

What I'm trying to do is add a click event, so that a user clicking on a part of the scale indicates "sets" their decision. What I'd like to happen at that point:

  1. The hover events should be disabled on click on all divs on the scale
  2. If the user clicks again, it should reset the scale and the hover events work again.

I'm playing around with the following to address 1) but its not working. The div I clicked on has its mouse events removed, but if I hover over any other element the events havent been removed. I also cant work out how to address 2). Perhaps there is a better way than what Im thinking.

.click(function() {
        var $this = $(this);

        $this.prevAll('scale').addBack().each(function(i) {
            $(this).unbind("mouseenter mouseleave");
        })

        $this.nextAll('scale').addBack().each(function(i) {
            $(this).unbind("mouseenter mouseleave");
        })

    });

HTML here:

            <table>
            <thead>
                <tr>
                    <td class="section-name">Overall</td>
                    <td></td>
                    <td class="section-total-answered">2 unanswered</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td class="question">Question1</td>
                    <td class="rating">
                        <div class="scale-text">No Rating</div>
                        <div data-scale="1" class="scale scale-1"></div>
                        <div data-scale="2" class="scale scale-2"></div>
                        <div data-scale="3" class="scale scale-3"></div>
                        <div data-scale="4" class="scale scale-4"></div>
                        <div data-scale="5" class="scale scale-5"></div>
                    </td>
                    <td class="comment"><a class="button" href="#">Comment</a></td>
                </tr>
                <tr>
                    <td class="question">Question2</td>
                    <td class="rating">
                        <div class="scale-text">No Rating</div>
                        <div data-scale="1" class="scale scale-1"></div>
                        <div data-scale="2" class="scale scale-2"></div>
                        <div data-scale="3" class="scale scale-3"></div>
                        <div data-scale="4" class="scale scale-4"></div>
                        <div data-scale="5" class="scale scale-5"></div>
                    </td>
                    <td class="comment"><a class="button" href="#">Comment</a></td>
                </tr>
                <tr>
                    <td class="question">Question3</td>
                    <td class="rating">
                        <div class="scale-text">No Rating</div>
                        <div data-scale="1" class="scale scale-1"></div>
                        <div data-scale="2" class="scale scale-2"></div>
                        <div data-scale="3" class="scale scale-3"></div>
                        <div data-scale="4" class="scale scale-4"></div>
                        <div data-scale="5" class="scale scale-5"></div>
                    </td>
                    <td class="comment"><a class="button" href="#">Comment</a></td>                     
                </tr>               
            </tbody>
            <tfoot>
                <td></td>
                <td></td>
                <td><a class="next-button" href="">Next ></a></td>
            </tfoot>
        </table>
3
Have you tried something like this : after the click, use $(".scale").off("hover"); and then do your calculations for the first part.?? - dvenkatsagar
For the second, have you thought of a way like : keep a variable outside the functionwhich will count the number of time the .slide has been clicked, if it is even, you can reset the scale, else if it is odd, dont do anything. - dvenkatsagar

3 Answers

2
votes

Simple solution that should work without having to change much: In your click handler use $this.parent().addClass("clicked"); then in your hover functions test if it's already been clicked before you do anything:

if(!$this.parent().hasClass("clicked"))
{
  /* your code here */
}

on a second click, you can use $this.parent().removeClass("clicked"); and you're back up and running

1
votes

I think you can achieve this, I guess:

First off keep the hover functions seperately:

var HoverOn = function(e){ ... }
var HoverOff = function(e) { ... }

Then you do the hover like this:

$(".scale").on("hover",HoverOn,HoverOff);

For the click, I think this may help(just to give an idea):

var count = 0;
$('.scale').click(function(e) {
    count++;
    var $this = $(this);          
    if(count%2 == 0){
      $this.prevAll('.scale').addBack().css('background-color', '');
      $this.siblings('.scale-text').html("No Rating");
      $this.parent().children().on("hover",HoverOn,HoverOff);
    }else{
       $this.parent().children().off("hover");  
    }
});

So what happens here is that, if you click the .slide, count the number of clicks. This will allow you to control the slide in such a way that, if you click odd number of times, you can switch off hover else do something...

Update: Well as @Nic suggested, it would be more appropriate to use a class on the parent to check if the slide section is clicked.

 $('.scale').click(function(e) {
    var $this = $(this);          
    if(!$this.parent().hasClass('clicked')){
      $this.parent().addClass('clicked');

      ...

      /* Some code to reset the scale */

      ...

      $this.parent().children().on("hover",HoverOn,HoverOff);
    }else{
       $this.parent().removeClass('clicked');
       $this.parent().children().off("hover");  
    }
});
0
votes

I used a combination of Nic and Dvenkatsagars answers to get the solution:

    $('.scale').hover(function() {

        var $this = $(this);

        if(!$this.parent().hasClass("clicked"))
        {
            $this.prevAll('.scale').addBack().each(function(i) {
                $(this).css("background", colors[i])
            })

            $this.siblings('.scale-text').html(scaletext[$this.data('scale')]);
        }

    // on mouse off of hover, set everything back to blank
    }, function() {

        var $this = $(this);

        if(!$this.parent().hasClass("clicked"))
        {
            $this.prevAll('.scale').addBack().css('background-color', '');
            $this.siblings('.scale-text').html("No Rating");
        }

    // once a value has been clicked be sure to stop the mouse off event so
    // that we dont lose the users selected value
    }).click(function() {
        var $this = $(this);

        if(!$this.parent().hasClass("clicked"))
        {
            $this.parent().addClass("clicked");
        } else {
            $this.parent().removeClass("clicked");
        }

    });