Complementary State with 2 checkboxes in knockout.js - javascript

I have two checkboxes That I would like to have complementary states.
for example: one checkbox is initially selected, so automatically, the other one is unchecked. If I toggle each one of them, the other one toggles too, but with a complementary state.
How can I do this with html and ko.js?

No need any library to do it. You can use it with pure JavaScript as below.
var cb = document.querySelectorAll('input[type=checkbox]');
let toggleCb = function(i){
let index = i ? 0 : 1;
cb[index].checked = !cb[index].checked;
}
for(let i=0; i<=1; i++){
cb[i].onclick = function(){
toggleCb(i);
}
}
<input type="checkbox" id="cb1" checked />
<input type="checkbox" id="cb2" />

Edit:
After seeing your comments, hope I've got this right.
You want the initial values to come from another viewmodel.
Both checkboxes can be unchecked but only 1 can be checked at a time after the initial setting is done. Correct? In this case writable computed observables are no longer required.
var viewmodel1 = function(){
var self = this;
self.initialValueCheckA = false;
self.initialValueCheckB = true;
};
var viewmodel2 = function(data){
var self = this;
self.checkA = ko.observable(data.initialValueCheckA);
self.checkB = ko.observable(data.initialValueCheckB);
self.checkA.subscribe(function(newAValue){
if(newAValue){
self.checkB(false);
}
});
self.checkB.subscribe(function(newBValue){
if(newBValue){
self.checkA(false);
}
});
};
var instance1 = new viewmodel1();
var instance2 = new viewmodel2({
initialValueCheckA: instance1.initialValueCheckA,
initialValueCheckB: instance1.initialValueCheckB
});
ko.applyBindings(instance1, document.getElementById('section1'));
ko.applyBindings(instance2, document.getElementById('section2'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div id="section1">
A
<input type="checkbox" data-bind="checked: initialValueCheckA" />
B
<input type="checkbox" data-bind="checked: initialValueCheckB" />
</div>
<div id="section2">
A
<input type="checkbox" data-bind="checked: checkA" />
B
<input type="checkbox" data-bind="checked: checkB" />
</div>

Related

change an array depending on whether the checkbox is checked or unchecked using vanilla JavaScript

I am quite new to javascript. Any help very appreciated.
I have created a simplified example for easier explanation. I want to change a finalArray according to whether the checboxes are checked or unchecked.
So for example if friends and strangers checkboxes are checked then the finalArray_ should = ["friend1" ,"friend2", "stranger1", "stranger2"].
If only enemies checkbox is checked then the finalArray_ should = ["enemy1" ,"enemy2"]. And so on.
<body>
<input type="checkbox" data-id="friends_"> Friends <br />
<!-- other code and functionality -->
<input type="checkbox" data-id="enemies_"> Enemies <br />
<!-- other code and functionality -->
<input type="checkbox" data-id="strangers_"> Strangers <br />
<script>
const friends_ = ["friend1","friend2"];
const enemies_ = ["enemy1","enemy2"];
const strangers_ = ["stranger1","stranger2"];
</script>
</body>
I tried this, but I know it's a crappy solution that doesn't work because I can't concat a string like this.
<script>
const friends_ = ["friend1", "friend2"];
const enemies_ = ["enemy1", "enemy2"];
const strangers_ = ["stranger1", "stranger2"];
const checkboxes = document.querySelectorAll("input[type=checkbox]");
checkboxes.forEach(function (checkbox) {
checkbox.addEventListener('change', function () {
checked_boxes = Array.from(checkboxes).filter(i => i.checked).map(i => i.dataset.id).join();
const finalArray = [].concat(checked_boxes);
console.log(finalArray); //Array [ "friends_,strangers_" ]
})
})
</script>
Thanks for your suggestions.
I joined the different units into a single object so I can use the data-id as a key to get the array.
I haven't ran it since I made this on my phone, but you can try it and it should work.
ED:
I've changed it on my computer now. Should run and show you the output when clicking the checkboxes.
ED2:
I moved all the logic into a function which is called on pageload and when a checkbox is toggled.
const units = {
friends_: ["friend1", "friend2"],
enemies_: ["enemy1", "enemy2"],
strangers_: ["stranger1", "stranger2"],
}
let selectedUnits = [];
const checkBoxes = document.querySelectorAll("input[type=checkbox]");
checkBoxes.forEach(elm => elm.addEventListener("change", updateUnits));
document.onload = updateUnits();
function updateUnits() {
selectedUnits = Array.from(checkBoxes)
.filter(elm => elm.checked)
.flatMap(elm => units[elm.getAttribute('data-id')]);
console.clear();
console.log(selectedUnits);
}
<body>
<input type="checkbox" data-id="friends_" checked> Friends <br />
<!-- other code and functionality -->
<input type="checkbox" data-id="enemies_"> Enemies <br />
<!-- other code and functionality -->
<input type="checkbox" data-id="strangers_"> Strangers <br />
</body>
You can create a dict using Set and obj of key-value pairs of checkbox data.
When a checkbox is checked then you can toggle its id in dict and then get results by iterating dict
const friends_ = ["friend1", "friend2"];
const enemies_ = ["enemy1", "enemy2"];
const strangers_ = ["stranger1", "stranger2"];
const dict = new Set();
const obj = { friends_, enemies_, strangers_ };
const checkboxes = document.querySelectorAll( "input[type=checkbox]" );
checkboxes.forEach( function ( checkbox ) {
checkbox.addEventListener( 'change', function (e) {
const id = e.target.dataset.id;
if(dict.has(id)) dict.delete(id);
else dict.add(id);
const result = [];
for(let key of dict) result.push(...obj[key])
console.log(result);
} )
} )
body {
display: flex;
}
<input type="checkbox" data-id="friends_" id="Friends" />
<label for="Friends">Friends</label>
<!-- other code and functionality -->
<input type="checkbox" data-id="enemies_" id="Enemies" />
<label for="Enemies">Enemies</label>
<!-- other code and functionality -->
<input type="checkbox" data-id="strangers_" id="Strangers" />
<label for="Strangers">Strangers</label>

Return CheckBox True False Status With jQuery Map

I am creating dynamic CheckBoxes using jQuery and by default, those are set to false status. Something as follows:
<input type="checkbox" class="cbCheck" value="false" />
So you can see no value or id is assigned there. Is it possible to just retrieve the true/false based on CheckBox checked/unchecked status something as follows using jQuery mapping?
string = $('input[type=checkbox]:checked').map(function (i, elements) {
return elements; //Here the elements like true or false, instead of elements.value
});
alert(string.join(','));
Expected Output: true, false, false, true (Based on user selection)
You can use the checked property.
const string = Array.from($('input[type=checkbox]')).map(function(element) {
return element.checked; //Here the elements like true or false, instead of elements.value
});
console.log(string.join(","));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="checkbox" class="cbCheck" checked/>
<input type="checkbox" class="cbCheck" />
<input type="checkbox" class="cbCheck" />
<input type="checkbox" class="cbCheck" checked/>
var checkboxes = [];
function createDynamicCheckBoxes() {
if (checkboxes.length != 0)
return;
var numberOfBoxes = parseInt(Math.random() * 10) + 1;
for (var i = 0; i < numberOfBoxes; i++) {
var checkbox = document.createElement('input');
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("value", "false");
var number = document.createElement('label');
number.innerText = "(" + (checkboxes.length+1) + ") ";
document.getElementById("container").appendChild(number);
document.getElementById("container").appendChild(checkbox);
document.getElementById("container").appendChild(document.createElement('br'));
checkboxes.push(checkbox);
}
}
function logValues(){
for(var i=0; i<checkboxes.length;i++){
console.log("Checkbox (" + (i+1) + ") is set to " + checkboxes[i].checked);
}
}
<button onclick="createDynamicCheckBoxes()">Generate Checkboxes</button>
<button onclick="logValues()">Log Values of Checkboxes</button>
<div id="container">
</div>
This is a pure JavaScript based snippet. You can do something like this!
The .checked property return check/uncheck status of checkbox. So you need to use it.
var string = $('[type=checkbox]').map(function (i, elements) {
return elements.checked;
}).toArray().join(",");
Also you can simplify the code
var string = $(':checkbox').map((i,ele) => ele.checked).toArray().join(",");
var string = $(':checkbox').map((i,ele) => ele.checked).toArray().join(",");
console.log(string);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="checkbox" class="cbCheck" />
<input type="checkbox" class="cbCheck" checked />
<input type="checkbox" class="cbCheck" />

Tricky Javascript logic with Objects, Array and Booleans

I am having a lot of issue trying to figure out this logic. Let me set the stage here:
In the HTML there are some form/input elements type radio. Each of them have an ID assigned to it.
<form>
<input type="radio" name="oneAllowed" id="yesterday" />
<input type="radio" name="oneAllowed" id="today" />
<input type="radio" name="oneAllowed" id="tomorrow" />
</form>
Using Javascript essentially what I am trying to do is loop through the 3 objects, since they all have same name assigned within HTML only a single one can be selected, whichever one is returning true I want grab hold of that result then access the second key:value pair, for example for 'commitYesterday' it would be 'commitYesterday.hasValue();' and dispatch that to a different function for other calculation.
var urgentOrderSelector = function(){
var commitYesterday = {
isChecked: document.getElementById("yesterday").checked,
hasValue: function(){
if (this.isChecked == true) {
return 3;
};
};
};
var commitToday = {
isChecked: document.getElementById("today").checked,
hasValue: function(){
if (this.isChecked == true) {
return 2;
};
};
};
var commitTomorrow = {
isChecked: document.getElementById("tomorrow").checked,
hasValue: function(){
if (this.isChecked == true) {
return 1;
};
};
};
var urgentArray = [commitYesterday.isChecked, commitToday.isChecked, commitTomorrow.isChecked];
for(var i = 0; i <= urgentArray.length-1; i++){
if (urgentArray[i].isChecked == true) {
//This is where I am stuck. I was thinking of doing perhaps the following:
return urgentArray[i].hasValue();
};
}
};
Why don't you change your HTML to this:
<form>
<input type="radio" name="oneAllowed" id="yesterday" value="3" />
<input type="radio" name="oneAllowed" id="today" value="2" />
<input type="radio" name="oneAllowed" id="tomorrow" value="1" />
</form>
And use document.querySelector to get the selected elements:
document.querySelector('[type="radio"][name="oneAllowed"]:checked').value
If you actually need to run specific functions dependend on which radio box is checked you could add an attribute data-fn="fnName" to each input and then create an object with the keys as functions:
var fns = {'fnName1': function () {}, 'fnName2': function() {} …};
And then call the function defined by the Attribute:
fns[document.querySelector('[type="radio"][name="oneAllowed"]:checked').getAttribute('data-fn')]();
Not exactly sure what your end goal is.
But here's a more minified version of your logic. Hope it helps.
var urgentOrderSelector = function(){
var radioDict = {'yesterday':3, 'today':2, 'tomorrow':1};
return radioDict[$('input[name=oneAllowed]:checked').attr('id')];
};
Alternatively, if you wanted to execute some function based on the selection, you could store the function pointers and execute them accordingly, ie:
var funcYesterday = function(){alert('yesterday');};
var funcToday = function(){alert('today');};
var funcTomorrow = function(){alert('tomorrow');};
var funcUrgentOrder = function(){
var radioDict = {
'yesterday' : funcYesterday,
'today' : funcToday,
'tomorrow' : funcTomorrow
};
return radioDict[$('input[name=oneAllowed]:checked').attr('id')]();
};
Or, much simpler, since you are using the 'value' property on your radios:
function urgentOrderSelector = function() {
return $('input[name=oneAllowed]:checked').val();
};

Looping through checkboxes with javascript

I have a number of checkboxes which I am wanting to check if they are checked (1) or not checked (0). I want to place the results in an array so that I can send them to the server to saved in a table. I have tried the below code:
<input class="publish" id="chkBox1" type="checkbox" checked>
<input class="publish" id="chkBox2" type="checkbox" checked>
<input class="publish" id="chkBox3" type="checkbox" checked>
<input class="publish" id="chkBox4" type="checkbox" checked>
<input class="publish" id="chkBox5" type="checkbox" checked>
<script>
$('#save-btn').click(function(evt){
evt.preventDefault();
var numberOfChBox = $('.publish').length;
var checkArray = new Array();
for(i = 1; i <= numberOfChBox; i++) {
if($('#chkBox' + i).is(':checked')) {
checkArray[i] = 1;
} else {
checkArray[i] = 0;
}
}
alert(checkArray);
});
</script>
but the alert outputs this:
,1,0,1,0,1,1
The values are correct except the first index in undefined. There are only a total of 5 checkboxes and yet the array is 6 indexes long. Why is this?
Try this efficient way bruvo :) http://jsfiddle.net/v4dxu/ with proper end tag in html: http://jsfiddle.net/L4p5r/
Pretty good link: https://learn.jquery.com/javascript-101/arrays/
Also in your html end your tag /> i.e.
<input class="publish" id="chkBox4" type="checkbox" checked>
rest should help :)
Code
var checkArray = new Array();
$('input[type=checkbox]').each(function () {
this.checked ? checkArray.push("1") : checkArray.push("0");
});
alert(checkArray);
As mentioned in the answers above the problem is with the index(i). But if you want to simplify the code further, How about the following code?
var checkArray = [];
$('input.publish').each(function () {
checkArray.push($(this).is(':checked'));
});
alert(checkArray);
Take into account that the first element you write is checkArray[1], as i starts with 1, instead of checkArray[0].
Replace checkArray[i] with checkArray[i-1] inside the for bucle

input field displaying NaN

Description
Hi, I am using knock out. I have three checkboxes and an input field. When I click on checkbox, the value of the checkbox should appear on the input field. However, instead of getting the value of the checkbox, I see NaN.
jsFiddle link
function ViewModel() {
var self = this;
self.primaryClass = ko.observable("50");
self.secondaryClass = ko.observable("40");
self.otherClass = ko.observable("10");
self.selectedValues = ko.observableArray([]);
self.sum = ko.computed(function () {
var total = 0;
ko.utils.arrayForEach(self.selectedValues(), function (item) {
total += parseInt(item);
});
return total;
});
}
ko.applyBindings(new ViewModel());
Looking at the code, on this line,
total += parseInt(item);
the variable item is the value of your checkboxes.
<input data-bind="checked: selectedValues" type="checkbox" value="primaryClass">500</input>
<input data-bind="checked: selectedValues" type="checkbox" value="secondaryClass">200</input>
<input data-bind="checked: selectedValues" type="checkbox" value="otherClass">100</input>
meaning you are trying to parseInt("primaryClass") ... and so on.
Try changing the value of the checkbox to numbers.
Like here: http://jsfiddle.net/2L4W9/
Check this out:
http://jsfiddle.net/Dtwigs/uFQdq/5/
Do your inputs like this to make them dynamic:
<label>
<input data-bind="checked: selectedValues, value: primaryClass" type="checkbox"></input>
<span data-bind="text: primaryClass"></span>
</label>
Change your values to the values in text.

Categories

Resources