I have a page which contains multiple HTML select dropdowns, and requires population onclick of the element. This population is done using an AJAX call in the click event listener of the select elements.
The reason for this is that performance and load are very crucial, and therefore they cannot be populated on page load.
Also, the design must use the native HTML select element.
I have created a jsFiddle demo to show the issue. When you click on the select the items are populated, and the width of the select increases as a result.
However the select only displays the initial option (prior to AJAX population).
------ View Demo ------
Demo uses setTimeout() of 50 milliseconds to emulate an AJAX response time.
How can I get this to populate onclick, and display correctly?
Is there a way of opening the select on callback of the popualation response?
EDIT: Alternatively, is there a jQuery plugin dropdown, which uses the browser's native theme for styling?
What I've tried so far
Populating the select on hover, however a quick user can open the select before the options have loaded. Also, if a user was to scroll all the way down the page, and over every select, this would cause a lot of unnecessary AJAX calls.
Changing the event listener to focus instead of click (as #AndyPerlitch suggested). However, this wouldn't work if the AJAX request took only 50 milliseconds to respond. (See Demo)
Changing the event listener to mousedown has the same effect as focus
UPDATE: This is not an issue in FireFox. select opens, then loads new items and displays them, all while in an open state.
Change the event to listen for from click to focus
Personally I would opt for a different approach completely, but it depends on you needs. Here I am assuming that the drop down will "almost definitely" be clicked (and thus loaded) at some point by the user.
With that in mind I would be tempted to populate the select lists using ajax as soon as the page is loaded. This has the benefit of being able to load the page quick (as there is still no "page load" list collecting) but it also means the ajax will most likely be complete before the user works out that they need to use the select list. I would even go an extra step and have temporary loading icons in place of the selected while the ajax is working it's magic (or disable them!) in case the ajax is having a slow day and the user is fast like superman.
of course, this all depends on how "set in stone" your requirement is to do the ajax load upon user interaction with the drop down element
or maybe this might prove some use?
The select will always display as it was before the click event started. You will therefore see only the initial option because you do the AJAX population after the click event started.
This may be a compromise for you but try to AJAX-populate before the click event. This may be:
-on hover, as you have done already (user has to scroll for the click anyway)
-an extra click for your users on an element neighbouring the select
Hide the drop down list and have something else in its place for the user to click on to trigger loading the drop down and displaying it.
Related
I'm using jquery's bPopup() to open a modal window. When the user clicks a button, jquery loads an ajax page and then shows the modal windows. Due to this small delay when loading the page, the button remains active, and if the user clicks twice, it will fire twice, making two ajax requests to the server and opening two windows.
Is there a simple way to prevent this from happening? Since it's relatively a common problem, I wonder if there's a "right" way the pros handle it.
I've tried assigining the popup to a window.object, so that it would be overwritten on the second call, but it's still opening two popups.
That depends on what UX you're after, but I'd suggest you disable the button.
That way your user will:
Know the click was "registered".
Not try to click again.
Not crash / confuse you code.
EDIT
According to the comment, the "button" is actually not a <button>, but an element with an onclick handler. So:
You can disable the click handler by reversing what you did to set it (removeEventHandler, onclick=null...), but you'd then have to set it back once the pop-up is done, and that might be quite annoying.
You'd have to somehow manipulate the UI to indicate the button was clicked and is disabled. Could probably be quite simple to do with a CSS class.
But really, you're probably better off having 2 "versions" of your button element (<div>...), with only 1 visible at a time, with the other hidden via display: none. The "clicked" version should not have a click event handler set at all. Then, when the button is clicked, you immediately switch between the 2 (can be done with a single CSS class), and once the pop-up is done, switch back.
I don't know if this is the effects of an update panel or what, but I basically have a drop down list that allows a user to select an item as a filter. When the item is selected it should bring back only one item into a grid view. That is this specific filter will at most bring back the record you are looking for. This works fine if the user clicks an "apply" link to apply the filter. Behind the apply link is some server-side code (C# within an ASP.NET Web Forms application).
We had a request by a user with something to the effect of:
"Why do I have to click the apply button if I make a selection in this
one drop down filter...it should simply get that one record I am
searching for. This helps me because I don't have to click the
"Apply" button."
I agreed with him and thought what is the easiest way to do this...I thought: Simple, I will have an on change event handler of the drop down such that when a selection is made I'll trigger a click event. Something to this effect:
$("#MainContent_ddlCompany").on("change", function() {
var companyId = $("#MainContent_ddlCompany").val();
$("#MainContent_hdnCompanyValue").val(companyId);
$("#<%=ddlCompany.ClientID %>").trigger("chosen:updated");
if (companyId.length > 0) {
$(".apply").click();
$(".apply").removeClass("applyButton");
$(".apply").addClass("resetButton");
} else {
//cleared selection of a company
$(".apply").removeClass("resetButton");
$(".apply").addClass("applyButton");
}
});
At first this didn't work, and I couldn't tell why, but then after some serious googling I changed this line:
$(".apply").click();
To this:
$('.apply')[0].click();
That worked great...so I decided to test it some more. As I kept selecting one filter value after another I noticed the page started to slow down. In fact by the 6th or 7th time it was pretty unusable. I don't know why it's happening, but I suspect again it has to do with the fact that this linkbutton with the class name .apply is inside an update panel.
But still I thought to myself, it was inside of an update panel before I changed my jQuery code to simulate the click event. So why does the page slow down and drag with this little piece of code? Is calling the event from jQuery code rendering something else in the HTML that could be causing this?
If I change my code back and force the user to click the apply button then we are back to a good normal speed. Why is it if I tell jQuery to simulate clicking the button my page slow down? It's doing the same thing, the simulation of the click of this link button is calling its server-side code method whether the user clicks it or I have jQuery click it.
For now I'm at a loss as to why this is happening because this button is in an update panel in either case, yet when I have jQuery click it via $('.apply')[0].click(); the page slows down after several attempts. Yet when I have the user simply click this button (without the jQuery click event) then it works fine?
What am I missing here?
Ugh, well, I found my issue. Because I was using updatepanels I had to wrap my jQuery code to include an add_endRequest. That is, you have something to the effect of:
$(document).ready(function() {
//Some initial event/triggers
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
//Copy of some initial event/triggers
});
});
Why do I use the endRequest you ask? Well, because updatepanels basically throw away all your events after an asynchronous postback because the HTML at that point (after an update) is rendered again and at that point all events associated with any control inside an update panel are wiped away. At this point of course document.ready() does not run, so I have to resubscribe to these events inside of endRequest. Enter my issue...
I had a huge brain fart where I basically took everything, literally everything inside document ready and copied it into endRequest. In fact, if I remember correctly, I read articles which stated
Whatever you have in document ready simply copy paste into endRequest
That's fine, but you have to be careful here. I was throwing in events that were not wrapped around inside of an updatepanel into endRequest. The result is disastrous...at least for me.
These events would be attached then multiple times..or based on the number of asynchronous postbacks made. In my case, as I was testing I mentioned after the 6th or 7th time performance starts degrading. Well, by that time my controls were being attached that many times to events. For instance, my .apply button along with my dropdownlist were both outside of my updatepanel. But my jQuery code was attaching the change event of my dropdownlist in both document ready and endRequest.
The result is initially it's pretty fast, because it's only in document ready. But as I make asynchronous postbacks these events are being attached every time. For n tests I would have n attached events...in my case the test of 7 yields 7 on change event handlers!
Case in point, do not place any event handlers such as jQuery's on() event for any controls that are NOT inside an update panel. Otherwise you will run into what I ran into which was poor performance as events are happening.
We're currently using the Chosen Dropdown Plugin which is rather awesome, apart from one minor issue. When we're using a single dropdown, if you tab into the 'chosen' control, the actual dropdown portion is not shown. However, when applying the plugin to a multiple 'select', it does appear.
Having been through the documentation and GitHub issues, there seems to be a lot of mentions regarding tab ordering and focusing, but nothing that seemingly deals with this rather simple requirement; Display the dropdown when receiving focus when tabbing.
So assuming that this functionality is not part of the plugin, is there an alternative such as capturing the focus of the anchor tag?
$('.chzn-single').focus(function(e){
alert('I should be focused!')
});
So far, I haven't been successful and was wondering whether any others have experienced this issue. You can check out this jsfiddle that demonstrates the problem
You should keep track of focus event for the search input thats inside chosen conainer, not the anchor element, then trigger mousedown event for the chosen container - that's the event that it listens to when opening a dropdown
You need to use delegated events approach to bind event handler to elements added dynamically (for jquery 1.7.1 and earlier you may just use 'live' method)
You also need to check if the container is active currently, to avoid recursive calls (when chosen dropdown gets opened - search input will be focused again)
$('body').on('focus', '.chzn-container-single input', function() {
if (!$(this).closest('.chzn-container').hasClass('chzn-container-active'))
$(this).closest('.chzn-container').trigger('mousedown');
//or use this instead
//$('#select').trigger('liszt:open');
});
Here's working jsfiddle
Instead of $(this).closest('.chzn-container').trigger('mousedown');
you may also trigger plugin's internal event: $('#select').trigger('liszt:open');
I have a series of select dropboxes setup, with content that dynamically updates depending upon the preceeding selection. It works fine selecting in series.
When I try to go back to the top and start again, even though I have attempted to reset all children using
my_select.selectedIndex = 0;
The child select boxes remain unchanged. I had thought it was a Javascript error, but found the JSFiddle example actually worked, but my code within JQuery mobile does not work - leading me to believe it is a JQuery Mobile related issue
You can see a JSFiddle example at http://jsfiddle.net/vinomarky/xfcdF/
Steps to replicate:
Select 'Casing' from Type
Select 5 from OD
Change Type to Tubing
The JSFiddle example behaves as it should - resetting children to "-", while my 'live' JQuery Mobile example does not
Any ideas as to why?
You're manipulating the DOM behind jQuery Mobile's back but never telling jQuery Mobile that anything has changed.
You need to call the refresh method after you change the underlying <select>:
refresh update the custom select
This is used to update the custom select to reflect the native select element's value.If the number of options in the select are different than the number of items in the custom menu, it'll rebuild the custom menu.
So you need to add things like this:
$('#od').selectmenu('refresh');
at the bottom of your change handlers. The element to refresh does, of course, depend on which change handler you're in.
Demo: http://jsfiddle.net/ambiguous/n3VXe/
Your fiddle worked fine because it didn't use jQuery Mobile at all.
Also, you shouldn't be using onchange attributes in 2012, you're loading jQuery so you should use it to bind handlers to the events you're interested in. You might want to replace all your direct DOM manipulation with jQuery as well.
I have a system with a fast-changing set of items that may appear as options in select boxes. I could update the options themselves directly each time the data changes, but I'd rather simply fill in the options at the point where the user is about to see them. E.g. when it's about to open. Is there an event for this?
I suppose I could use the 'click' or 'mousedown' event, but what about navigating via the keyboard? There may be other cases too (perhaps)
BTW, I know how to add options to a select, the 'opening' event is really what I'm after.
Thanks,
Ben
You've got two choices: click() and focus() there are no others.
Use focus() and not click() because the click event does not give enough time to populate the drop down with new values which causes quirky behavior. Also the click event will only capture mouse clicks, with the focus() you get both mouse and keyboard focus events and also it gives ample time for the drop down to get populated with new data. Here is a fiddle with some simple experiments, try each function one at a time to see the difference.
If you're doing something like this, a select drop down probably isnt going to be the UI element of choice.
I would recommend changing to a jQuery UI Autocomplete widget; then you can simply serve items based on the query the user entered.
In addition, you can attach to the keyup event (or the focus event), and show a set of items at that point (as if the 'drop down' was clicked on) http://jqueryui.com/demos/autocomplete/#maxheight