I have a page that displays a list of records. The user can select the record status using radio buttons, e.g.:
<div id="record_653">
<label><input type="radio" name="status_653" value="new" checked/>new</label>
<label><input type="radio" name="status_653" value="skipped" />skipped</label>
<label><input type="radio" name="status_653" value="downloaded" />downloaded</label>
</div>
I am using JQuery to send the changes made by the user back to the server, where I use them to update the database. This is a simplified version of what I do:
$("#record_653").click(
function(event) {
var url = ...,
params = ...;
post(url,params);
});
The problem is that this code will create requests even if the user clicks the same button that was previously checked. What I actually want is the "on change" event, except its behavior in Internet Explorer is not very useful (e.g. here).
So I figure I somehow have to identify if the click event changed the value.
Is the old value stored somewhere (in the DOM? in the event?) so I could compare against it?
If not, how should I store the old value?
The old value is not stored someplace where you can query it, no. You will need to store the value yourself. You could use a javascript variable, a hidden input element, or jQuery's data() function.
EDIT
The jQuery data function provides access to a key-value-pair data structure as a way to store arbitrary data for a given element. The api looks like:
// store original value for an element
$(selector).data('key', value);
// retrieve original value for an element
var value = $(selector).data('key');
A more developed thought:
$(document).ready(function() {
// store original values on document ready
$(selector).each(function() {
var value = $(this).val();
$(this).data('original-value', value);
})
// later on, you might attach a click handler to the the option
// and want to determine if the value has actually changed or not.
$(selector).click(function() {
var currentValue = $(this).val();
var originalValue = $(this).data('original-value');
if (currentValue != originalValue) {
// do stuff.
// you might want to update the original value so future changes
// can be detected:
$(this).data('original-value', currentValue);
}
});
});
$('#record_653 input:radio').each(function() {
$(this).data('isChecked', $(this).is(':checked'));
$(this).click(function() {
if ( $(this).is(':checked') !== $(this).data('isChecked') ) {
// do changed action
} else {
$(this).data('isChecked', !$(this).data('isChecked') );
}
})
});
This was complicated to do in my head but I think you want something like this.
As was suggested by meder and Ken Browning, I ended up using JQuery's data() to store the previous value and check against it on every click.
Storing an "is checked" boolean for each input radio is one solution. However you need to maintain this value. So in the click event handler, in addition to changing the "is checked" of the current input, you need to find the input that was previously checked and change its "is checked" data to false.
What I chose to do instead was to store, in the parent element, the currently checked object. So my code looks something like:
$(document).ready(
function() {
// find the checked input and store it as "currChecked" for the record
$("#record_653").data("currChecked",
$(this).find("input:radio:checked")[0]);
// add the click event
$("#record_653").click( function(event) {
if ($(event.target).is("input:radio") &&
event.target !== $(this).data("currChecked"))
{
$(this).data("currChecked", event.target);
handleChangeEvent(event);
}
});
});
}
);
Thanks
I had the same problem, but with FF I managed to deal with it using the onchange event rather than the onclick.
This is exactly what I was looking for to deal with IE7. Works like a charm!
Thanks for the detailed solution!
Related
In the following code why doesn't the radio report the correct value when checked via its variable name?
var $myRadio = $('input[type=radio][name=options]:checked');
$('#button').click(() => {
// this works
console.log($('input[type=radio][name=options]:checked').val());
// this doesn't :(
console.log($myRadio.val());
});
https://jsfiddle.net/charsi/p4beztwx/13/
I am using mdl radio buttons so that could be causing it. I have also tried getting the value with $myRadio[0].MaterialRadio.value but that doesn't work either.
EDIT: This was a poorly worded question and didn't really have anythng to do with mdl. What I really wanted was the ability to set the DOM variable for my radio button somewhere else without having to select it by name again to check the value.
The reason for getting incorrect values when checked via its variable name is because you are setting $myRadio before the click event. $myRadio is set on document ready (before click event) and it gets the value of the checked radio option which at this moment is always 1.
Moving $myRadio inside a click handler should work. Why? Because now it gets the value of the radio (checked) as soon as the click function is called which is actually what you need.
$('#button').click(() => {
var $myRadio = $('[id^="option"]:checked');
// neither of these work
alert($('input[type=radio][name=options]:checked').val());
alert($myRadio.val());
});
fiddle here
For anyone else running into the same issue. Not wanting to call the radio button name when checking for its value, you can use filter -
var $myRadio = $('input[type=radio][name=options]');
$('#button').click(() => {
console.log($myRadio.filter(':checked').val());
}
Tried to solve this multiple ways. 1. by simply adding the normal html "checked" default option to radio buttons in my form and 2. having js functions do it, being the gist of the ideas tried.
The issue: I'm finding that no matter how I do it, if the radio is designated as checked by default (before the user makes his/her choice), anything done after that will not be saved correctly (if at all) in localStorage. localStorage WILL save the initial default selections, however but, nothing can be changed from then on (even after "physically" selecting another option).
I know localStorage is working because if I leave off the default designation (and for the rest of the inputs) it functions perfectly.
The form code:
<label>Who is the contact person for this event?<span class="requiredtext">*</span></label>
<input type="radio" name="Contact_Person" id="Contact_Person1" value="Submitter is the contact person" onclick="contacthide()" checked required> I am<br />
<input type="radio" name="Contact_Person" id="Contact_Person2" value="Submitter is not the contact person" onclick="contactshow()" required>
The localStorage save code:
function localStoragefunctions() {
localStorage.clear();
if (Modernizr.localstorage) {
//Set variable to show that data is saved
localStorage.setItem("flag", "set");
//Save radio and checkbox data
$(window).bind('unload', function() {
$('input[type=radio]').each(function() {
localStorage.setItem('radio_' + $(this).attr('id'), JSON.stringify({
checked: this.checked
}));
});
});
The code that spits it back out if the user goes back to make changes before final submission:
$(document).ready(function() {
if (Modernizr.localstorage) {
//Browser supports it
if (localStorage.getItem("flag") == "set") {
$('input[type=radio]').each(function() {
var state = JSON.parse(localStorage.getItem('radio_' + $(this).attr('id')));
if (state) this.checked = state.checked;
});
Other than this, I have a confirmation page that grabs all of the variables stored in localStorage and presents them to the user for final inspection before they hit submit for good.
That consists of: var ContactPerson = localStorage.getItem('Contact_Person'); and then a document.write that spits out html and the variable's value. Again, this works fine if I don't try to set default radio choices (and works great for all other input types).
The ideal outcome would be choosing the most likely radio button choices by default so that it could possibly save the user time. I'd like to not have to present them with a form where they have to physically click each radio button if I can "make that decision for them" before hand.
Hope this all makes sense!
I know this an old question, but I've been troubleshooting a similar issue and thought I'd share my solution.
When you set your localStorage item, you are saving both radio inputs and their values, b/c your using the ID attribute as your key.
localStorage.setItem('radio_' + $(this).attr('id'), JSON.stringify({ checked: this.checked }));
This could be ok, but I've taken a different approach. And, I maybe missing something, so comments are welcome.
Instead, I use $(this).attr('name') to set the key. As a result, when either radio button in selected, you are saving the value to the same localStorage key.
In my scenario, I'm storing many inputs to localStorage, so my solution is a bit abstract. I'm calling saveToLocalStorage() using jQuery's .change() method on each input. Also, I'm saving the input's value directly to localStorage.
function saveToLocalStorage(input) {
if ( $(input).attr('type')=='radio' ) {
localStorage[$(input).attr('name')] = $(input).val();
} else {
localStorage[$(input).attr('id')] = $(input).val();
}
}
When retrieving from localStorage, I had to check if the localStorage key:value pair matched the radio input before selecting it. Otherwise, I was selecting both radio inputs. Note, in my scenario, I'm working with jQuery 1.4.4, hence the attr('checked', 'checked').
$('input[type=radio]').each(function() {
var key = $(this).attr('name');
var val = localStorage[key];
if ( $(this).attr('name') == key && $(this).attr('value') == val ) {
$(this).attr('checked', 'checked');
}
});
Got a strange thing going on, really don't have a idea how to solve this one. Neither did I find useful stuff when googleing.
I have a html form that includes this:
<label for="gebied">Gebieden</label>
<div class="button button-selected"><input type="checkbox" name="areas" value="nederland" checked="checked" />Nederland</div>
<div class="button button-selected"><input type="checkbox" name="areas" value="europa" checked="checked" />Europa</div>
<div class="button button-selected"><input type="checkbox" name="areas" value="wereld" checked="checked" />De Wereld</div>
Then with javascript (jQuery) I check which are checked and which are not:
var areas = [];
$('input[name=areas]:checked').each(function(){
areas.push($(this).val());
});
This is called from within createShortUrl();, below in the relevant code:
$(function() {
//Handle things when a buttons is clicked
$("div.button").click(function() {
//Find the input field for the clicked div
var input = $(this).find(':input');
var inputName = $(input).attr('name');
//Handle checkboxes, which define the gebied
if ($(input).is(':checkbox')) {
//Change the classes
input.prop('checked', !input[0].checked);
$(this).toggleClass('button-selected');
}
//Handle radio
if ($(input).is(':radio')) {
$('form').find('input[name=' + inputName + ']').each(function() {
$(this).parent('div').toggleClass('button-selected');
$(this).prop('checked', !input[0].checked);
});
}
//Clicking means something chanhes; create a new short url
createShortUrl();
});
});
The strange thing is that when in Firefox, when I have earlier checked some of them, they stay in the areas array. Even when I uncheck some of them, they stay in the array and vice versa. But when debugging in Safari, it works like a charm!
When I then uncheck every thing, the array is empty. Recheck some, and there in the array.
So, any ideas, what's going on with Firefox? It looks like FF is caching, even after couple of times refreshing, the previous array. Despite my
var areas = []
in which I hoped to empty it and rebuild it....
It's live at here, fired after the large button on the bottom is clicked.
Any thoughts are more then welcome!
The issue is with your event handler. The problem is, the way you are modifying the state of the element does not work in Firefox. You should use attr() instead of prop() to change the checked state.
Working code: Replaced .prop() with .attr().
//Handle things when a buttons is clicked
$("div.button").click(function() {
console.log("Click");
//Find the input field for the clicked div
var input = $(this).find(':input');
var inputName = $(input).attr('name');
//Handle checkboxes, which define the gebied
if ($(input).is(':checkbox')) {
//Change the classes
console.log("check");
input.attr('checked', !input[0].checked);
$(this).toggleClass('button-selected');
}
//Handle radio
if ($(input).is(':radio')) {
$('form').find('input[name=' + inputName + ']').each(function() {
$(this).parent('div').toggleClass('button-selected');
$(this).attr('checked', !input[0].checked);
});
}
//Clicking means something chanhes; create a new short url
createShortUrl();
});
You are pushing the values (these are strings) of the inputs into a static array. There is no reason for this array to be updated in tandem with the DOM, in Firefox or in any other browser.
If you were to store the DOM elements themselves in the array and retrieve values from those, that would be a different story.
I want to change the value of data-confirm attribute on a button (submit) based on user's choices on a form. I put the following on the change function of a dropdown list:
...
if($("#"+select_name).val() == "abc")
{
$(".variable_button").attr("data-confirm","abc is good choice!");
} else
{
$(".variable_button").attr("data-confirm","abc would have been great but this is fine too...");
}
...
The problem I am facing is that apparently data-confirm cannot be changed once it is assigned a non-empty string. I have it set to "" in the server code. And, it changes to one of the two messages shown above when the user first makes a selection on the dropdownlist. But if the user changes the selection one more time, the data-confirm message does not change. Is this per design or am I missing something?
Don't use .attr(), use .data():
var newData = ($("#"+select_name).val() == "abc")
? "abc is good choice!"
: "abc would have been great but this is fine too...";
$(".variable_button").data("confirm", newData);
jQuery does allow you to update a data- attribute with the .attr() method, so something else is breaking.
Here's a working example (JSFiddle):
var counter = 1;
$('#click').click(function() {
button = $('#click');
console.log(button.attr('data-confirm'));
button.attr('data-confirm', 'this is test ' + counter);
console.log(button.attr('data-confirm'));
counter++;
});
Can you try to repo the issue in a JSFiddle?
On rereading your question, it sounds like an event handler isn't firing the second time the user changes the selection. See if you can set a breakpoint in your event handler to see if it even gets hit.
Unfortunately form.reset() function doesn't reset hidden inputs of the form.
Checked in FF3 and Chromium.
Does any one have an idea how to do the reset for hidden fields as well?
Seems the easiest way of doing that is having <input style="display: none" type="text"/> field instead of <input type="hidden"/> field.
At this case default reset process regularly.
This is correct as per the standard, unfortunately. A bad spec wart IMO. IE provides hidden fields with a resettable defaultValue nonetheless. See this discussion: it's not (alas) going to change in HTML5.
(Luckily, there is rarely any need to reset a form. As a UI feature it's generally frowned upon.)
Since you can't get the original value of the value attribute at all, you would have to duplicate it in another attribute and fetch that. eg.:
<form id="f">
<input type="hidden" name="foo" value="bar" class="value=bar"/>
function resetForm() {
var f= document.getElementById('f');
f.reset();
f.elements.foo.value= Element_getClassValue(f.elements.foo, 'value');
}
function Element_getClassValue(el, classname) {
var prefix= classname+'=';
var classes= el.className.split(/\s+/);
for (var i= classes.length; i-->0;)
if (classes[i].substring(0, prefix.length)===prefix)
return classes[i].substring(prefix.length);
return '';
}
Alternative ways of smuggling that value in might include HTML5 data, another spare attribute like title, an immediately-following <!-- comment --> to read the value from, explicit additional JS information, or extra hidden fields just to hold the default values.
Whatever approach, it would have to clutter up the HTML; it can't be created by script at document ready time because some browsers will have already overridden the field's value with a remembered value (from a reload or back button press) by that time that code executes.
Another answer, in case anyone comes here looking for one.
Serialize the form after the page loads and use those values to reset the hidden fields later:
var serializedForm = $('#myForm').serialize();
Then, to reset the form:
function fullReset(){
$('#myForm').reset(); // resets everything except hidden fields
var formFields = decodeURIComponent(serializedForm).split('&'); //split up the serialized form into variable pairs
//put it into an associative array
var splitFields = new Array();
for(i in formFields){
vals= formFields[i].split('=');
splitFields[vals[0]] = vals[1];
}
$('#myForm').find('input[type=hidden]').each(function(){
this.value = splitFields[this.name];
});
}
You can use jQuery - this will empty hidden fields:
$('form').on('reset', function() {
$("input[type='hidden']", $(this)).val('');
});
Tip: just make sure you're not resetting csrf token field or anything else that shouldn't be emptied. You can narrow down element's specification if needed.
If you want to reset the field to a default value you can use(not tested):
$('form').on('reset', function() {
$("input[type='hidden']", $(this)).each(function() {
var $t = $(this);
$t.val($t.data('defaultvalue'));
});
});
and save the default value in the data-defaultvalue="Something" property.
I found it easier to just set a default value when the document is loaded then trap the reset and reset the hidden puppies back to their original value. For example,
//fix form reset (hidden fields don't get reset - this will fix that pain in the arse issue)
$( document ).ready(function() {
$("#myForm").find("input:hidden").each(function() {
$(this).data("myDefaultValue", $(this).val());
});
$("#myForm").off("reset.myarse");
$("#myForm").on("reset.myarse", function() {
var myDefaultValue = $(this).data("myDefaultValue");
if (myDefaultValue != null) {
$(this).val(myDefaultValue);
}
});
}
Hope this helps someone out :)
$('#form :reset').on('click',function(e)({
e.preventDefault();
e.stopImmediatePropagation();
$("#form input:hidden,#form :text,#form textarea").val('');
});
For select, checkbox, radio, it's better you know (hold) the default values and in that event handler, you set them to their default values.
Create a button and add JavaScript to the onClick event which clears the fields.
That said, I'm curious why you want to reset these fields. Usually, they contain internal data. If I would clear them in my code, the post of the form would fail (for example after the user has entered the new data and tries to submit the form).
[EDIT] I misunderstood your question. If you're worried that someone might tamper with the values in the hidden fields, then there is no way to reset them. For example, you can call reset() on the form but not on a field in the form.
You could think that you could save the values in a JavaScript file and use that to reset the values but when a user can tamper with the hidden fields, he can tamper with the JavaScript as well.
So from a security point of view, if you need to reset hidden fields, then avoid them in the first place and save the information in the session on the server.
How I would do it is put an event listener on the change event of the hidden field. In that listener function you could save the initial value to the DOM element storage (mootools, jquery) and then listen to the reset event of the form to restore the initial values stored in the hidden form field storage.
This will do:
$("#form input:hidden").val('').trigger('change');
You can reset hidden input field value using below line, you just need to change your form id instead of frmForm.
$("#frmForm input:hidden").val(' ');