Knockout.js: Initial value of observable doesn't update RadioButton state - javascript

Here is a very simple story that I fail to make it work:
We have an array of questions. Each question has an array of answer. Each answer has a text and value. Each question has the property selectedAnswer that represents the selected answer's value.
Here is jsfiddle: https://jsfiddle.net/votsevfd/8/
Implementation:
<div data-bind="foreach : {data: questions}">
Question: <span data-bind="text: descr"></span>
<div data-bind="foreach: {data: answers}">
<div>
<label data-bind="text: text"></label>
<input name="something" type="radio" data-bind="checked: $parent.selectedAnswer, value: value"></input>
</div>
</div>
<div>
The selected answer is:<span data-bind="text: selectedAnswer"></span>
</div>
</div>
And here is the related JavaScript:
var model = {
questions: ko.observableArray(),
};
var q1 = {
descr: 'Do you like JS?',
selectedAnswer: ko.observable('200'), // Initially, select No (200)
answers: [
{text:'Yes', value:'100'},
{text:'No', value:'200'}
],
}
model.questions.push(q1);
ko.applyBindings(model);
Problem:
I want the appropriate radio button become selected according to initial value of selectedAnswer (in the above case, radio button No). But it doesn't work.
What am I missing?

This is a weird issue. I was able to fix it by changing the order of the checked and value bindings like this:
<input name="something" type="radio" data-bind="value: value, checked: $parent.selectedAnswer" />
Updated fiddle
There's another fix for this. If you switch to knockout's latest version, this issues goes away. So, I'm assuming they fixed it somewhere between version 2 and 3.0.
Updated fiddle
(Also, you can simplify your foreach binding to this:data-bind="foreach : questions")
Update:
It is indeed a bug. You can go through #user3297291's detailed answer for more information regarding this.

Related

knockoutjs "checked" binding not working correctly in Safari and IE

I have built a pricing calculator for different document types that gives you a final price based on the number of pages, quality and quantity in your document.
The pricing is generated by a service and the data for each request is outputted as a JSON object which is than used on the calculator.
So far everything works well in Chrome or Firefox, but not in Safari or IE. I have been able to narrow down that the issue is with the Quality radio buttons.
The issue is that the pricing in Safari for example, is always incorrect when you use the "Quality" radio buttons. It seems that the first click on the radio button is not firing and you always get the incorrect price.
I've set up an example on jsfiddle with instructions on how to repro the issue:
https://jsfiddle.net/IntricatePixels/f21dtr8j/
The example of JSFiddle should have all the details but I'd be happy to provide more info here on this post if necessary.
<div class="form-group document-quality">
<label>Quality</label>
<fieldset data-role="controlgroup">
<div class="field-container" data-bind="foreach:categoryOptions, valueUpdate: 'afterkeydown', event: { change: onSubmit }" id="documentQuality">
<label class="btn btn-default document-quality-label" data-bind="css: { 'active': $parent.selectedCategoryValue() === value }"></label>
<div class="radio-container">
<label class="btn btn-default document-quality-label" data-bind="css: { 'active': $parent.selectedCategoryValue() === value }">
<input data-bind="attr: {value: value}, checked: $parent.selectedCategoryValue" id="uniqueQuestionName" name="uniqueQuestionName" type="radio">
</label>
</div>
<label class="btn btn-default document-quality-label" data-bind="css: { 'active': $parent.selectedCategoryValue() === value }"><span data-bind="text: label"></span></label>
</div>
</fieldset>
</div>
<div class="form-group quantity">
<label>Quantity</label>
<input data-bind="value: copies, valueUpdate: 'keyup'" id="numberofCopies" type="text">
</div>
Though the codes might seem confusing I would say thanks to you I've found some tricks to knockout that I didn't it can be done in that way (but I doubt I would use though :D).
But let's get back to the point, let's just say that you are tired of cleaning your code for now and you want to continue with this. The issue with this is with this one event: { change: onSubmit }. When the function was called, the value of selectedCategoryValue is not updated yet (note: I only tested this on IE11, I have not available macs to use for now). This code which assigns the value of selectedCategoryValue only took effect after the onSubmit function executed.
<input data-bind="attr: {value: value}, checked: $parent.selectedCategoryValue" id="uniqueQuestionName" name="uniqueQuestionName" type="radio">
I tried two ways that worked.
First is the brute way that i don't recommend because for some personal reason i don't like setTimeout.
Add setTimeout in the onSubmit function.
self.onSubmit = function() {
setTimeout(function(){
self.response("<div class='priceLoading'>Loading</div>");
var servURL = "https://prices.azurewebsites.net/price/ProductionUS/" + ko.utils.unwrapObservable(self.selectedCategoryValue) + "/" + ko.utils.unwrapObservable(self.pages()) + "/" + ko.utils.unwrapObservable(self.copies());
$.get(servURL, function(response) {
self.response(response.PriceFormatted);
});
console.log(servURL);
}, 100)
}
Fiddle here.
Second is more knockouty way, utilizing the subscription of selectedCategoryValue so if the value of selectedCategoryValue changes, then call the onSubmit function.
Change the old subscribe callback of selectedCategoryValue to:
self.selectedCategoryValue.subscribe(function(newValue) {
self.onSubmit();
});
And remove change event that calls onSubmit:
<div class="field-container" data-bind="foreach:categoryOptions, valueUpdate: 'afterkeydown'" id="documentQuality">
Fiddle here.
And lastly, you should really upgrade your knockout library (if it's possible) so that you can utilize knockout's new cool features just like textInput to change your value, valueUpdate binding combo.

jQuery else clause not working [duplicate]

I have 3 radio buttons in my web page, like below:
<label for="theme-grey">
<input type="radio" id="theme-grey" name="theme" value="grey" />Grey</label>
<label for="theme-pink">
<input type="radio" id="theme-pink" name="theme" value="pink" />Pink</label>
<label for="theme-green">
<input type="radio" id="theme-green" name="theme" value="green" />Green</label>
In jQuery, I want to get the value of the selected radio button when any of these three are clicked. In jQuery we have id (#) and class (.) selectors, but what if I want to find a radio button by its name, as below?
$("<radiobutton name attribute>").click(function(){});
Please tell me how to solve this problem.
This should do it, all of this is in the documentation, which has a very similar example to this:
$("input[type='radio'][name='theme']").click(function() {
var value = $(this).val();
});
I should also note you have multiple identical IDs in that snippet. This is invalid HTML. Use classes to group set of elements, not IDs, as they should be unique.
To determine which radio button is checked, try this:
$('input:radio[name=theme]').click(function() {
var val = $('input:radio[name=theme]:checked').val();
});
The event will be caught for all of the radio buttons in the group and the value of the selected button will be placed in val.
Update: After posting I decided that Paolo's answer above is better, since it uses one less DOM traversal. I am letting this answer stand since it shows how to get the selected element in a way that is cross-browser compatible.
$('input:radio[name=theme]:checked').val();
another way
$('input:radio[name=theme]').filter(":checked").val()
This works great for me. For example you have two radio buttons with the same "name", and you just wanted to get the value of the checked one. You may try this one.
$valueOfTheCheckedRadio = $('[name=radioName]:checked').val();
The following code is used to get the selected radio button value by name
jQuery("input:radio[name=theme]:checked").val();
Thanks
Adnan
For anyone who doesn't want to include a library to do something really simple:
document.querySelector('[name="theme"]:checked').value;
jsfiddle
For a performance overview of the current answers check here
I found this question as I was researching an error after I upgraded from 1.7.2 of jQuery to 1.8.2. I'm adding my answer because there has been a change in jQuery 1.8 and higher that changes how this question is answered now.
With jQuery 1.8 they have deprecated the pseudo-selectors like :radio, :checkbox, :text.
To do the above now just replace the :radio with [type=radio].
So your answer now becomes for all versions of jQuery 1.8 and above:
$("input[type=radio][name=theme]").click(function() {
var value = $(this).val();
});
You can read about the change on the 1.8 readme and the ticket specific for this change as well as a understand why on the :radio selector page under the Additional Information section.
If you'd like to know the value of the default selected radio button before a click event, try this:
alert($("input:radio:checked").val());
You can use filter function if you have more than one radio group on the page, as below
$('input[type=radio]').change(function(){
var value = $(this).filter(':checked' ).val();
alert(value);
});
Here is fiddle url
http://jsfiddle.net/h6ye7/67/
<input type="radio" name="ans3" value="help">
<input type="radio" name="ans3" value="help1">
<input type="radio" name="ans3" value="help2">
<input type="radio" name="ans2" value="test">
<input type="radio" name="ans2" value="test1">
<input type="radio" name="ans2" value="test2">
<script type="text/javascript">
var ans3 = jq("input[name='ans3']:checked").val()
var ans2 = jq("input[name='ans2']:checked").val()
</script>
If you want a true/false value, use this:
$("input:radio[name=theme]").is(":checked")
Something like this maybe?
$("input:radio[name=theme]").click(function() {
...
});
When you click on any radio button, I believe it will end up selected, so this is going to be called for the selected radio button.
I you have more than one group of radio buttons on the same page you can also try this to get the value of radio button:
$("input:radio[type=radio]").click(function() {
var value = $(this).val();
alert(value);
});
Cheers!
can also use a CSS class to define the range of radio buttons and then use the following to determine the value
$('.radio_check:checked').val()
This worked for me..
HTML:
<input type="radio" class="radioClass" name="radioName" value="1" />Test<br/>
<input type="radio" class="radioClass" name="radioName" value="2" />Practice<br/>
<input type="radio" class="radioClass" name="radioName" value="3" />Both<br/>
Jquery:
$(".radioClass").each(function() {
if($(this).is(':checked'))
alert($(this).val());
});
Hope it helps..
$('input:radio[name=theme]').bind(
'click',
function(){
$(this).val();
});
You might notice using class selector to get value of ASP.NET RadioButton controls is always empty and here is the reason.
You create RadioButton control in ASP.NET as below:
<asp:RadioButton runat="server" ID="rbSingle" GroupName="Type" CssClass="radios" Text="Single" />
<asp:RadioButton runat="server" ID="rbDouble" GroupName="Type" CssClass="radios" Text="Double" />
<asp:RadioButton runat="server" ID="rbTriple" GroupName="Type" CssClass="radios" Text="Triple" />
And ASP.NET renders following HTML for your RadioButton
<span class="radios"><input id="Content_rbSingle" type="radio" name="ctl00$Content$Type" value="rbSingle" /><label for="Content_rbSingle">Single</label></span>
<span class="radios"><input id="Content_rbDouble" type="radio" name="ctl00$Content$Type" value="rbDouble" /><label for="Content_rbDouble">Double</label></span>
<span class="radios"><input id="Content_rbTriple" type="radio" name="ctl00$Content$Type" value="rbTriple" /><label for="Content_rbTriple">Triple</label></span>
For ASP.NET we don't want to use RadioButton control name or id because they can change for any reason out of user's hand (change in container name, form name, usercontrol name, ...) as you can see in code above.
The only remaining feasible way to get the value of the RadioButton using jQuery is using css class as mentioned in this answer to a totally unrelated question as following
$('span.radios input:radio').click(function() {
var value = $(this).val();
});

Displaying a list of checkboxes and text field after radio is checked [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have a form that has the following fields:
<div>
<input name="department" type="radio" value="1" required >
<label for="Orchestra">Orchestra</label>
</div>
<div>
<input name="department" type="radio" value="2">
<label for="Band">Band</label>
</div>
What I would like to be able to do is to display different checkboxes and comment text fields ONLY if the radio button for "Band" is checked. If this is unchecked then, the checkboxes should go away. I found several examples online, but for some reason I can't get them to work. The problem must be that I do not know Javascript or JQuery :( Any help would be appreciated.
I have tried different things that I have seen on stackOverflow and other websites, but I am so clueless about Javascript that I can't get it to work.
I've created a commented fiddle to help you accomplish what you ask, but also clue you in on what's actually going on. I recommend really diving into JavaScript/JQuery with the many resources available online, but for now, I hope my comments will help get you started.
The main takeaway here, is we use JavaScript to "listen" to whether or not the input in question is selected, not selected—based on that value, we can dictate what our view will look like—in this case, hiding or showing element(s).
JS
$(function () {
// Create selectors for relevant DOM elements
var $Department = $('input[name="department"]');
var $BandSelected = $('#BandSelected');
// Create a function that you pass
// the value of the input element in question.
// Return TRUE/FALSE based on equality to 2,
// the `value` associated with the 'Band' input
function isBandsSelected(val) {
return val == 2;
}
// Attach an event listener on `click' of inputs
$Department.click(function () {
// Assign a variable to the function that determines if the input
// we click on is 'Band' (has a value of 2)
var showBand = isBandsSelected($(this).val());
// If `showBand` returns TRUE, show our `BandSelected` div
if (showBand) {
$BandSelected.show();
// If `showBand` returns FALSE, show our `BandSelected` div
} else {
$BandSelected.hide();
}
});
});
Markup
<div>
<input name="department" type="radio" value="1" required>
<label for="Orchestra">Orchestra</label>
</div>
<div>
<input name="department" type="radio" value="2">
<label for="Band">Band</label>
</div>
<div id="BandSelected" class="hidden">
Band is selected
</div>
Demo Fiddle: http://jsfiddle.net/4x1ybqyv/

Combining checked binding with click binding on containing element [duplicate]

This question already has an answer here:
Prevent event bubbling when using the checked binding in knockoutjs
(1 answer)
Closed 8 years ago.
In my view model I have a boolean property that's visualized by a checkbox in the view. I want the user to be able to click on the containing element as well to toggle the property, but that poses problems when the user clicks the checkbox: the change is not registered then.
Consider this view:
<div class="my-option" data-bind="click: toggleOption1">
<input type="checkbox" data-bind="checked: isOption1Checked" />
Entire div is clickable to select this option.
</div>
With this view model:
var ViewModel = function() {
var self = this;
self.isOption1Checked = ko.observable(false);
self.toggleOption1 = function(){
self.isOption1Checked(!self.isOption1Checked());
};
};
As you can see in this corresponding jsfiddle, this will not allow you to click on the checkbox to change the boolean observable. This kinda makes sense to me, probably the click handler changes the value, but the checked binding also handles the change and reverts it.
The general solution I felt I needed was a one way checked binding or something of the sort, so I tried using the attr binding:
<div class="my-option" data-bind="click: toggleOption1">
<input type="checkbox"
data-bind="attr: { checked: isOption1Checked() ? 'checked' : '???'" />
Entire div is clickable to select this option.
</div>
However, this will not work: there is no checked="false" option in html. You just omit the checked attribute altogether. I don't think the attr binding can do that however.
One other workaround I thought of was to create my own binding (possibly based on / delegating the read bit to the default checked binding), but it feels like overkill. Am I missing an obvious, elegant Knockout solution?
My current workaround (trying to evade creating such a custom binding) involves some elaborate view logic:
<div class="my-option" data-bind="click: toggleOption1">
<!-- ko if: isOption1Checked -->
<input type="checkbox" checked="checked" />
<!-- /ko -->
<!-- ko if: !isOption1Checked() -->
<input type="checkbox" />
<!-- /ko -->
Entire div is clickable to select this option.
</div>
This works, but is very verbose to my taste.
Any other elegant, concise way to handle this?
Right, just after posting and searching some more I found the answer in another question. Here's the specifics for the scenario from my question:
<div class="my-option" data-bind="click: toggleOption1">
<input type="checkbox"
data-bind="checked: isOption1Checked,
click: function() { return true; },
clickBubble: false" />
Entire div is clickable to select this option.
</div>
I'll leave this answer and question here as a duplicate, should it help a random Googling internet user that words his question similar to mine as opposed to similar to the other one.

knockout event handling

I have a code (you can play it at http://learn.knockoutjs.com/#/?tutorial=intro , click Run in output window before playing ):
HTML:
<div class="btn" style="margin-left: 15px;" data-bind="click: includeMyNumber">
<input data-bind="checked: isIncludeMyNumber" data-val="true" id="IncludeMe" name="IncludeMe" style="margin: 0" type="checkbox" value="true" />
Include my number (+<span>11111111111</span>)
</div>
Javascript:
// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function AppViewModel() {
this.isIncludeMyNumber = ko.observable(false);
this.includeMyNumber = function(){
this.isIncludeMyNumber(!this.isIncludeMyNumber());
}
}
// Activates knockout.js
ko.applyBindings(new AppViewModel());
The problem is that checkbox click event handling does not work properly. When I click the space inside [div class="btn"...] ...[/div] area, checkbox behaviour is OK, but when I click the checkbox itself, it is not checked. How can I make it checkable in any case?
Thank you.
You´re use case is to make the checkbox checked when clicking the text?
I made a binding for this in my custom binding collection
https://github.com/AndersMalmgren/Knockout.Bindings
http://jsfiddle.net/5nqw4/
<input data-bind="checked: checked, label: { caption: 'Label with reference to input' }" type="checkbox" />
edit: You can also fix this by using the standard hack of wrapping the checkbox in a label element like http://jsfiddle.net/7dTfM/

Categories