Intercepting clicks on a knockout radio button - javascript

edited to add:
here is the only way I've managed to make it work at the moment - I took the ko implementation of the 'checked' binding and made a few small mods. Seems a bit heavyweight and prone to breaking when the framework gets updated but hey ho...
working code pen
I have a collection of radio buttons backed off with a knockout vm. If a user attempts to change the selection, I would like to first present them with a confirmation window (i.e. 'are you sure?').
I have managed to make this work, but I'm not happy with the solutions - one was too complex, the other showed two radio buttons selected when the confirmation window appeared.
I would like to intercept the click so that the confirmation shows before the selection changes in the UI (or the backing observable). I've tried to use the mouseup or mousedown event bindings but nothing I do prevents the selection occurring after choosing to cancel the change.
Is it possible to intercept the click and prevent the change propagating if required?
js:
var model = {
checkboxOptions : ["yes","no","maybe"],
selectedOption : ko.observable(),
showConfirm:function(data,ev){
if(!confirm("go ahead?")){
//doesn't work
ev.stopPropagation();
ev.preventDefault();
return false;
}
}
}
ko.applyBindings(model);
html:
<p>
<!-- ko foreach:checkboxOptions -->
<input type="radio" data-bind="event: {mouseup:$parent.showConfirm, click:null, mousedown:null}, value:$data,checked:$parent.selectedOption"/><span data-bind="text:$data"></span>
<!-- /ko -->
</p>
<p data-bind="text:selectedOption"></p>
codepen here

Since you want to change the way knockout checked binding works I would probably customise it with a bindingHandler, something like
<input type="radio" data-bind="radioWithConfirm: { selected: $parent.selectedOption }, value: $data"/>
ko.bindingHandlers.radioWithConfirm = {
init: function(element, valueAccessor) {
var options = valueAccessor();
$(element).on('click', function(event) {
if (!confirm('really?')) {
event.preventDefault();
return false;
} else {
options.selected(this.value);
return true;
}
});
}
}
CodePen here

Related

Why isn't my Javascript working?

I am new to coding and I need to use Javascript in my code. I have a checkbox within an HTML table (below).
<td><input type="checkbox" id="check1"/>
<label th:text="${item.contents}"> </label>
</td>
I am trying to use Javascript to alert me when I have checked the box with the code below.
<script>
$('#check1').click(function() {
if($(this).not(':checked'))
alert('unchecked');
else
alert('checked');
});
</script>
Why isn't it working? I don't get an error, but nothing happens either.
Thank you.
Ok, first, you have some syntax that is not HTML here:
<label **th:text="${item.contents}"**>
And, if that non-HTML code is incorrect, that could be enough for the page to stop processing. You say you don't get an error, but do you mean that you've checked your developer tools console window and don't see an error there?
As for the checkbox, neither the table cell, nor the label are related to your goal.
Next, JQuery is a great thing, but it sometimes makes things that are already easy, harder. Your code is actually EXCLUDING any checked elements from the wrapped set that will be examined because you are using not().
Here is a solution that doesn't rely on JQuery:
var chk = document.getElementById("check1");
chk.addEventListener("click", function(){
// The following is not part of your question, but is
// added just for completeness:
// Because the alert() is modal, it will block the UI
// from updating and it will most likely appear before
// the UI updates the checkbox to the latest appearance.
// To solve this, we add a short delay before making the
// alert using a timer and we need to store the checked
// status of the checkbox outside of the timer's callback
// function.
var on = this.checked;
setTimeout(function(){
var message = "checked";
if(!on){
message = "un" + message;
}
alert(message);
}, 50);
});
<input type="checkbox" id="check1">
I don't think it's normally very wise to listen to click events on things like checkboxes and radio buttons. From what I understand they may be triggered before the value of the input is updated, depending on where you catch the event in the dom.
I'm not sure what the html syntax is on your label, the th:text part, but it seems to be some sort of templating syntax and also may be unrelated. To help simplify the problem also I will give you an example without using jQuery, jQuery often adds unnecessary complexity to simple problems.
A properly working example of your code using vanilla javascript (without jquery) would be,
document.getElementById("check1").addEventListener('change', function(e) {
var checked = this.checked;
if(checked) { alert("Checked"); }
else { alert("Unchecked"); }
});
And with jquery, a working example is:
$("#check1").on("change", function(e) {
var checked = this.checked;
if(checked) { alert("Checked"); }
else { alert("Unchecked"); }
});

Is it possible to stop a checkbox from changing when clicked, pending some check?

I came across an situation today where I wanted a checkbox to not change unless an associated ajax call was successful. By "not change" I mean - if the checkbox was currently checked then it should NOT show as unchecked until the ajax call was completed and was successful.
Example HTML:
<input type="checkbox" id="a" />
Example (psuedo) jQuery:
$("#a").change(function(e) {
//somehow stop the checkbox from showing as checked in the UI
$.ajax...
success: function() {
//checkbox should now show as checked in the UI
},
error: function() {
//show error to user. checkbox should still be unchecked.
}
});
Various google searches only turned up references to getting or changing the state of a checkbox.
For now I'm just changing the state of the checkbox back in the case of an error.
I suppose this could be done by using images to represent the checkbox and changing them at the appropriate times, but I'm looking for a solution that uses "native" HTML elements, CSS, and or Javascript (or some Javascript library). Just curious what stackoverflow users have to say about this.
Thanks!
Try to use instead of change(), click() function and prevent default action in it. Then on success you could manually change the checkbox state.
Here example
$("#a").click(function(e) {
$.ajax...
success: function() {
$('a').attr('checked','checked')
},
error: function() {
//show error to user. check box should still be unchecked.
}
e.preventDefault();
return false;
});
Is it possible to stop a checkbox from changing when clicked, pending
some check?
Yes, you can temporarily disable the checkbox while your ajax query is running.
It seems that you already using jquery, based on that, you can try:
$("#a").change(function(e) {
$("input#a").attr("disabled", true); //disable input
$.ajax...
success: function() {
$("input#a").removeAttr("disabled"); //re-enable input
},
error: function() {
//show error to user. check box should still be unchecked.
}
});
NOTE:
You should also enable the checkbox inside error: function(), but I followed your comment because I don't know what you're trying to accomplish.

Trouble setting event handler on bootstrap-switch element with AngularJS

The context is I have a radio button in my angular application that triggers a drop-down menu to appear. I'm attempting to attach an event listener that will fire off an AJAX request to a server and populate the drop-down list with the response. I'm using angular-bootstrap-select/bootstrap-select for the switch.
My initial approach was to simply add an ng-click directive to the div surrounding the button, which works, but the request is only sent if the user clicks on the white part of the button:
Image of button:
However the click doesn't register if the user clicks the grey part where it reads "All". I also tried wrapping the div in an anchor and attaching the ng-click to that but that did not work either.
I also tried to use the method in the documentation:
bootstrap-switch-event
My code:
$('input[id="mySwitch"]').on('switchChange.bootstrapSwitch', function(event, state) {
console.log('event triggered');
if ( !itemsCalled ) {
myService.items.get().$promise.then(function(response) {
$scope.itemList = response.items;
});
itemsCalled = true;
}
});
Template:
<input bs-switch id="mySwitch" ng-model="item" type="radio" switch-on-text="All" switch-off-text="Custom" switch-on-color="grey" switch-off-color="blue" switch-animate="true" switch-size="small" ng-value="'All'" ng-true-value="'All'" ng-false-value="'Custom'">
And a bunch of variations of this with no success. I'm pretty new to angular so I'm not sure if I'm going about this the wrong way or not.
If you want to make the Ajax call when the switch change from "Custom" to "All" :
function Controller($scope) {
$scope.$watch('item', function(newValue, oldValue){
if(newValue === "All") {
// Ajax call
alert("ajax");
}
})
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="Controller">
<input ng-model="item" type="radio" ng-value="'All'" ng-true-value="'All'" ng-false-value="'Custom'">
<button ng-click="item = 'Custom'">Reset</button>
</div>

Detect the changes of the controls in a page using Jquery

I have page with around 20 to 30 controls based on the query string values. I need to change a button as disabled based on the value changes in the controls. For examble in the list of Check boxes if something is checked or unchecked, some texts added or removed etc... for all the controls.
The controls are textbox, option buttons, check boxes, select controls and list boxes.
I don't want to add static methods to all controls. I do have an idea of doing the late binding to all the controls and to attach events. And that events will disable the button whenever the event gets fired.
Is there any other way to do this functionality in a simple way(Like Keypress or using event property window object)?
As #ekhaled pointed out you can use the same handler to handle all the click and change events.
Here's a somewhat convoluted example:
<div id="container">
<input id="input1" type="text" value="" />
<select>
<option value="1">ABC</option>
<option value="2">EFG</option>
</select>
<input type="button" value="Submit" />
</div>
and the javascript for it:
$('#container').on("change click", ":input", function (event) {
if (event.target.nodeName == "SELECT") {
if ($(event.target).val() == "2") {
console.log("disable");
$(":button").prop("disabled", true);
} else {
$(":button").prop("disabled", false);
console.log("enable");
}
}
if (event.target.id == "input1" && $(event.target).val() == "") {
$(":button").prop("disabled", true);
}
});
See it working here.
However if you main concern is validation you should have a look at jquery validation
With jQuery validation you can set specific rules for each of the inputs that will make up the validation of the whole form. It is very customizable, you can change where and how the errors are displayed, when is the validation triggered, etc.
You can use event delegation and bind your event to the parent element, and then write all your logic inside that one event handler.
Can't really show you much, because you haven't included any examples or code. But something along the lines of:
$("body").on('change click', 'input, select', function(){
var _this = $(this);
if(_this.is('input[type=checkbox].className')){
//follow one logic
}
if(_this.is('input[type=radio].className')){
//follow another logic
}
//etc, etc
})

jQuery - Checkbox not being checked

I'm using checkboxes to toggle the enabled and disabled state of some multi-lists on a registration form. The checkbox is labeled with the category, and the multi-list contains the items that belong to that category.
I'm using jQuery 1.7.2.
$('#sch_cat_hockeyschools').toggle(function(ev) {
ev.stopPropagation();
$("#type_select_hockeyschools").prop("disabled", false);
$("#type_select_hockeyschools").removeProp("disabled", "disabled");
$("#sch_cat_hockeyschools").prop("checked", true);
$("#sch_cat_hockeyschools").prop("checked", "checked");
}, function(ev) {
ev.stopPropagation();
$("#type_select_hockeyschools option:selected").removeAttr("selected");
$("#type_select_hockeyschools").prop("disabled", true);
$("#type_select_hockeyschools").prop("disabled", "disabled");
$("#sch_cat_hockeyschools").prop("checked", false);
$("#sch_cat_hockeyschools").removeProp("checked");
});
Sample of corresponding checkbox HTML:
<input class="catmark" type="checkbox" name="sch_categories[]" id="sch_cat_hockeyschools" value="1" />General Hockey Schools
<input class="catmark" type="checkbox" name="sch_categories[]" id="sch_cat_springhockey" value="2" />Spring Hockey
The problem is that the upon clicking the checkbox, the checkbox does not become ticked or checked; it immediately returns to an unchecked state, which I thought the stopPropagation() function would help with. Apparently not. The multi-lists get enabled and disabled as expected, but the checkbox doesn't get ticked.
The result of this problem is that when the form is submitted, the array containing the selected categories is empty; thus, because at least one checked category is a required field in the form, the PHP script that processes the form throws one of my errors which tells me a required field was left blank.
Any ideas on how to make sure that the checkbox actually gets checked, and by extension, POSTS actual data to the processing script?
Thanks guys.
The problem is the use of toggle -- per the documentation:
The implementation also calls .preventDefault() on the event, so links
will not be followed and buttons will not be clicked if .toggle() has
been called on the element.
toggle itself is calling preventDefault, which is stopping the default behavior of the event, checking/unchecking the box.
Rather than toggle, use bind or on (see edit note below) to add a listener for the change event, in which you can examine the state:
$('#sch_cat_hockeyschools').on('change', function () {
if (this.checked) {
// do stuff for a checked box
console.log('check is on');
} else {
// do stuff for an unchecked box
console.log('check is off');
}
});
Try it out at jsFiddle.
EDIT
Please note, this code shows use of the on method, whereas the jsFiddle example uses bind. As pointed out by Sam Sehnert, on is the preferred method for attaching events with > jQuery 1.7. If you are using an older version of jQuery, use bind as in the jsFiddle example.
Documentation
jQuery.toggle
jQuery.bind
jQuery.on

Categories