2

I am trying to change the default behavior of a Magento Reviews extension such that it will allow a no-vote but only if there is a review attached. I have done enough research to know where to change the code, and I have added a "Cancel Rating" function, but it isn't working exactly as expected, and I can't seem to figure out how to check if a rating is present.

Here is the HTML part where the radios are defined.

<div class="right" id="ratings-right">
    <?php $countRatings = count($this->getRatings()); ?>
    <?php foreach ($this->getRatings() as $_rating): ?>
        <?php if ( $countRatings > 1 ): ?>
        <div class="rating-code" id="ratings-code[<?php echo $_rating->getRatingCode(); ?>]"</div>
        <?php endif; ?>
        <ul>
        <?php $sizeOptions = sizeof($_rating->getOptions()); $index=0; ?>
         <li class="value">
            <div class="rating-cancel"></div>
            <input type="radio" value="0" name="cancel[<?php echo $_rating->getId() ?>]" id="<?php echo $this->escapeHtml($_rating->getRatingCode()) ?>C<?php echo $_rating->getId() ?>" class="radio" /></li>
        <?php foreach ($_rating->getOptions() as $_option): $index++;?>
            <li class="value">
                <div class="separate-rating-star"></div>
                <input type="radio" <?php if ( $sizeOptions ==  $index ) :?><?php endif; ?>name="ratings[<?php echo $_rating->getId() ?>]" id="<?php echo $this->escapeHtml($_rating->getRatingCode()) ?>_<?php echo $_option->getValue() ?>" value="<?php echo $_option->getId() ?>" class="radio" />
            </li>
       <?php endforeach; ?>
        </ul>
    <?php endforeach; ?>
    <input type="hidden" name="validate_rating" class="validate-rating" value="" />
</div>

And here is the JavaScript portion where validation and resetting occur

Validation.addAllThese(
[
    ['validate-rating', '<?php echo $this->__('Please select a rating above OR write your Review below') ?>', function(v) {
        var ratingContainer = document.getElementById('ratings-right');
        var ratings = ratingContainer.getElementsByClassName('rating-code');
        var values;
        var star;
        var error = 1;
        window.console&&console.log("START");
        for (r=0;r < ratings.length; r++ ) {
            values = ratings.getElementsByClassName('value');
            stars = values.getElementsByTagName('radio');
            for (s=0; s < stars.length; s++ ) {
                console.log("Checking star %d.", s);
                if (stars[s].checked == true) {
                    error = 0;
                    window.console&&console.log("Radio %d is checked.\n", s);
                    }
                }
            var review = $('review_field').length;
            window.console&&console.log("Review size %d.", review);
            if ( review > 5 ) {
                error = 0;
                window.console&&console.log("Review size (%d) greater than 5.", review);
                }
            if( error != 0 ) {
                window.console&&console.log("Failed.\n");
                return false;
            } else {
                 window.console&&console.log("Passed.\n");
                 error = 1;
                 }
            }
        return true;
        }]
    ]
);
$(".overall-raiting ul li").click(
    function(){
        var tthis = this;
        var done = 0;
        var $li = $(tthis).parent().children('li');
        $li.removeClass('active');
        $li.each(function(){
            if( done < 1 ) $(this).addClass('active');
            if ( tthis == this ) done++;
            if( done != 1 ) $(this).prop('checked', false);
            })
        if ( done > 0 ) return false;
        $(this).find('input.radio').attr('checked',true);
        }
    );

I can't get the console to consistently report values despite reading questions here about using the delete window['console']; method in firefox with firebug and Chrome. But it appears that my .onclick function is changing all radios to unchecked, including the one that should be checked. And as near as I can tell I am not selecting the radios in the validation portion, I've tried using the .val() and .value properties, but this code is my most recent attempt.

All I want is the radio that is clicked to stay checked with all others unchecked and to validate by determining if any is checked (including the cancel) OR if the textarea 'review_field' contains anything.

My final answer is provided below. It is more elegant than my first solution, but I hope this helps someone in the future.

David Wilkins
  • 574
  • 4
  • 19

2 Answers2

0

According to what you want to do

all others unchecked and to validate by determining if any is checked (including the cancel) OR if the textarea 'review_field' contains anything

this function might help:

function isValidForm() {
   var numRadios = $('#ratings-right input:radio:checked').length,
       reviewContents = $('#review_field').val(),
       isValid = numRadios == 1 || reviewContents != '';

   return isValid;
}
bbird
  • 368
  • 1
  • 6
  • I just tried that for the validation, but it fails under every test. I even removed the code that resets radios and verified with firebug that the radio is checked, and this still results in isValid being false. – David Wilkins May 29 '13 at 19:29
  • I edited my answer... I had put the 'ratings-right' selector as a class instead of ID. Also, I don't know if the 'review_field' is a class or ID so you might need to change that as well. – bbird May 29 '13 at 19:38
  • the review_field is an ID as well, so I have #review_field and #ratings-right and its still failing – David Wilkins May 30 '13 at 12:07
  • Is it possible to post a jsfiddle or a link to the site? I was only able to minimally replicate the page myself from your example and may have missed important DOM elements on the page that interfere with the jQuery selectors I used. Or you could break & watch numRadios and reviewContents in Firebug to see where my function might be going wrong. – bbird May 30 '13 at 15:57
  • I've used your response as well as additional research to find the solution. See the OP, I'm not sure if I should answer my own question with this one... – David Wilkins May 30 '13 at 16:01
  • I would say if your solution is significantly different than mine and more appropriate to the question at hand, then yes, definitely post your answer as it will be more useful to others searching for your same issue. – bbird May 30 '13 at 16:06
0

First, my Javascript logging problem was resolved by an answer to this question: JavaScript console log in Magento

jQuery(document).ready(function(){
   window.console = jQuery('<iframe>').hide().appendTo('body')[0].contentWindow.console;
});

This obviously only works if you are using jQuery.

The remainder of my question was resolved by implementation of a variation of bbird's code:

var rated = 0;
var ratingValue = $('#ratings-right input:radio:checked');
var reviewArea = $('#review_field');
var reviewContents = "";
for (i=0; i<reviewArea.length; i++) {
    reviewContents += reviewArea[i].value;
    }
for (i=0; i<ratingValue.length; i++) {
    if (ratingValue[i].value.length == 1 )
    rated = 1;
    }
console.log("%s", rated);
console.log("%s", reviewContents);
var isValid = rated > 0 || reviewContents != '';
console.log("%s", isValid);
return isValid;

As for the radio buttons themselves, in Magento's database, I added a zero star value with an optionId of 99999. This rating is displayed first among the rating options and in the controller for this, I check for a value less than 9999. This ensures that a zero star rating won't be calculated into the aggregate.

This also allowed all radio buttons to be the same class and name so there is no longer any need to programmatically uncheck anything. Radio buttons' default behavior is that only one radio among a group with the same name is allowed to be checked.

here's the implementation of the radio buttons now:

<div <?php if ($_option->getValue() == "0" ) echo "class=\"rating-cancel\""; else echo "class=\"separate-rating-star\"" ?>></div>
<input type="radio" <?php if ( $sizeOptions ==  $index ) :?><?php endif; ?>name="ratings[<?php echo $_rating->getId() ?>]" id="<?php echo $this->escapeHtml($_rating->getRatingCode()) ?>_<?php echo $_option->getValue() ?>" value="<?php echo $_option->getId() ?>" class="radio" />

This way the first option, which has a value of 0, can by stylized with css to be a cancel button of some sort, and the rest will be stars.

Community
  • 1
  • 1
David Wilkins
  • 574
  • 4
  • 19