Reputation: 6400
I have a requirement of allowing a user to uncheck a radio button.
I have created a general function that clears (unchecks) a radio button. After doing so, I trigger the change event using jQuery, but the Observable model does not update it's value.
var UnCheck = "UnCheck";
$("input:radio.AllowUnCheck").click(function(event){
var $clickedbox = $(this),
radioname = $clickedbox.prop("name"),
$group = $('input[name|="'+ radioname + '"]'),
doUncheck = $clickedbox.hasClass(UnCheck),
isChecked = $clickedbox.is(':checked');
if(doUncheck){
$group.removeClass(UnCheck);
$clickedbox.prop('checked', false);
//Edit: Added this code as a work around.
if(kendo)if(this.kendoBindingTarget){
bindingSource = this.kendoBindingTarget.source;
if(bindingSource){
try{
// This assumes that the name of the radio group is the same as the
// as the observables key (set and get key).
bindingSource.set(radioname, "None");
}
catch(e){/*Do nothing*/}
}
};
}
else if(isChecked){
// Make sure that others in the group do not have the UnCheck class
// This will ensure that only one radio in the group will have the UnCheck class at a time.
$group.removeClass(UnCheck);
// Adding the class tells the function to uncheck it the next time this radio
// is clicked, if clicked before any other radio in the group is clicked.
$clickedbox.addClass(UnCheck);
}
//$clickedbox.trigger("change");
document.getElementById(this.id).onchange();
});
I've also tried the shortcut $clickedbox.change()
and document.getElementById("id").onchange();
So how to I get the Observable to update it's value with the UI when I've changed the value with JavaScript?
Keep in mind, that the code making the change does not know that the element is bound to a kendo Observable, and cannot be dependent on the kendo-ui API.
Edit: I could not find a way around it, so I added code to check for kendo observable bindings. Following the convention of of using the radio groups name as the key for accessing the corresponding observable, I was able to get the model to appropriately update.
Upvotes: 2
Views: 3557
Reputation: 6400
I could not find a way to get the models to properly update without knowledge of the framework, so I made some modifications in order to check to see if kendo or ko are defined, and then attempt to update the model. This works for me in kendo MVVM, but I have not yet vetted it in knockout. If anyone has suggestions on how to improve this, let me know.
/**
* Depends on jQuery.
*/
var AllowRadioUnCheck = new function(){
var PUBLIC=this,
UnCheck = "UnCheck",
className = "AllowRadioUnCheck";
/**
* @returns {string} The class name that is added to a radio input to
* indicate that it should be unchecked the next time it is clicked.
*/
function getUnCheck(){
return UnCheck;
}
PUBLIC.getUnCheck = getUnCheck;
/**
* @returns {string} The class name for AllowRadioUnCheck, to indicate that the radio group should
* allow the user to uncheck values. The class needs to be added to each element in the named group.
*/
function getAllowRadioUnCheck(){
return className;
}
PUBLIC.getAllowRadioUnCheck = getAllowRadioUnCheck;
/**
* @param data_bind (string) The data_bind parameter value for the element.
* @returns {*} The model name/key that is bound to the "checked" binding.
*/
function getModelBind(data_bind){
if(data_bind){
var checkedIndex = data_bind.indexOf("checked:");
if(checkedIndex >= 0){
checkedIndex += 8;
}
else{
checkedIndex = 0;
}
var targetEnd = data_bind.indexOf(",",checkedIndex);
if(targetEnd < checkedIndex){
targetEnd = data_bind.length;
}
var key = $.trim(data_bind.substring(checkedIndex, targetEnd));
return key;
}
else{
return "";
}
}
/**
* This should be called after any MVVM data binding, and after the class has been added to all appropriate elements,
* if you are adding the class programatically with jQuery or JavaScript,m as opposed to in line.
*/
function bind(){
$("input:radio.AllowRadioUnCheck").click(function(event){
var $clickedbox = $(this),
radioname = $clickedbox.prop("name"),
$group = $('input[name|="'+ radioname + '"]'),
doUnCheck = $clickedbox.hasClass(UnCheck),
isChecked = $clickedbox.is(':checked'),
data_bind = $clickedbox.data('bind'),
bindingSource = null,
$koData = null;
if(doUnCheck){
$group.removeClass(UnCheck);
$clickedbox.prop('checked', false);
try{
if(kendo)if(this.kendoBindingTarget){
bindingSource = this.kendoBindingTarget.source;
if(bindingSource){
var modelKey = getModelBind(data_bind);
bindingSource.set(modelKey, "None");
/*TODO: Needs more testing to determine whether dependant observables are updating properly.
I may need to add some kind of change event notification here.
*/
}
};
}
catch(e){/*Do nothing*/}
try{
// Has not been tested for proper knockout functionality yet.
// Let me know if this works for you if you are using knockout.
if(ko){
$koData = ko.dataFor(this);
$koData("None");
$koData.valueHasMutated();//Make sure computed update properly.
}
}
catch(e){/*Do nothing*/}
}
else if(isChecked){
// Make sure that others in the group do not have the UnCheck class
// This will ensure that only one radio in the group will have the UnCheck class at a time.
$group.removeClass(UnCheck);
// Adding the class tells the function to uncheck it the next time this radio
// is clicked, if clicked before any other radio in the group is clicked.
$clickedbox.addClass(UnCheck);
}
});
$("input:radio.AllowRadioUnCheck:checked").addClass(UnCheck);
}
PUBLIC.bind = bind;
}
Also, I thought I would add this little bit to show how this is used.
HTML:
<input type=radio" name="MyRadio" id="One" value="One" class="AllowRadioUnCheck"/>
<input type=radio" name="MyRadio" id="Two" value="Two" class="AllowRadioUnCheck"/>
JavaScript:
$(document).ready(function(){
AllowRadioUnCheck.bind();
//I prefer allowing the developer to decide when to bind the class functionality
});
Upvotes: 1