0

I have 4 checkboxes. If all 4 check boxes are pressed, I want to produce the Number 15, e.g. "0000 1111". If none of checkboxes are clicked, then it should produce 0, e.g. "0000 0000". In other words, when the checkbox is clicked, the associated bit should be set, else it should be unset. Each checkbox is raised by the power of 2 in order to target the next bit:

<input type="checkbox" name="validation_rules" id="inlineCheckbox1" value="1">
<input type="checkbox" name="validation_rules" id="inlineCheckbox2" value="2">
<input type="checkbox" name="validation_rules" id="inlineCheckbox4" value="4">
<input type="checkbox" name="validation_rules" id="inlineCheckbox8" value="8">

I have it working fine to set the bits:

Below is the relevant method:

listen_for_enabled_change: function(){
  $form.on('click', 'input[name="validation_rules"]', function(){
    var $hidden = $(this).closest('.field-border').find("input[type='hidden'][name='result']");
    var new_val;
    if($(this).get(0).checked) {
      new_val = $hidden.val() | $(this).val();
    } else {
      var mask = 1 << $(this).val()/2;
      new_val = $hidden.val() & ~mask;
    }
    $hidden.val(new_val);
  })
}

Unfortunately, unsetting the bit is not working in the above code. For example, if the hidden input field value is 8. And then I uncheck the checkbox with value 8, it should produce 0. However, it doesn't change the value at all. It just returns the Number 8. What may I be doing wrong?

5
  • 2
    Side note: $(this).get(0) will just get you back this. Commented Jul 2, 2015 at 22:23
  • Is this what you're after? Commented Jul 2, 2015 at 22:29
  • @royhowie yes that's the idea. THe problem with my code is right here: var mask = 1 << $(this).val()/2;. It shifts too far to the right, therefore having no effect on any bits. I thought division by 2 would handle offsets but it does not. Commented Jul 2, 2015 at 22:31
  • Seems like you'd want to left-shift by the values 0,1,2,3 instead of 0,1,2,4. Right? Or just don't shift and divide at all, since they already hold the bit positions you want. Like this: jsfiddle.net/np7kaLkd Commented Jul 2, 2015 at 22:35
  • ...here's a version with a lot less jQuery. Much faster and less verbose. jsfiddle.net/np7kaLkd/1 Commented Jul 2, 2015 at 22:40

3 Answers 3

1

I think your problem is here:

  var mask = 1 << $(this).val()/2;
  new_val = $hidden.val() & ~mask;

The values are [1,2,4,8], which would result in rounded down integers of [0,1,2,4]. Yes thats a 4, should be a 3.

Why not tag the checkbox value as the bit index that needs setting instead?

<input type="checkbox" name="validation_rules" id="inlineCheckbox1" value="0">
<input type="checkbox" name="validation_rules" id="inlineCheckbox2" value="1">
<input type="checkbox" name="validation_rules" id="inlineCheckbox4" value="2">
<input type="checkbox" name="validation_rules" id="inlineCheckbox8" value="3">

Then you can just:

if($(this).get(0).checked) {
  // flip on the bit at the bit index
  new_val = $hidden.val() | (1 << $(this).val());
} else {
  // flip off the bit at the bit index
  new_val = $hidden.val() & ~(1 << $(this).val());
}

Or the whole thing, cleaned up a bit:

var $this = $(this);
var $hidden = $("#result");
var newVal = $hidden.val();
var bit = $this.val()

if (this.checked) {
  newVal = newVal | (1 << bit);
} else {
  newVal = newVal & ~(1 << bit);
}
$hidden.val(newVal);

Working example: https://jsfiddle.net/zjg2gbp3/3/

Sign up to request clarification or add additional context in comments.

4 Comments

I know it was in the question, but this should really get fixed. $(this).get(0).checked.
@squint thanks I fixed that too. Too much dependency on jQuery, I agree.
It's either that or $this[0].checked or the jquery idiomatic $this.is(':checked'). Take your pick :)
Neither... this.checked and I'd skip creating a jQuery object altogether, and just use its .value property.
1

It seems to me that all that bit masking and shifting based on which checkbox was just checked is unnecessarily complicated (premature optimization?), and that instead of manipulating the current $hidden value based on the checkbox that was just checked, you'd get far more readable / less error prone code by simply totalling the value each time any of the checkboxes change:

$form.on('change', 'input[name="validation_rules"]', function () {  // 'change' is more robust than 'click' here    
    var new_val = 0;

    $('input[name="validation_rules"]').each(function(i, elem) {
        if (elem.checked) {
            new_val += parseInt(elem.value, 10);
        }
    });

    $hidden.val(new_val);
})

1 Comment

I have a hunch that @Donato wants to use binary operations. But if not, this is the way to go.
0

I must be missing something but...simple serialise will do:

you can just pass a collection of elements into a function that will add up your bitmasks.

var getBitmask = function(els){
    return Array.prototype.reduce.call(Array.prototype.filter.call(els, function(el){
        return el.checked;
    }), function(a, b){
        return {value: ~~a.value + ~~b.value};
    }).value;
};

console.log(getBitmask(document.querySelectorAll('input[type=checkbox]')));

above works without jQuery.

you can build your bitmasks automatically around the element index as well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.