Backbone event adding extra events to radio button - javascript

I have a set of radio buttons that I am testing with, will be used to change theme. Html code is straight forward
<div id="options">
<input type="radio" name="imm" id="themea" value="a" /> Theme 1
<input type="radio" name="imm" id="themeb" value="b" /> Theme 2
</div>
How when I click on a radio item, the first time around the following code will show alert once, second time it will display twice, third time third and so on. What is going on, I reckon I need to destroy something but not sure what.
Here is my backbone code:
events: {
"click input[type=radio]": "onRadioClick"
},
onRadioClick: function (e) {
// e.stopPropagation();
var self = this
_.bindAll(self)
$("input:radio[name=imm]").click(function (){
var somval = $(this).val();
alert(somval)
});
This is how I initialize the view:
initialize: function(state) {
var self = this
_.bindAll(self)
self.state = state
self.setElement('#options')
self.elem = {
imm: self.$el.find('#imm')
}
}

Related

KnockoutJS Binding a checkbox with both "checked" and "click" bindings causes unexpected behavior

here is the code I've been working on.
Javascript:
function ViewModel() {
var self = this;
self.isChecked = ko.observable(false);
self.testing = function(){
console.log("hello from testing");
}
}
var app = new ViewModel();
ko.applyBindings(app);
And here's the html:
<div>
<div>
<button data-bind="click: testing" type="button">Something</button>
<input data-bind="checked: isChecked, click: testing" type="checkbox" />
<input data-bind="checked: isChecked" type="checkbox" />
</div>
</div>
What I'm looking to accomplish is that I want a checkbox, whose value is data-binded to a variable in my model and updates accordingly. And at the same time, whenever a user clicks the checkbox to change its boolean value, I want a function to be executed AFTER the value is changed in the model and the checkbox is updated.
I have two buttons data-binded to the same value just for testing purposes. When I click the checkbox that is binded with click to testing, its checkmark doesn't change, but the function executes correctly. However, the other checkbox DOES indeed update to reflect the changes in the model when the button is clicked.
What is happening that causes this behavior, and how could I write a better solution to achieve what I'm looking for?
EDIT: So apparently, by adding a return true; to the function, I managed to... arrive at the intended behavior?
function ViewModel() {
var self = this;
self.isChecked = ko.observable(false);
self.testing = function(){
console.log(self.isChecked());
console.log("hello from testing");
console.log(self.isChecked());
return true;
}
}
var app = new ViewModel();
ko.applyBindings(app);
The question is then, why does this happen, and is it safe?
This seems like an XY problem. So, in addition to what #Tomalak mentioned, if you want to trigger a function when the checkbox value is changed, you can subscribe to the isChecked observable
function ViewModel() {
var self = this;
self.isChecked = ko.observable(false);
self.isChecked.subscribe(function(newValue) {
// this gets executed every time "isChecked" changes
console.log(self.isChecked());
console.log(newValue);
});
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input data-bind="checked: isChecked" type="checkbox" />
The advantage of using subscribe over click binding is that, this function gets triggered even when you set the value of checkbox programmatically like this self.isChecked(false)

How to properly clear another field on checkbox click in Knockout.js?

I have a list of checkboxes and one of them is "Other" and what I want is that if "Other" is selected, then a textbox is enabled. If "Other" is not checked, then the textbox must be disabled and its content must be cleared.
Now, the problem is that when I click on the "Other" checkbox, the checkmark doesn't show up or disappear UNTIL I trigger another binding event. I must have on the way of Knockout by adding the click event handler to the "Other" checkbox.
fiddle here
HTML
<input type='checkbox' value='apple' data-bind='checked: selectedFoods' />apple
<br>
<input type='checkbox' value='banana' data-bind='checked: selectedFoods' />banana
<br>
<input type='checkbox' value='other' data-bind='checked: selectedFoods, event: {click: otherClicked}' />other
<input type='text' data-bind="text: otherFoods, attr:{disabled: selectedFoods.indexOf('other') < 0}" />
JS
$(document).ready(function () {
var BaseVM = function () {
var that = {};
return that;
};
var TestVM = function () {
var that = BaseVM();
that.selectedFoods = ko.observableArray(['apple', 'banana']);
that.otherFoods = ko.observable(null);
that.otherClicked = function () {
if (that.selectedFoods.indexOf('other') < 0) {
that.otherFoods = '';
}
};
return that;
};
var vm = TestVM();
ko.applyBindings(vm);
});
This line
that.otherFoods = '';
is wrong. You need to assign the value as an observable, since that's what it is:
that.otherFoods('');
Also, you need to evaluate your array when checking the values:
that.selectedFoods.indexOf('other') < 0
should be
that.selectedFoods().indexOf('other') < 0
Edit: and your click handler was set up wrong, see this updated fiddle:
http://jsfiddle.net/2qdu9tuo/9/
You need to return true in the click handler to let the checkbox still behave like a checkbox. Also, you're using the text binding instead of the value binding on the textbox.
First, you need to return true from your click handler, otherwise the native event would not propagate and the checkbox state will not change.
Also, when resetting the otherFoods observable, you need to invoke the observable, not override it:
that.otherClicked = function () {
if (that.selectedFoods.indexOf('other') < 0)
that.otherFoods('');
return true;
};
Another problem is that you're using the text binding handler, for your otherFoods input, instead of the value handler:
<input type='text' data-bind="value: otherFoods, attr:{disabled: selectedFoods.indexOf('other') < 0}" />
See Fiddle

Prevent user from clicking radio again and without disabling it

<input type="radio" id="Svar0" name="Svar" value="Yes">
<input type="radio" id="Svar1" name="Svar" value="No">
<input type="radio" id="Svar2" name="Svar" value="MayBe">
User can choose only once.
As per requirement, if the user has selected a radio, he can not select another one. Means that if the user has answered YES (clicked on YES), then he can not change the answer to NO or MayBe.
Workarounds:
If I disable the radio after single click then it is not submitted to the server.
There is no option for readonly.
I tried onchange handler returning false, but it makes the user answer disappearing.
<script>
$('input[type = "radio"]').change(function () {
this.checked = false;
});
</script>
I am thinking of weird options like transparent div before radio buttons.
I do not want to prefer hidden fields as I have above 60 questions and I find it difficult to manage them.
Please help me any code in Jquery or Javascript.
If the user selects one answer in radio, then the page should not allow him to select another answer and so the first selected answer should be the one that gets submitted.
Another simple option (disable all, except selection, on selection of any). This allows the selected value to be posted back:
$(':radio').change(function(){
$(':radio').not(this).prop("disabled", true);
});
JSFiddle: http://jsfiddle.net/9n8v4heo/
Update (delay before disable):
It does not appear to be a good user experience to allow radio selection then freeze it immediately, as mistakes do happen.
The following example will allow a 2 second delay after any selection, before making them disabled, so you can keep clicking but after two seconds you cannot select again:
var tme;
$(':radio').change(function(){
var t = this;
clearTimeout(tme);
tme = setTimeout(function(){
$(':radio').not(t).prop("disabled", true);
}, 2000);
});
JSFiddle: http://jsfiddle.net/9n8v4heo/1/
try
$("[type=radio][name=Svar]").change(function () {
if (!$("[type=radio][name=Svar]").filter("[clicked]").length) {
$(this).attr("clicked", "true")
} else {
$(this).prop("checked", !this.checked);
$("[type=radio][name=Svar]").filter("[clicked]").prop("checked", true)
}
});
DEMO
use preventDefault() with click event as #JotaBe said
$("[type=radio][name=Svar]").click(function (e) {
if (!$("[type=radio][name=Svar]").filter("[clicked]").length) {
$(this).attr("clicked", "true")
} else {
e.preventDefault();
}
});
DEMO
You can disable the other buttons when one gets selected, this way the selected one will get sent when the form is submitted.
jQuery("input[name=Svar]").change(function() {
jQuery("input[name=Svar]").prop("disabled", "disabled");
jQuery(this).prop("disabled",false);
});
You can attach an event handler that disables the default action for the click to all the radios, and do whatever you need to do instead ofteh default action. Tod so so, attach a handler that simply includes a call to: event.preventDefault(), and your own code.
See jquery docs for event.preventDefault()
$(document).ready(function() {
var allowChoose = true;
$('input').click(function(e) {
if (allowChoose) {
allowChoose = false;
} else {
e.preventDefault();
}
});
});
As you can see, you can use a flag like 'allowChoose' to allow the default action on the first click, and then change the flag and avoid the default action (checking the radio) on the next calls.
See the fiddle here.
Quick solution: You can disable the others radio buttons and the selected value remains enabled.
var $Svars = $('input[name="Svar"]');
$Svars.change(function () {
$Svars.not(this).prop("disabled", true);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="radio" id="Svar0" name="Svar" value="Yes" /> Yes
<input type="radio" id="Svar1" name="Svar" value="No" /> No
<input type="radio" id="Svar2" name="Svar" value="MayBe" /> Maybe
Solution 2: Another solution will be to add a class or a data attribute to exclude the others, like below.
var $Svars = $('input[name="Svar"]');
$Svars.change(function () {
var $this = $(this);
if($this.val() == $this.data('selected') || $this.data('selected') == undefined) {
$Svars.data('selected', $this.val());
} else {
$Svars.val([$this.data('selected')]);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="radio" id="Svar0" name="Svar" value="Yes" /> Yes
<input type="radio" id="Svar1" name="Svar" value="No" /> No
<input type="radio" id="Svar2" name="Svar" value="MayBe" /> Maybe

Public property bound to button outside of class doesn't have the same value as button bound internally when object is instantiated

Overall, I have an object that keeps track of selected checkbox IDs. The way it does this is by pushing/slicing the IDs into/out of an array, $Grid.selectedRows. This object also binds a 'refresh' method to a refresh button. I have a class that I created that object from, KendoGridSelection.
My issue is the button bound inside of the class shows the correct array values, while the button bound outside of the class with the public selectedRows property no longer updates after the refresh button is clicked.
For testing purposes, I have two seeSelectedRowsArray buttons:
seeSelectedRowsArray button (Bound internally)
seeSelectedRowsArray2 button (Bound outside of class)
I am testing in Chrome Version 28.0.1500.95 m
Here is my code:
JS
var KendoGridSelection = function (gridID, pagerSelector) {
var $Grid = this;
$Grid.selectedRows = [];
$Grid.gridID = gridID;
$Grid.pagerSelector = pagerSelector;
$Grid.grid = $($Grid.gridID).data('kendoGrid');
$Grid.pager = $($Grid.pagerSelector).data('kendoPager');
$Grid.gridCheckboxes = $('input[type=checkbox]', $Grid.gridID);
$Grid.gridRows = $('table tbody tr', $Grid.gridID);
$Grid.refreshButton = $('.refreshButton', $Grid.gridID);
$Grid.bindUIEvents = function () {
$Grid.gridCheckboxes = $('input[type=checkbox]', $Grid.gridID);
$Grid.gridRows = $('.row', $Grid.gridID);
// Row click event
/*$($Grid.gridRows).click(function (e) {
if (!$(e.target).parent().hasClass('k-hierarchy-cell')) $(this).find('input[type=checkbox]').click();
});*/
// Checkbock click event
$($Grid.gridCheckboxes).click(function (e) {
console.log('checkbox clicked!');
e.stopPropagation();
var $t = $(this);
var checkboxID = $t.attr('id');
var thisRow = $t.closest('tr');
if ($t.is(':checked')) {
thisRow.addClass('k-state-selected');
// add to selected[]
if ($.inArray(checkboxID, $Grid.selectedRows) === -1) $Grid.selectedRows.push(checkboxID);
} else {
thisRow.removeClass('k-state-selected');
// remove from selected[]
$Grid.selectedRows.splice($.inArray(checkboxID, $Grid.selectedRows), 1);
}
});
}
$Grid.gridPersistSelected = function () {
$.each($Grid.selectedRows, function () {
var $t = $('#' + this);
if ($t) $t.click();
});
}
$Grid.pagerChange = function () {
$Grid.bindUIEvents();
$Grid.gridPersistSelected();
}
$Grid.refresh = function () {
$Grid.selectedRows = [];
$Grid.gridCheckboxes.attr('checked', false);
console.log('Refresh clicked.');
console.log('$Grid.selectedRows: '+$Grid.selectedRows);
}
// Init
$Grid.pagerChange();
// $Grid.pager.bind("change", $Grid.pagerChange);
// Unbind refresh button, then rebind
// Refresh button
$Grid.refreshButton.click(function(){
console.log('reset!');
$Grid.refresh();
});
$('.seeSelectedRowsArray').click(function(){
console.log($Grid.selectedRows);
});
return {
selectedRows: $Grid.selectedRows,
refresh: $Grid.refresh,
}
}
$(function(){
window.activeThreatsGrid = new KendoGridSelection('.grid', '.pager');
$('.seeSelectedRowsArray2').click(function(){
console.log(activeThreatsGrid.selectedRows);
});
});
HTML
<div class='grid'>
<div class='row'>
<label><input type="checkbox" id="item1"> </label>
</div>
<div class='row'>
<label><input type="checkbox" id="item2"> </label>
</div>
<div class='row'>
<label><input type="checkbox" id="item3"> </label>
</div>
<div class='row'>
<label><input type="checkbox" id="item4"> </label>
</div>
<div class='row'>
<label><input type="checkbox" id="item5"> </label>
</div>
<div class='pager'>
<input type="button" value="refresh" class="refreshButton">
</div>
<div><input type="button" value="seeSelectedRowsArray" class="seeSelectedRowsArray"></div>
<div><input type="button" value="seeSelectedRowsArray2" class="seeSelectedRowsArray2"></div>
</div>
CSS
.row{background:blue; height:20px; width:100px; margin-bottom:5px;}
JSFiddle
Demo
What is happening:
When I click on multiple checkboxes, then click the seeSelectedRowsArray, I get the correct values in the array. I can do this however many times and still get the correct values.
When I hit the refresh button, my console.logs tell me my selectedRows array is empty. Then when I click the seeSelectedRowsArray, the array is empty (expected). When I click the seeSelectedRowsArray2, the array still has values in it.
UPDATE 1
What I have found is if I bind $Grid.selectedRows to a button click from within my class, it always gets the most current values, even after refresh. If I bind the public selectedRows to a button click outside of my class, after the refresh button is clicked, selectedRows no longer updates and gets stuck at the value just before the refresh.
Why does the button bound internally show the correct array values, while the button bound outside of the class with the public selectedRows property no longer updates after the refresh button is clicked?
Any help would be appreciated!
Your problem lies in how you are returning/tracking references to the object.
In your constructor, you set $Grid = this
However, you return a new object as a result of the function:
return {
selectedRows: $Grid.selectedRows,
refresh: $Grid.refresh,
}
That returned object now only holds a reference to the current value of $Grid.selectedRows
When your refresh method sets $Grid.selectedRows to a new array it breaks the associated value from the returned object which remains set to the original array.
Change your refresh from:
$Grid.selectedRows = []
to:
$Grid.selectedRows.length = 0;
Demo

javascript onload page radio checked

I have a function that enables or disables form elements based on which radio item is checked. It is working ok. However, I wish that one of the radio buttons to be checked at page load with the appropriate form elements already disabled or enabled.
Right now on page load, I have one of the radio buttons checked on the form itself but the javascript will fire when there is a change.
Here is the javascript
<script type="text/javascript">
function customerChoice() {
if (document.getElementById('radio1').checked) {
document.getElementById('company').disabled = false;
document.getElementById('onetime').disabled = true;
document.getElementById('span1').style.color = '#cccccc';
document.getElementById('span2').style.color = '#000000';
}
if (document.getElementById('radio2').checked) {
document.getElementById('company').disabled = true;
document.getElementById('onetime').disabled = false;
document.getElementById('span1').style.color = '#000000';
document.getElementById('span2').style.color = '#cccccc';
}
}
window.onload = customerChoice();
</script>
And here are the two radio buttons.
<input type="radio" name="type" id="radio1" value="C" onclick="customerChoice()" checked />Current Customer<br />
<input type="radio" name="type" id="radio2" value="O" onclick="customerChoice()" />One Time Customer<br />
Need help figuring out what to change in order to make the javascript fire upon loading. Thank you.
Try:
window.onload = customerChoice;
The way you have it runs the function immediately, and sets the onload handler to the result (which is undefined, since the function doesn't return anything), rather than to the function itself. It's not working because it runs before the DOM is loaded.
try putting the customerChoice() function inside an anonymous function:
window.onload = function() {
customerChoice();
};

Categories

Resources