Skip to content

Instantly share code, notes, and snippets.

@taeo
Last active November 8, 2022 15:18
Show Gist options
  • Save taeo/3ae264fa4aad3463b26f to your computer and use it in GitHub Desktop.
Save taeo/3ae264fa4aad3463b26f to your computer and use it in GitHub Desktop.
Quick hack / jQuery plugin to enable visual star ratings from Gravity Forms radio fields.
<!--
GRAVIY FORMS NOTES:
1. Create a “radio” group on any form
2. In the “appearance" tab, give the custom css class `js-gf-rating-stars`
3. The radio values should be in order from low -> high (1,2,3,4,5,etc…).
4. You can have as many stars as you want, it’s based off the number of radio elements in the group.
5. You could technically have as many groups of ratings stars as you want.
JS CONFIG:
This assumes you are using some iconfont, but the setup would work otherwise with some custom css.
Default assumes font awesome. To modify the icon font, just follow the below example:
$('.js-gf-rating-stars').gformsRatings({
iconClass: "class-name-for-your-icon-fonts-star-icon"
});
-->
<style type="text/css">
.gf-rating-star {
color: gray;
cursor: pointer;
font-size: 2em;
}
.gf-rating-star + .gf-rating-star {
padding-left: 4px;
}
.gf-rating-star-active {
color: orange;
}
</style>
<script>
(function($) {
$(document).ready(function() {
$('.js-gf-rating-stars').gformsRatings();
});
// The meat and potatoes
$.fn.gformsRatings = function( options ) {
// Setup options
var settings = $.extend({
'labels' : false,
'activeClass' : 'gf-rating-star-active',
'iconClass' : 'fa fa-star'
}, options);
return this.each(function() {
// Store the object
var $this = $(this),
$container = $('.ginput_container', $this),
$radioGroup = $('.gfield_radio', $this),
$radios = $('input[type="radio"]', $radioGroup),
$stars = null,
$currentIndex = null;
// Initialize
var init = function() {
$radioGroup.css('display', 'none');
$wrap = $('<div class="gf-rating-stars"></div>');
for (var i = 0; i < $radios.length; i++) {
var label = $radios.eq(i).siblings('label').text(),
value = $radios.eq(i).val(),
$star = $('<i class="js-gf-rating-star gf-rating-star"></i>');
$star
.addClass(settings.iconClass)
.data('index', i)
.data('value', value)
.data('label', label)
.attr('title', label)
.appendTo($wrap);
}
$wrap.appendTo($container);
$stars = $('.js-gf-rating-star');
// Star Interactions
$stars.on('hover', function() {
handleHover($(this));
}).on('click', function() {
handleClick($(this));
});
// Restore to currently checked next field
$wrap.on('mouseout', function() {
$checked = $radios.filter(':checked');
if (!$checked.length) {
$stars.removeClass(settings.activeClass);
} else {
highlight($currentIndex);
}
});
}
var highlight = function(index) {
$stars.filter(':gt(' + index + ')').removeClass(settings.activeClass);
$stars.filter(':lt(' + index + '), :eq(' + index + ')').addClass(settings.activeClass);
}
var handleHover = function(el) {
var index = el.data('index');
highlight(index);
}
var handleClick = function(el) {
var index = el.data('index');
$currentIndex = index;
$radios.eq(index).trigger('click');
}
// Kick it off
init();
});
};
})(jQuery);
</script>
@SimonVetterli
Copy link

@taeo

Hello

I have 5 radio groups. But somehow, they get all the same classes: https://chilli-cycling.asia/customer-review-form/

How can I change this?

Regards,
Simon

@taeo
Copy link
Author

taeo commented Jun 21, 2021

Hi @SimonVetterli - can you be more specific about your issue?
"They get all the same classes" is too vague for me to spend time helping.

@SimonVetterli
Copy link

SimonVetterli commented Jun 21, 2021

Hi @taeo

Okay...

I have on the link I provided 5 radio group fields: https://chilli-cycling.asia/customer-review-form/

Each of them I have a separate script:

`<script>
(function($) {

$(document).ready(function() {
    $('.js-gf-rating-stars-1').gformsRatings();
});

// The meat and potatoes
$.fn.gformsRatings = function( options ) {

    // Setup options
    var settings = $.extend({
        'labels' : false,
        'activeClass' : 'gf-rating-star-active-1',
        'iconClass' : 'far fa-star'
    }, options);

    return this.each(function() {

        // Store the object
        var $this = $(this),
            $container = $('.ginput_container', $this),
            $radioGroup = $('.gfield_radio', $this),
            $radios = $('input[type="radio"]', $radioGroup),
            $stars = null,
            $currentIndex = null;

        // Initialize
        var init = function() {

            $radioGroup.css('display', 'none');
            $wrap = $('<div class="gf-rating-stars-1"></div>');
            for (var i = 0; i < $radios.length; i++) {
                var label = $radios.eq(i).siblings('label').text(),
                    value = $radios.eq(i).val(),
                    $star = $('<i class="js-gf-rating-star-1 gf-rating-star-1"></i>');

                $star
                    .addClass(settings.iconClass)
                    .data('index', i)
                    .data('value', value)
                    .data('label', label)
                    .attr('title', label)
                    .appendTo($wrap);
            }
            $wrap.appendTo($container);
            $stars = $('.js-gf-rating-star-1');
            // Star Interactions
            $stars.on('hover', function() {
                handleHover($(this));
            }).on('click', function() {
                handleClick($(this));
            });

            // Restore to currently checked next field
            $wrap.on('mouseout', function() {
                $checked = $radios.filter(':checked');
                if (!$checked.length) {
                    $stars.removeClass(settings.activeClass);
                } else {
                    highlight($currentIndex);
                }
            });
        }

        var highlight = function(index) {
            $stars.filter(':gt(' + index + ')').removeClass(settings.activeClass);
            $stars.filter(':lt(' + index + '), :eq(' + index + ')').addClass(settings.activeClass);
        }
        var handleHover = function(el) {
            var index = el.data('index');
            highlight(index);
        }
        var handleClick = function(el) {
            var index = el.data('index');
            $currentIndex = index;
            $radios.eq(index).trigger('click');
        }
        // Kick it off
        init();
    });
};

})(jQuery);
</script>`

With different classes defined.

But when hovering the second one, it only change the colors respectively the status to active of the first one. when hovering the fourth one, it changes the status to active on the first one.

Anything I am missing?

@timoh6
Copy link

timoh6 commented Aug 27, 2021

Here is a fixed version which addresses the issue with multiple radio groups. Also, handleHover gets now called and clicking a star immediately makes it selected.

Ping @SimonVetterli @gaganwalia

(function($) {

    $(document).ready(function() {
        $('.js-gf-rating-stars').gformsRatings();
    });

    // The meat and potatoes
    $.fn.gformsRatings = function( options ) {

        // Setup options
        var settings = $.extend({
            'labels' : false,
            'activeClass' : 'gf-rating-star-active',
            'iconClass' : 'fa fa-star'
        }, options);

        return this.each(function() {

            // Store the object
            let $this = $(this),
                $container = $('.ginput_container', $this),
                $radioGroup = $('.gfield_radio', $this),
                $radios = $('input[type="radio"]', $radioGroup),
                $stars = null,
                $currentIndex = null;

            // Initialize
            let init = function() {

                $radioGroup.css('display', 'none');

                $wrap = $('<div class="gf-rating-stars"></div>');

                for (let i = 0; i < $radios.length; i++) {
                    let label = $radios.eq(i).siblings('label').text(),
                        value = $radios.eq(i).val(),
                        $star = $('<i class="js-gf-rating-star gf-rating-star"></i>');

                    $star
                        .addClass(settings.iconClass)
                        .data('index', i)
                        .data('value', value)
                        .data('label', label)
                        .attr('title', label)
                        .appendTo($wrap);

                }

                $wrap.appendTo($container);
                
                $stars = $('.js-gf-rating-star', $this); // Fix issue with multiple radio groups

                // Star Interactions
                $stars.on('mouseover', function() { // Mouseover instead of hover
                    handleHover($(this));
                }).on('click', function() {
                    handleClick($(this));
                }).on('mouseout', function() {
                    handleOut($(this));
                });

                // Restore to currently checked next field
                $wrap.on('mouseout', function() {
                    $checked = $radios.filter(':checked');

                    if (!$checked.length) {
                        $stars.removeClass(settings.activeClass);
                    } else {
                        highlight($currentIndex);
                    }
                });
            }

            let highlight = function(index) {
                $stars.filter(':gt(' + index + ')').removeClass(settings.activeClass);
                $stars.filter(':lt(' + index + '), :eq(' + index + ')').addClass(settings.activeClass);
            }

            let handleHover = function(el) {
                let index = el.data('index');

                if (index >= $currentIndex) { // Do not apply to stars lesser than
                    highlight(index);
                }
            }

            let handleOut = function(el) { // Empty selections if not clicked
                if ($currentIndex === null) {
                    $stars.removeClass(settings.activeClass);
                }
            }

            let handleClick = function(el) {
                let index = el.data('index');
                highlight(index); // Highlight immediately after clicking
                $currentIndex = index;
                $radios.eq(index).trigger('click');
            }

            // Kick it off
            init();

        });

    };

})(jQuery);

@prescottt
Copy link

@timoh6 @taeo huge thanks to both of you, this was exactly what I needed, works a charm!

@gfarquhar
Copy link

I created a form and had this working fine and then duplicated that form to work off of and it won't work on the second form. Any suggestions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment