unsetting bits in javascript producing wrong value - javascript

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?

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/

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);
})

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.

Related

Change html slider step exponentially

I am trying to change the slider step by the power of 10 on each slide but it's not working correctly. I am unsure if I should use stepUp() or change the value of value of step directly.
This is how I increment by the power of 10:
var increment = (function(n) {
return function() {
n = n + 2;
var x = Math.pow(10, n);
console.log(x +" " + "Math.Pow thingy");
return x;
}
Here is how I try to pass it as an argument:
document.getElementById("something").stepUp(increment);
In case anyone is wondering, here is the stepUp() that I am using.
Also, here is a fiddle of my slider: Slider Fiddle #1
I want my slider to step to change to 10,100,1000,10000 on each slide.
Pretty sure you can't really do it your way, you'll need to do some kind of calculation yourself. Step only works for constant numbers
var input = document.getElementById("input")
var output = document.getElementById("output")
function getValue() {
let power = input.value
let result = Math.pow(10, +power)
output.value = result
}
<input id="input" type="range" min="1" max="10" value="1" oninput="getValue()" />
<input type="text" id="output" value="10"/>
The natural behaviour of <input type="range" /> is linear, so you have to engineer the required mapping of natural values to required values.
What you are looking for is slider with a socalled log-linear action such that the slider is set up to yield the logarithm of the values you ultimately want;
<input id="something" name="something" type="range" min="2" max="5" value="3" step="1" class="form-control slider" />
Here, the critical settings are
min="2" - log-base10(100) == 2
max="5" - log-base10(100000) == 5
value="3" - log-base10(1000) == 3
Then to get back to the values you actually want, you have to do an anti-logarithm, or Math.pow(10, x).
var slider = document.getElementById('something');
var output = document.getElementById('demo');
slider.onchange = function() {
output.innerHTML = Math.pow(10, this.value);
}
slider.onchange(); // set output for the initial value
DEMO
EDIT:
The behaviour of an <input type="range" /> slider element is inescapably linear. At its current state of development, HTML offers nothing else.
In order to submit the value you actually want, you can use your slider field as the UI for an underlying hidden field, the value of which is maintained to hold a transform of the linear element's value. Providing you can write code to perform the transformation, you are in business. In this case, it's simple - antilogarithm.
So your HTML might be something like this :
<input id="something-ui" type="range" min="2" max="5" value="3" step="1" class="form-control slider" />
<input id="something-hidden" name="something" type="hidden" />
And the corresponding javascript :
var slider = document.getElementById('something-ui');
var hidden = document.getElementById('something-hidden');
var output = document.getElementById('demo');
slider.oninput = function() { // or onChange
output.innerHTML = hidden.value = Math.pow(10, this.value); // antilogarithm
}
slider.oninput(); // set hidden value and output for the initial value
So now, the UI control still behaves linearly but is given (by demo) the appearance, and a submit behaviour (by something-hidden), of being exponential.
This is one way to do this
// Get DOM refs for the required elements
var slider = document.getElementById('myRange');
var res = document.getElementById('res');
var inc = document.getElementById('inc');
// Initialize Div to show starting value
res.innerHTML = slider.value;
// Register on change handler to update div value if slider is changed
slider.onchange = function(){
res.innerHTML = this.value;
}
// Register a click handler inside a closure to increment exponentially
inc.onclick = (function(){
// Initial increment value
var n = 1;
// Return a click handler function which has access to the variable n because of the closure
return function(){
// Button is clicked, increment by n
slider.stepUp(n);
// Update div value for display
res.innerHTML = slider.value;
// Multilply n by 10 so the next time the increment is 10x
n *= 10;
}
})()
<input type="range" id="myRange" value="1000" min="1" max="1000">
<div id="res"></div>
<button id="inc">Increment</button>

Check number of checkboxes depending on input

I have this following checkbox on my page
<div class="col-sm-6">
<label>Product Show</label>
<input type="checkbox" name="edprodShow" value="1" >Shape<br>
<input type="checkbox" name="edprodShow" value="2" >Color<br>
<input type="checkbox" name="edprodShow" value="3" >Design<br>
</div>
I would get values like 1 or 2 or 3(Externally, like in a JSON and i would extract that data). I want to set first check box if 1 and 1st and 2nd if two check box and all three if I get 3.(i.e) Get only shape for 1 and color + shape for 2 and color+shape+design for 3
I have tried many sources and ways but not finding the appropriate output how can I do it ?
Edit :
Code I tried to do
if(split_data[7].toString() === "1"){
$('#edprodShow').prop('checked', true);
}else if(split_data[7].toString() === "2"){
}else if(split_data[7].toString() === "3"){
$('#edprodShow').prop('checked', true);
}
where split_data[7] gives me 1,2 or 3
Try this.
Sample Json from server
var json = { edprodShow: [1,2,4]};
Code
var checker = function(data){
$("[name='edprodShow']").attr('checked', false);
$.each(data.edprodShow, function(i, value){
$("[name='edprodShow'][value='"+ value +"']").attr('checked', true);
}
}
Call the function
checker(json);
I got the solution dear ☺
you can do this by javascript :
$(document).ready(function(){
var $checkboxes = $('#devel-generate-content-form td input[type="checkbox"]');
$checkboxes.change(function(){
var countCheckedCheckboxes = $checkboxes.filter(':checked').length;
// $('#count-checked-checkboxes').text(countCheckedCheckboxes);
$('#edit-count-checked-checkboxes').val(countCheckedCheckboxes);
})
Here you can see Demo

javascript modify variable

I have this:
var category = "3%2C16%2C6%2C10%2C1%2C19";
in witch category id are 3 16 6 10 1 19 and the %2C is the space between category.
What i want is here:
if (document.getElementById("3").checked = false) {
category = "16%2C6%2C10%2C1%2C19";
}
else {
category = "3%2C16%2C6%2C10%2C1%2C19";
}
I want to make this for all the checkbox that i have, but you can't deselect all the checkbox because the servers don't send you back any data.
This is for filtering the results
It would be easier to use an array, then convert it to this string representation, when needed.
var categories = [];
$('#category-form input').change(function () {
var id = $(this).attr('data-id'),
index = categories.indexOf(id);
if (this.checked && index === -1) {
categories.push(id);
} else if (!this.checked && index !== -1) {
categories.splice(index, 1);
}
});
You can see my working code in this fiddle.
(with multiple checkboxes, string representation, and at least one check)
Try
if (document.getElementById("3").checked === false) {
notice the extra double equals to do a typesafe check
or better still
if (!document.getElementById("3").checked) {
However, as you're using jQuery and you appear to be munging a string together from checked states, which is going to be really brittle with hardcoded strings so maybe something like:
var category = "";
$( "input:checked" ).each(function() {
category = $(this).id + "%2C";
};
Only calling that when you need the output e.g. button press.
As you are using jquery, you can listen to the change event for the checkboxes, then build the list each time one is checked or unchecked. To store the values you can either use the value attribute for the checkbox or add data- attributes.
Getting an array of values and joining them will avoid the trailing %2C.
var category = '';
(function($) {
// cache collection of checkboxes
var cboxes = $('input[type=checkbox]');
cboxes.on('change', function() {
// find the ticked boxes only, and make an array of their category values, then join the values by a space
category = $.makeArray(cboxes.filter(':checked').map(function() {
return $(this).data('category');
//return $(this).val(); // if you store them in value="3"
})).join('%2C');
// output for debug purpose
$('#categoryOutput').html("'" + category + "'");
});
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form>
<input type="checkbox" id="c1" data-category="3" />
<input type="checkbox" id="c2" data-category="16" />
<input type="checkbox" id="c3" data-category="6" />
<input type="checkbox" id="c4" data-category="10" />
<input type="checkbox" id="c5" data-category="1" />
<input type="checkbox" id="c6" data-category="19" />
</form>
<div id="categoryOutput"></div>
Side Note: try to avoid starting element ids with numbers - it is technically invalid and can break things in some scenarios.

Sync Selected Radio Button between 2 radio button groups - Opposites

I need to do something similar to JQuery Sync Selected Radio Button between 2 radio button groups.
I have 2 radio groups -
<input type="radio" name="radio_A" id="radio_A_1" value="1" />1st
<input type="radio" name="radio_A" id="radio_A_2" value="2" />2nd
<input type="radio" name="radio_B" id="radio_B_1" value="1" />1st
<input type="radio" name="radio_B" id="radio_B_2" value="2" />2nd
When radio_A_1 is checked, I need radio_B_2 synced/checked. The relationships would be-
radio_A_1=>radio_B_2
radio_A_2=>radio_B_1
radio_B_1=>radio_A_2
radio_B_2=>radio_A_1
Using the answer provided #8804502
$('input[name=radio_A]').change(function() {
var index = $(this).index('input[name=radio_A]');
console.log(index);
$('input[name=radio_B]:eq(' + index + ')').attr('checked','checked');
});
I get same=>same, but only when A changes-
radio_A_1=>radio_B_1
radio_A_2=>radio_B_2
So if I copy it, changing it if from A=>B to B=>A-
$('input[name=radio_A]').change(function() {
var index = $(this).index('input[name=radio_A]');
console.log(index);
$('input[name=radio_B]:eq(' + index + ')').attr('checked','checked');
});
$('input[name=radio_B]').change(function() {
var index = $(this).index('input[name=radio_B]');
console.log(index);
$('input[name=radio_A]:eq(' + index + ')').attr('checked','checked');
});
I get same=>same, when either A or B changes -
radio_A_1=>radio_B_1
radio_A_2=>radio_B_2
radio_B_1=>radio_A_1
radio_B_2=>radio_A_2
How can I sync them 1=>2/2=>1, instead of 1=>1/2=>2? And can it be done with 1 block of code, instead of 2?
You need to add some code to take the index of the element just clicked and set it to 0 if it is 1, or 1 if it is 0. The first way that came to mind is as follows:
$('input[name=radio_A]').change(function() {
var index = $(this).index('input[name=radio_A]') === 1 ? 0 : 1;
$('input[name=radio_B]:eq(' + index + ')').attr('checked', 'checked');
});
$('input[name=radio_B]').change(function() {
var index = $(this).index('input[name=radio_B]') === 1 ? 0 : 1;
$('input[name=radio_A]:eq(' + index + ')').attr('checked', 'checked');
});
Demo: http://jsfiddle.net/cTQeJ/1/
Though you could also try:
var index = 1 - $(this).index('input[name=radio_A]');
(Or the following demo uses kind of a fun hack if you like to make your code confusing: http://jsfiddle.net/cTQeJ/)
"And can it be done with 1 block of code, instead of 2?"
If you can modify the html slightly it is pretty easy with a single, short code block. Try a change like this:
<input type="radio" name="radio_A" data-sync="1" value="1" />1st
<input type="radio" name="radio_A" data-sync="2" value="2" />2nd
<input type="radio" name="radio_B" data-sync="2" value="1" />1st
<input type="radio" name="radio_B" data-sync="1" value="2" />2nd
I've added a data-sync attribute to each radio button (and removed the id attribute since it wasn't being used, but obviously you can leave that in if needed). Then you can write a simple function like this:
var $radios = $('input[data-sync]');
$radios.change(function() {
$radios.filter('[data-sync="' + $(this).attr('data-sync') + '"]')
.prop('checked', true);
});​
...that basically says whenever any of the radio buttons is checked, find all other radio buttons with a data-sync attribute of the same value and check them too.
Note that this will work with more than two groups, as shown in this demo: http://jsfiddle.net/cTQeJ/2/

How To copy object by value using jquery

Hello I'm having an issue with this check box :
<input type="checkbox" id="hideTempSeries" checked="checked" value="0" />
Temperature <br />
<input type="checkbox" id="hideFlowSeries" checked="checked" value="1" />
Flow <br />
<input type="checkbox" id="hidePressSeries" checked="checked" value="2"/>
Pressure <br />
<input type="checkbox" id="hideCondSeries" checked="checked" value="3" />
Conductivity <br />
.. and this jQuery function that sends an array of this check box values to a function called
removePanes(checkedArray) " every time any of the check boxes have changed "
$("#tools :checkbox").change(function(){
if($(this).prop('checked')){// when Checked
}
else{// when unChecked
var checkedArray = [] ;
$("#tools :checkbox").each(function(index,value){
if($(this).prop('checked') == false){checkedArray.push($(this).val())}
});
removePanes(checkedArray) ;
}
removePanes() function
function removePanes(id){
var removeUncheckedSeries = $.map(newSeries , function(index,value){
for(var i=0 ; i < id.length ; i++){
if(index.yAxis == id[i])return null;
}
return index ;
});
var modified = $.map(removeUncheckedSeries, function(index,value) {
index.yAxis = 15 ;
return index ;
});
console.log(modified) ;
} ;
this is newSeries[] Object
The removePanes(checkedArray) function then takes this array and removes all the objects equivalent to the unchecked values from : newSeries[] object
Then it sets all the yAxis values equal to 15.
This function is not working.
Because each time the check box changed the function doesn't reload the newSeries[] object it just modifies it on the last change.
What it does is, the first click works fine and then it set all the yAxis to 15. When I unchecked any other boxes since all the yAxis equal to 15 and the jQuery array send value from 0 to 3 nothing happened.
QUESTION: How can i make the removePanes(checkedArray) reload with the newSeries[] object each time a change on check box trigger?
That is happening because objects are by default copied by reference
in Javascript.
So if you change any property of copied object from anywhere it will affect all others. To copy an object by value only(or clone) you can use jQuery's $.extend() method like Jonh Resig(Yes he himself) showed here https://stackoverflow.com/a/122704/344304
var newObj = $.extend(true, {}, oldObj); // deep copy
So change your removePanes function like following
function removePanes(id) {
var seriesCopy = jQuery.extend(true, {}, newSeries);
var removeUncheckedSeries = $.map(seriesCopy, function(obj, index) {
return $.inArray(obj.yAxis,id) == -1 ? obj : null;
});
var modified = $.map(removeUncheckedSeries, function(obj, index) {
obj.yAxis = 15;
return obj;
});
console.log(modified);
};​
Demo: http://jsfiddle.net/joycse06/w2KS2/

Categories

Resources