Rollback SELECT change with jQuery - javascript

I want a user to be able to confirm a selection they make in a select control, or to rollback to the previous value if they cancel. The following works fine in Chrome/Safari, but no matter what I try, I can't get it to work in Firefox (on Mac).
HTML:
<select id='my-select'>
<option value="client">Client</option>
<option selected="selected" value="assistant">Assistant</option>
<option value="manager">Manager</option>
</select>
JS:
$('#my-select').focus(function() {
//Store old value
$(this).data('lastValue',$(this).val());
});
$('#my-select').change(function(e) {
var lastRole = $(this).data('lastValue');
var newRole = $(this).val();
if(confirm("Change user's role from "+lastRole+" to "+newRole+"?"))
{
// The control may remain in focus, so we update lastValue here:
$(this).data('lastValue',newRole);
// Do stuff
}
else {
$(this).val(lastRole);
}
});​
Fiddle:
http://jsfiddle.net/yxzqY/13/
The issue can be demonstrated as follows:
Select 'Manager'
Click 'Cancel' (Selected value = 'Assistant')
Select 'Manager' again
Click 'Cancel' (Selected value = 'Assistant' in Chrome, Selected value = 'Manager' in FireFox)
I'm just stumped- no idea how to get this working in Firefox, or how to resolve the diff behavior across browsers.

Why do you need focus event? I think the problem with Firefox is that focus event fires also when you choose element from the dropdown menu before actual change event.
I think you do not need to overcomplicate your code. Try to change focus event to default initialization of data value. Something like this:
$('#my-select').each(function() {
$(this).data('lastValue', $(this).val());
});
And it should work fine.
DEMO: http://jsfiddle.net/yxzqY/17/

OK figured out a solution, if not the exact cause- The issue has something to do with how Firefox behaves when the control keeps focus through multiple selections- If you remove focus post-selection, it will behave properly.
The answer is to add $(this).blur(); at the end of the change handler.
http://jsfiddle.net/yxzqY/16/
$('#my-select').focus(function() {
//Store old value
$(this).data('lastValue',$(this).val());
});
$('#my-select').change(function(e) {
var lastRole = $(this).data('lastValue');
var newRole = $(this).val();
if(confirm("Change user's role from "+lastRole+" to "+newRole+"?"))
{
// Do stuff
}
else {
$(this).val(lastRole);
}
// IMPORTANT!: Firefox will not act properly without this:
$(this).blur();
});

Related

Is it possible to find out which select option has focus in IE before it is selected?

I'm trying to enable custom keyboard navigation of a jqxGrid. I've got it working 99.9% of the way, but I can't get IE to select the highlighted/focused options in a select box.
I wanted to see if there was a way to detect the option that's being focused on in order to manually set the select value when I hit the enter key.
I've tried:
var optVal = $select.find('option:selected').val();
$select.val(optVal);
which just gets the previous val of the select element, and:
var optVal = $select.find('option:focus').val();
$select.val(optVal);
which gets nothing.
EDIT: Also, I can't bind events directly to my controls.
How about checking the target.event of the keyup event (try on the select or on the option) ?
$("myselect").keyup(function(e) {
var code = e.which;
if(code==13) {
//check the event.target
}
});
$("myselect option").keyup(function(e) {
var code = e.which;
if(code==13) {
$("myselect").val($(this).val());
}
});

Bug in firefox with setting disabled attribute to select after change event

On page i have two with same options. If a select option it should be disabled in each select. Here is my demo: http://jsfiddle.net/bfmKw/8/
$("select").off('change').on('change', function () {
disableOptions();
});
function disableOptions() {
var $dropdowns = $('select');
$dropdowns.find('option').attr('disabled', false);
$.each($dropdowns, function (i, dropdown) {
var mark = $(dropdown).find('option:selected').attr('mark');
if (mark) {
$dropdowns.find('option[mark="' + mark + '"]:not(:selected)').attr('disabled', true);
}
});
}
But in firefox exist bug or feature. Steps for reproduction:
1) Open select box and choose option. Change event will rise and options will be disabled.
2) Open same select box, hover mouse on another option and click twice on diferent from select box place. Change event will be rised too.
If instead disabled set any another attribute all works fine. May be exist another way how can i disable options?
This wrong behavior appears after disabling selected option and only in firefox. Right disabling:
$dropdowns.find('option[mark="' + mark + '"]:not(:selected)').attr('disabled', true);

Select selected option again

I have a table and I use select menu in each row for different actions for that specific row.
For example:
$(document).on('change', '.lead-action', function() {
// Do stuff
}
this method gets the value of the selected option. Based on the selected value, I display different popups. When the user leaves the page, the select menu retains the previously selected option.
Sometimes users click on the same option in the select menu. When they do, the above code doesn't work.
Is there a way to invoke the code block above if the same option in the select menu is selected?
I'm gathering that you just want the dropdown to fire anytime a selection is made. If so, check out the answer to Fire event each time a DropDownList item is selected with jQuery.
See my updated answer below:
You can use this small extension:
$.fn.selected = function(fn) {
return this.each(function() {
var clicknum = 0;
$(this).click(function() {
clicknum++;
if (clicknum == 2) {
clicknum = 0;
fn(this);
}
});
});
}
Then call like this:
$(".lead-action").selected(function(e) {
alert('You selected ' + $(e).val());
});
Update:
I'm actually rather unhappy with the original script. It will break in a lot of situations, and any solution that relies on checking the click count twice will be very fickle.
Some scenarios to consider:
If you click on, then off, then back on, it will count both clicks and fire.
In firefox, you can open the menu with a single mouse click and drag to the chosen option without ever lifting up your mouse.
If you use any combination of keyboard strokes you are likely to get the click counter out of sync or miss the change event altogether.
You can open the dropdown with Alt+↕ (or the Spacebar in Chrome and Opera).
When the dropdown has focus, any of the arrow keys will change the selection
When the dropdown menu is open, clicking Tab or Enter will make a selection
Here's a more comprehensive extension I just came up with:
The most robust way to see if an option was selected is to use the change event, which you can handle with jQuery's .change() handler.
The only remaining thing to do is determine if the original element was selected again.
This has been asked a lot (one, two, three) without a great answer in any situation.
The simplest thing to do would be to check to see if there was a click or keyup event on the option:selected element BUT Chrome, IE, and Safari don't seem to support events on option elements, even though they are referenced in the w3c recommendation
Inside the Select element is a black box. If you listen to events on it, you can't even tell on which element the event occurred or whether the list was open or not.
The next best thing is to handle the blur event. This will indicate that the user has focused on the dropdown (perhaps seen the list, perhaps not) and made a decision that they would like to stick with the original value. To continue handling changes right away we'll still subscribe to the change event. And to ensure we don't double count, we'll set a flag if the change event was raised so we don't fire back twice:
Updated example in jsFiddle
(function ($) {
$.fn.selected = function (fn) {
return this.each(function () {
var changed = false;
$(this).focus(function () {
changed = false;
}).change(function () {
changed = true;
fn(this);
}).blur(function (e) {
if (!changed) {
fn(this);
}
});
});
};
})(jQuery);
Instead of relying on change() for this use mouseup() -
$(document).on('mouseup', '.lead-action', function() {
// Do stuff
}
That way, if they re-select, you'll get an event you can handle.
http://jsfiddle.net/jayblanchard/Hgd5z/

Choosing same option in select list

What I have is a html select list that is populated through jquery. Right now I have the change event so that when I change the option, the map refocuses on the POI. I'm trying to make it work so that when I click on the same option, the map treats it as a change event. Options don't support click events, and adding a click event on the select list doesn't work either, seeing as there would be 2 click events.
In summary, .change() doesn't trigger if you click the same option.
Is there a way to make this work, a modification to the option tag or another event I may not be aware of?
Thanks!
Try to do something like this:
$('select').on({
change: function(e) {
alert('change')
$(this).data('change', true);
},
click: function() {
if (!$(this).data('change')) {
$(this).trigger('change');
}
$(this).data('change', false);
}
});
http://jsfiddle.net/WFmpW/1/
So the idea is to trigger change event on click only if there were not previous option change. To do this we can set some flag like I did with data-change.
Correct answer:
I'll just edit this answer so I can accept this as the correct answer seeing as the idea is right but the implementation isn't. The correct way is to take out the .change event. Link to the correct code: http://jsfiddle.net/qcJwm/1/.
Code:
$('select').click(function () {
if ($(this).data('click')) {
doStuff();
$(this).data('click', false);
} else {
$(this).data('click', true);
}
});
var doStuff = function () {
alert('stuff');
}
You could add a first option with no value. On change you change the value of the first option to that of the selected option and perform your ´goto-code'.
Because you want to be able to change it again, you have to make the first option selected with $('item')[0].selectedIndex=0. This will not be noticable by the user, because it has the same value. Because of this, your user can change it again to the option they just selected, to fold it back
I had the very same problem, but also needed it to work on mobile, so I combined couple different solutions. Unfortunately I didn't find a way to do all this without triggering the target function multiple times, so I ended up limiting it with setTimeOut. :(
It's far from perfect, but works in my scenario:
<select id="select">
<option disabled selected>Pick one..</option>
<option value="1">one</option>
<option value="2">two</option>
<option value="3">three</option>
<option value="4">four</option>
<option class="dummy" style="display:none">Pick one..</option>
</select>
And jQuery:
var canDo = true; //variable for settimeout
$('#select').on('focus',function(){
$(this).find("option.dummy").text($(this).find("option:selected").text());
$(this).find("option.dummy").prop("selected", true);
$(this).data('click', true);
});
$('#select').on('change blur',function(){
//blur is optional and offers solution to the case where user closes options
//in mobile ja taps away (if you then want to trigger the function). BUT, it
//also causes a bug: if user opens options and clicks the topmost option, which
//is the header bar showing currently selected option, options are hidden and
//function triggered - but the focus stays on the element, so when user clicks
//away, function is re-triggered.
var select = $(this);
var text = select.find("option:selected").text();
$('.dummy').attr('value',select.val()).text(text);
doYourThing($(select).val());
});
$('#select option').on('click',function(){ //note that we're checking clicks to option instead of select
if($(this).data('click')){
$(this).data('click', false);
doYourThing($(select).val());
}else{
$(this).data('click', true);
}
$(this).parent().blur();
});
function doYourThing(stuff){
if(canDo){
canDo = false;
alert('Selected '+stuff);
canDoTimeout = setTimeout(function(){
canDo = true;
}, 500);
}
}
jsFiddle: http://jsfiddle.net/nxabv0wk/3/

Run change event for select even when same option is reselected

Basically, I have drop down menu that looks like this:
<select>
<option>0</option>
<option selected="selected">1</option>
<option>2</option>
<option>3</option>
</select>
I am trying to write a function that is fired even when you select the same option, i.e. even if the drop-down is opened and re-select the selected option, I want it to execute the function.
If you mean selecting with the mouse, you can use mouseup. However, it will fire when the select box is being opened as well, so you'll need to keep track of the amount of times it was fired (even: select is being opened, odd: select is being closed): http://jsfiddle.net/T4yUm/2/.
$("select").mouseup(function() {
var open = $(this).data("isopen");
if(open) {
alert(1);
}
$(this).data("isopen", !open);
});
pimvdb's answer was a big help for me but I added a couple of extra bits to deal with keyboard activation and navigation away from the select:
$('select').mouseup(... as in pimvdb... )
.blur(function() {
$(this).data('isopen', false);
}).keyup(function(ev) {
if (ev.keyCode == 13)
alert(1);
});
The blur handler deals with navigating away from the select while the dropdown is open, the keyup handler deals with when you change the select's value with the keyboard. The behaviour is then that the user is only considered to have finally selected the value when they click return to navigate away. If you want a different behaviour with the keyboard that shouldn't be hard to do.
select isn't meant to be used this way — there are hacks you can use to get this kind of behavior in most cases, like tracking mouse and keyboard events on the select, but there’s no guarantee they’ll keep working, or work on every platform.
I would suggest either…
Resetting the select to its default value on change, and using some other text to indicate which one is “selected”, or
using a control other than select.
Can you describe the end goal a little more detail?
An alternative, use the .blur() event -- http://jsfiddle.net/VKZb2/4/
Pro
This will fire either way.
Con
It only fires once the control loses focus.
I ran into the same issue. I just added a click event to the option tags and change the value of the select:
$("#select option").mouseup(function() {
$(this).parent().val($(this).attr("value"));
// do something.
});
NOTE: This doesn't work on iPhone or iPad devices.
Try the below solution. It accounts for loss of focus via mouse click or Esc key.
// whether or not dropdown is opened
var open = false;
$("#selectElement").on("click", function() {
open = !open;
if (!open)
{
console.log("option has been selected/re-selected");
}
});
// update dropdown state upon loss of focus
$("#selectElement").on("blur", function() {
if(open){
open = !open;
}
});
// update dropdown state upon Esc key of focus
$(document).keyup(function(e) {
if (e.keyCode == 27) {
if(open){
open = !open;
}
}
});

Categories