Set Checkbox when Radio button changes with Knockout - javascript

I am new to knockout and I have an issue that has stumped me so far. I have spent a whole day on this with little progress.
I have 4 radio buttons that are bound to an observable called InvType:
<input type="radio" id="rdoAIP" name="rdoAIP" value="AIP" data-bind="checked: InvType" />AIP
<input type="radio" id="rdoPSI" name="rdoPSI" value="PSI" data-bind="checked: InvType" />PSI
<input type="radio" id="rdoPSIAIP" name="rdoPSIAIP" value="PSIAIP" data-bind="checked: InvType" />PSI/AIP
<input type="radio" id="rdoShortForm" name="rdoShortForm" value="PSIShortForm" data-bind="checked: InvType" />PSI Short Form
I have several checkboxes that should only be checked when a specific radio button is checked:
<input data-bind="checked: OptionalValue1" id="chk1" type="checkbox" /> Checkbox 1<br/>
<input data-bind="checked: OptionalValue2" id="chk2" type="checkbox" /> Checkbox 2<br/>
<input data-bind="checked: OptionalValue2" id="chk3" type="checkbox" /> Checkbox 3<br/>
When the user clicks a different radio button, a different combination of check boxes should become checked as well. For example, if the "AIP" radio button is checked on initial page load, then the first 2 checkboxes should also be checked. But when the user clicks the "PSI" radio button, then I want only the first checkbox to be checked and the others should be unchecked.
edit:
Sorry but I was not clear about the check boxes. So here are the conditions:
On initial page load, the radio button gets set and this causes the checkboxes to update accordingly. Each different radio value cause a different combination of the checkboxes to become checked and unchecked.
After the page loads, the user can click on an individual checkbox and change its value. This will NOT affect any other checkbox or radio button.
My knockout code so far:
<script type="text/javascript">
var psiInvestigationViewModel = #Html.Raw(New JavaScriptSerializer().Serialize(Model));
function PSIInvestigationViewModel(data)
{
var self = this;
InvestigationType : ko.observable();
ko.mapping.fromJS(data, {}, self);
};
$(function ()
{
ko.applyBindings(new PSIInvestigationViewModel(psiInvestigationViewModel), $('#PSIInvestigation#(ViewData("UniqueID"))')[0]);
});
If someone could show me the code needed to get my checkboxes to update based on the radio button change, then I would be grateful.
Thanks

First, all radio buttons should have the same, so if you select one the other will be deselected.
If the checkboxes are not readonly you can code the selection logic in an init function.
This init function will be called on each radio buttons change :
var VM = function () {
var self = this;
self.InvType = ko.observable();
var initState = function () {
var t = self.InvType();
self.OptionalValue1(t == 'AIP' || t == 'PSIAIP');
self.OptionalValue2(t == 'PSI' || t == 'PSIAIP');
self.OptionalValue3(t == 'PSIAIP');
};
self.OptionalValue1 = ko.observable();
self.OptionalValue2 = ko.observable();
self.OptionalValue3 = ko.observable();
self.InvType.subscribe(initState);
}
ko.applyBindings(new VM());
See fiddle
I hope it helps.

Another way to do it would be to use computed observables:
self.Optionalvalue1 = ko.computed(function() {
return self.InvType() == 'AIP' || self.InvType() =='PSIAIP';
)};
and so on.

Related

Auto-Select Radio Button By Default And Execute 'onchange' Function

I've achieved the first part of the question using php or js. I use php to echo checked attribute. The problem here is that the radio inputs have other inputs that become visible upon selection with onchange event. However, if any of the radio gets selected/checked by default, the conditional inputs aren't displayed until I change the radio selections. Hence the question, how do I get it checked by default and still have the respective conditional inputs displayed.
<input name="mode" id="single" onchange="conditionalDisplay(this.value)" type="radio" value="single" <?php if($mode == single){echo 'checked';}>
<input name="mode" id="multi" onchange="conditionalDisplay(this.value)" type="radio" value="multi" <?php if($mode == multi){echo 'checked';}>
When single is selected, other inputs become visible. Same goes for multi. If the condition specified in the php code is true, then one of them gets selected/checked by default but the accompanying hidden inputs from the onchange function are not displayed until the selection is changed.
N:B - The value of $mode is retrieved from a database.
You can trigger onchange programmatically, for ex., with element.onchange();.
function conditionalDisplay(value) {
// Let's for example log to browser console
console.log('Do something useful with ' + value);
}
// When DOM is ready, trigger an `onchange` event
document.addEventListener('DOMContentLoaded', function() {
var singleElement = document.getElementById('single');
var multiElement = document.getElementById('multi');
// Test which exactly element is checked
console.log(`singleElement.checked: ${singleElement.checked}`);
console.log(`multiElement.checked: ${multiElement.checked}`);
if (singleElement.checked == true) {
singleElement.onchange();
} else {
multiElement.onchange();
}
});
<input name="mode" id="single" onchange="conditionalDisplay(this.value)" type="radio" value="single">
<input name="mode" id="multi" onchange="conditionalDisplay(this.value)" type="radio" value="multi" checked>
This one might be useful for you as well How can I trigger an onchange event manually?

How to filter (show/hide) with two or more values in data attribute

I have a the following html:
<input id="check_1" type="checkbox" name="check" value="option_1">
<label for="check_1">Option 1</label>
<input id="check_2" type="checkbox" name="check" value="option_2">
<label for="check_2">Option 2</label>
<input id="check_3" type="checkbox" name="check" value="option_3">
<label for="check_3">Option 3</label>
<input id="check_4" type="checkbox" name="check" value="option_4">
<label for="check_4">Option 4</label>
<div class="productsBox" data-tag="option_1 option_2 option_3">Product 1</div>
<div class="productsBox" data-tag="option_1 option_4">Product 2</div>
And the following javascript:
<script>
window.onload=function(){
$('input').on('change', function () {
var $checked = $('input:checked');
if ($checked.length) {
$('.productsBox').hide();
$checked.each(function () {
var val = $(this).val();
$('.productsBox').filter('[data-tag*="'+val+'"]').show();
});
} else {
$('.productsBox').show();
}
});
}
</script>
So, if option 1 and option 4 are checked, the divs with product 1 and product 2 are shown, because they both contain the values option_1 OR option_4.
However, I would like to see that if option 1 and option 4 are checked only product 2 is shown because it contains the values option_1 AND option_4.
Is that possible? Any help is appreciated.
The issue is (1) in how you're deciding which .productsBox elements to show and (2) that you're applying the .filter().show() inside your .each() function.
Instead, you should create the complete filter condition by looping through the checked items, then apply the filter+show. In addition, at least based on your example data, you should use the "Attribute Contains Word Selector" (documentation) which is ~= instead of the contains selector *=. The former will ensure that option_10 is seen as distinct from option_1 in your data-tag filter.
Complete working JS:
$(function() {
$("input").on("change", function() {
var $checked = $("input:checked");
var $checkedFilter = '';
if ($checked.length) {
$(".productsBox").hide();
$checked.each(function() {
$checkedFilter = $checkedFilter + '[data-tag~="' + $(this).val() + '"]';
});
$(".productsBox").filter($checkedFilter).show();
} else {
$(".productsBox").show();
}
});
});
You can see I create a new string variable upfront called checkedFilter; this is where we'll build the dynamic filter for which .productsBox items to show. Then as we iterate through the checked checkboxes, we build the complete filter based on those items. In the example of Option 1 and Option 4 being checked, the value of checkedFilter is: [data-tag~="option_1"][data-tag~="option_4"].
Then outside the each loop of checked items, we invoke the .filter(checkedFilter).show() using the checkedFilter variable.
Working CodePen here: https://codepen.io/anon/pen/xzZEmd
If you select Options 1 & 4, only Product 2 appears; if you then select as a 3rd option Option 3, no product elements are displayed because none have 1, 3 & 4. If you select 1, 2 & 3, only Product 1 appears, etc.

is there a defaultValue property for radio select?

I am wondering if there is a way to reset a radio to it's originally selected option. I know of defaultValue for inputs but is there a way to make it so that I can reset the radios back to their originally selected value on page load?
I am not wanting to simply unselect all radios. I am trying to put them back to their originally selected value.
Thanks for any info.
Yes, radio inputs do have defaultValue property, but what you are looking for is the defaultChecked property:
$('input[type=radio]').prop('checked', function() {
return this.defaultChecked;
});
That being said, if you want to reset the form you can use the reset method of the HTMLFormElement object:
$('#formElement').get(0).reset();
I think you want this
<form action="">
<input type="radio" name="gender" value="male" checked="true"/>Male
<input type="radio" name="gender" value="female"/>Female
<input type="reset" value="reset"/>
</form>
Any time you will reset the form, the male radio button will be selected.
I will rather make a jQuery plugin like this:
$.fn.defaultVal = function (checked) {
if(checked === true || checked === false) {
$(this).attr("data-default", checked);
return;
}
if(!$(this).attr("data-default")) {
console.log("No default value assigned!");
return;
}
return $(this).attr("data-default");
}
JSFIDDLE LINK UPDATE
Working Demo is here: JSFIDDLE

Length is returning undefined but value is showing

I have a function where I get an error saying "length" is null, I then did an alert to see the value and length and I see that the value is coming back in the loop, sometimes it has a String value and sometimes it has a number (eg. SUIT and then 8), but for some reason the length is showing as undefined? The radioobj variable takes radio button values that are coming in from the form input.
function getRadioValue(radioobj) {
radiovalue = "";
for (i=0, n=radioobj.length; i<n; i++) {
if (radioobj[i].checked) {
radiovalue = radioobj[i].value;
break;
}
}
if (!radiovalue) { return 0; }
else { return radiovalue; }
}
The way the code is written, it appears to be looking to take in a group of radio buttons and looping through them to find the one that is checked. To do that, the input MUST be a collection of radio buttons . . . passing an individual reference to a radio button will not work (and will give an undefined value for radioobj.length). Example:
HTML
<fieldset id="radioVals">
<input type="radio" name="radioVals" id="val0" value="">Pick an value . . .</input>
<input type="radio" name="radioVals" id="val1" value="Value1">Value 1</input>
<input type="radio" name="radioVals" id="val2" value="Value1">Value 2</input>
</fieldset>
Given this group, if you were to pass in a reference to any of the individual radio buttons (e.g., using document.getElementById), you will get and error, because what is returned by that method is the reference to an individual element.
var radioOption = document.getElementById("val0");
window.console.log(radioOption.length); // will log "undefined"
However, if you pass in an array of radio button elements (e.g., using .children), you can use the for loop, because the array will have a length.
var radioOptions = document.getElementById("radioVals").children;
window.console.log(radioOptions.length); // will log "3"
From what you are describing, it sounds like the code is using the first approach, rather than the second. There are certainly ways of doing this check with individual radio buttons, but that is not how this code has been set up.
You can get collection of radios with the same id easily.
Use for it document.forms['form_id']['radio_id']:
<form id="form_id">
<input type="radio" name="radio_name" id="radio_id" value="Value1" />Value 1
<input type="radio" name="radio_name" id="radio_id" value="Value2" />Value 2
<input type="radio" name="radio_name" id="radio_id" value="Value3" />Value 3
</form>
var radio_list = document.forms['form_id']['radio_id'];
alert(radio_list.lengh) // will "3"

How to check a Particular Radio Box in a "Group" using JavaScript

I have a radio box group and I need to select a given radio box using javascript as in the following case, I have to check option with value D3
<input type="radio" name="day" id="day" value="D1" />D1
<input type="radio" name="day" id="day" value="D2" />D2
<input type="radio" name="day" id="day" value="D3" />D3
<input type="radio" name="day" id="day" value="D4" />D4
How can the third option for example be checked?
Be sure putting this radio group in a form and change the theNameOfTheForm to your form's name.
<form name="theNameOfTheForm">
..
..
..
</form>
The java-script function:
<script type="text/javascript">
function select_radio_value(theValue)
{
for (var i=0; i < document.theNameOfTheForm.day.length; i++)
{
if (document.theNameOfTheForm.day[i].value == theValue)
{
document.theNameOfTheForm.day[i].checked = true;
}
}
}
</script>
Now you can use it as a js function on any event. for instance:
<input type='button' name='c3' value='Click Here to check the D3 radio' onClick="javascript:select_radio_value('D3')">
Normally, you'd use document.getElementById('day').val or jQuery('#day').val(). That is, if they have different ids. If they share the id, I'm not sure you can with document.getElementById since it assumes that the ids are different, but perhaps
jQuery('#day')[3].val()
could work, because jQuery actually returns an array of elements that match the criteia
Remove the unique ID from each of the checkboxes. You should only have ONE unique ID on a page.
In JavaScript, access the third checkbox in this group with the following and set it to checked:
var inputs = document.getElementsByTagName('input');
inputs[2].setAttribute('checked', 'checked');
OR, you can simply add checked=checked to your HTML.
function selectRadio(toBeSelectedRadioIndex)
{
var radioElements = document.getElementById('day');
radioElements[toBeSelectedRadioIndex].checked = true;
}
In many cases you need to have Id names different for your elements.
You can then give them same name and use getElementsByTagName instead.
The the code will look like...
function selectRadio(toBeSelectedRadioIndex)
{
var radioElements = document.getElementsByTagName('day');
radioElements[toBeSelectedRadioIndex].checked = true;
}
I would give the radio buttons different ids and then do the following :
d3.select("input#thirdRadio").property("checked", "true");

Categories

Resources