I have been trying to implement the autocomplete and have come across a problem that has stumped me. The first time I call .autocomplete it all works fine and I have no problems. If, however, I call it after I have removed some (unrelated) elements from the DOM and added a new section to the DOM then autocomplete does nothing and reports no errors.
Code:-
$.ajax({
type : 'get',
dataType : 'json',
url : '/finance/occupations',
cache:true,
success:function(data){
occupationList = data;
$('.js-occupation').autocomplete({
source: occupationList,
messages: {
noResults: '',
results: function(){}
},
minLength : 2,
select:function(event, ui){
$('.js-occupationId').val(ui.item.id);
}
});
}
});
The background to this page is that it contains multiple sections that are manipulated as the user moves through them. Hide and show works fine and does not impact on the autocomplete. However, if I do the following:-
var section = $('.js-addressForm:last').clone();
clearForm(section);
$('div.addressDetails').append(section);
$('.js-addressForm:first').remove();
Which gives the user the bility to add multiple addresses on the previous section then the autocomplete stops working.
Any suggestions or pointers on something obvious I am missing?
I have tried to put the initialisation of the autocomplete on an event when the element gets focus and it still does not work.
You have to create the autocomplete after all other underlying objects. If you F12, you will see that the list is "visible", however it is below and hidden by all instances created after it.
If you created a div with inputs (one input being the autocomplete), then you create the automplete then the dialog instances, the autocomplete will never show. If you create the dialog then the autocomplete, no problem. The problem is the z-order
I have faced the same issue. For now to fix this, i'm creating widget on the input once input is in focus. It will help you solve the issue.
You can look for the help on
making sure some event bing only when needed
Sample code will look like this
$( "#target" ).focus(function() {
//I don't care if you manipulated the DOM or not. I'll be cautious. ;)
(function() {
$( "#combobox" ).combobox();
$( "#toggle" ).click(function() {
$( "#combobox" ).toggle();
});
})();
// use a flag variable if you want
});
This solved my problem. Hope its the solution you were looking f
Related
I fill list dynamically, and after that on click I have multiple calls of event. 1st time it is repeated 1 time, 2nd time 2 times, 3rd time 3 times, etc...
First, more about this problem can be found in my other answer: jQuery Mobile: document ready vs page events
Prevent multiple event binding/triggering
Because of interesting jQM loading architecture, multiple event triggering is a constant problem. For example, take a look at this code snipet:
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/CCfL4/
Each time you visit page #index click event will is going to be bound to button #test-button. There are few ways to prevent this problem:
Solution 1:
Remove event before you bind it:
$('#index').live('pagebeforeshow',function(e,data){
$('#test-button').die().live('click', function(e) {
alert('Button click');
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/K8YmG/
In case you have different events bound to an object:
$('#index').live('pagebeforeshow',function(e,data){
$('#test-button').die('click').live('click', function(e) {
alert('Button click');
});
});
Solution 2:
Use a jQuery Filter selector, like this:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
Because event filter is not a part of official jQuery framework it can be found here: http://www.codenothing.com/archives/2009/event-filter/
In a nutshell, if speed is your main concern then Solution 2 is much better then Solution 1.
Solution 3:
A new one, probably an easiest of them all.
$(document).on('pagebeforeshow', '#index', function(){
$(document).on('click', '#test-button',function(e) {
if(e.handled !== true) // This will prevent event triggering more then once
{
alert('Clicked');
e.handled = true;
}
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/Yerv9/
Tnx to the sholsinger for this solution: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
More info
If you want to find more about this problem take a look at this article, working examples are included.
I am using the pagecreate initialization event to call a function which makes an AJAX call to populate a list.
The problem I have is that this event never completes. The page loading message persists.
I've search here and on the Jquery forum, without any luck.
My code looks like this:
$( "#events" ).live( 'pagecreate', function(event) {
// Executed once the page is loaded
var fromDate = new Date(),
toDate = new Date(fromDate.getFullYear(), fromDate.getMonth() + 3, fromDate.getDate());
update(fromDate, toDate);
//alert('done');
});
function update(from, to) {
var eventList = $('ul#event-list');
$.ajax({
url: 'events.php',
dataType: 'json',
data: {from: from, to: to},
success: function(data) {
showEvents(data, from, to, eventList); // Create list items and append to eventList
$('.value h2').formatCurrency({ negativeFormat: "-%s%n" }); // Format currency correctly using jQuery plugin
}
});
}
I get an "a.Deferred is not a function" error, which suggests to me it has something to do with the completion of the AJAX call, but I've checked, and the showEvents function is correctly creating the list items, so it's not hanging.
After reading this, I tried alternative initialization events: pageinit, and even changePage, without success.
Thanks for your help.
p.s. in case it helps, uncommenting that alert() gets the updated list to reformat correctly, without solving the problem. I figure I'd mention it, since I obviously don't understand what's going on.
If u want to run
the code only once when your project loaded then use
mobileinit. pageshow for every view of page and pagecreate for first
time when pagecreate in your project.
I have a custom select menu (multiple) defined as follows:
<select name="DanceStyles" id="DanceStyles" multiple="multiple" data-native-menu="false">
Everything works fine except that I want to move the header's button icon over to the right AND display the Close text. (I have found some mobile users have a problem either realising what the X icon is for or they have trouble clicking it, so I want it on the right with the word 'Close' making too big to miss.) There don't seem to be any options for doing that on the select since its options apply to the select bar itself.
I have tried intercepting the create event and in there, finding the button anchor and adding a create handler for that, doing something like this (I have tried several variations, as you can see by the commenting out):
$('#search').live('pagecreate', function (event) {
$("#DanceStyles").selectmenu({
create: function (event, ui) {
$('ul#DanceStyles-menu').prev().find('a.ui-btn').button({
create: function (event, ui) {
var $btn = $(this);
$btn.attr('class', $btn.attr('class').replace('ui-btn-left', 'ui-btn-right'));
$btn.attr('class', $btn.attr('class').replace('ui-btn-icon-notext', 'ui-btn-icon-left'));
// $(this).button({ iconpos: 'right' });
// $btn.attr('class', $btn.attr('class').replace('ui-btn-icon-notext', 'ui-btn-icon-left'));
// // $btn.attr('data-iconpos', 'left');
$(this).button('refresh');
}
});
}
});
});
So I have tried resetting the button options and calling refresh (didn't work), and changing the CSS. Neither worked and I got weird formatting issues with the close icon having a line break.
Anyone know the right way to do this?
I got this to work cleanly after looking at the source code for the selectmenu plugin. It is not in fact using a button; the anchor tag is the source for the buttonMarkup plugin, which has already been created (natch) before the Create event fires.
This means that the markup has already been created. My first attempt (see my question) where I try to mangle the existing markup is too messy. It is cleaner and more reliable to remove the buttonMarkup and recreate it with my desired options. Note that the '#search' selector is the id of the JQ page-div, and '#DanceStyles' is the id of my native select element. I could see the latter being used for the id of the menu, which is why I select it first and navigate back up and down to the anchor; I couldn't see any other reliable way to get to the anchor.
$('#search').live('pagecreate', function (event) {
$("#DanceStyles").selectmenu({
create: function (event, ui) {
$('ul#DanceStyles-menu').prev().find('a.ui-btn')
.empty()
.text('Done')
.attr('class', 'ui-btn-right')
.attr("data-" + $.mobile.ns + "iconpos", '')
.attr("data-" + $.mobile.ns + "icon", '')
.attr("title", 'Done')
.buttonMarkup({ iconpos: 'left', icon: 'arrow-l' });
}
});
});
The buttonMarkup plugin uses the A element's text and class values when creating itself but the other data- attributes result from the previous buttonMarkup and have to be removed, as does the inner html that the buttonMarkup creates (child span, etc). The title attribute was not recreated, for some reason, so I set it myself.
PS If anyone knows of a better way to achieve this (buttonMarkup('remove')? for example), please let us know.
the way i achieved it was changing a bit of the jquery mobile code so that the close button always came to the right, without an icon and with the text, "Close"
not the best way i agree. but works..
I got a similar case, and I did some dirty hack about this :P
$("#DanceStyles-button").click(function() {
setTimeout(function(){
$("#DanceStyles-dialog a[role=button]").removeClass("ui-icon-delete").addClass("ui-icon-check");
$("#DanceStyles-dialog .ui-title").html("<span style='float:left;margin-left:25px' id='done'>Done</span>Dance Styles");
$("#DanceStyles-dialog .ui-title #done").click(function() {
$("#DanceStyles").selectmenu("close")
});
},1);
} );
I want to set the overlay of a jQuery dialog to an image, and can't seem to manage the task.
I have other dialogs on the pages that I want to no have the background images, so setting the css for the overlay background won't work as a blanket solution.
I have tried a lot of different methods, and I believe there is a timing issue with the appliction of the jQuery command to set the overlay with css and the actual dialog div's and css getting added to the DOM.
Here is what I have tried so far.
$('#submitUpload').click(function(){
$("#uploadStart").dialog('open');
$(".ui-widget-overlay").css({'background-image': 'url("http://www.mydomain.com/images/ftp-page-bg.gif")','opacity':'1'})
$("#uploadForm").submit();
});
OR
$("#uploadStart").dialog({
autoOpen: false,
width: 400,
modal: true,
closeOnEscape: false,
draggable: false,
resizable: false,
open: function(event, ui) {
$(".ui-dialog-titlebar-close").hide();
$(".ui-widget-overlay").css({'background-image': 'url("http://www.mydomain.com/images/ftp-page-bg.gif")','opacity':'1'})
}
});
I have also tried using the dialogClass method on the dialog code with no success.
With both the absolute url and the relative, and the url in quotes or with no quotes.
The image exists in the directory.
Anyone have any ideas on how to get jQuery to apply with the correct timing to display the image as the overlay?
Thanks!
Update
The dialog class designation will allow you to set classes for the overal dialog. I was actually looking to just tap into the specific ui-widget-overlay class and over-ride the background image there. I found that trying to override the background using the dialogClass worked for overriding the background of the dialog, not the overlay background.
When the dialog is added to the DOM, jQuery loads it's div's right before the body tag.
I found a solution, being that in the open method for the dialog, I used
$(".ui-widget-overlay").addClass('artFTP');
to add a class
.artFTP{background-image: url(../../images/ftp-page-bg.gif); opacity:1;}
and made sure it was the last class in the file that would overwrite the overlay background image.
I hope this helps someone.
Thanks and +1 to jjross, your answer got me to jump back into the jQuery docs.
If anyone has a better solution, please post. I would be happy to see it. I think there might be a way to use CSS to accomplish the task, but (for the life of me) couldn't figure it out.
You should be able to add the class to the div in your HTML code prior to jquery being called on it. In my testing, this automatically added that class to the dialog when it was created.
In the new class, you should be able to specify a background image.
For example:
calling:
$("#dialog").dialog();
on
<div id="dialog" class="thisClass" title="Edit Case Status">
<div>some stuff</div>
</div>
causes the dialog to be created with the
"thisClass" class.
as an alternative option, it looks like the dialog has a "dialogClass" method. It will let you add your own class to the dialog (in that class, you can define the background). From the docs:
The specified class name(s) will be added to the dialog, for additional theming.
Code examples
Initialize a dialog with the dialogClass option specified.
$( ".selector" ).dialog({ dialogClass: 'alert' });
Get or set the dialogClass option, after init.
//getter
var dialogClass = $( ".selector" ).dialog( "option", "dialogClass" );
//setter
$( ".selector" ).dialog( "option", "dialogClass", 'alert' );
I encountered the same problem and found In this case your question. I didn't find any solution that could satisfy me, so I did something on my own.
First, let me introduce my problem.
I have a page, where I have two kinds of dialogs. Dialogs with video and dialogs with message (like alert, confirmation, error etc.). As we know, we can set a different class for a dialog, but we can't set class for different overlay. So question was, how to set a different behavior for different overlays?
So I dig, I dig deeper than Dwarves in Moria into jQuery ui code itself. I found out, that actualy there is an unique overlay for each dialog. And it is created in "private" function _createOverlay which is not accessible. In fact, I found function via jquery ui namespace as $.ui.dialog.prototype._createOverlay. So I was able to make a small extension with logic based on class:
(function() {
// memorize old function
var originFn = $.ui.dialog.prototype._createOverlay;
// make new function
$.ui.dialog.prototype._createOverlay = function() {
originFn.call(this); // call old one
// write your own extension code there
if (this.options["dialogClass"] === "video-dialog") {
var overlay = this.overlay; // memorize overlay (it is in old function call as this.overlay)
var that = this; // just cause bind is event
// my own extenstion, when you click anywhere on overlay, dialog is closed + I change css
overlay.bind('click', function() {
that.close(); // it is same like element.dialog('close');
}).css({
"background": "none",
"background-image": "url(\'files/main-page/profile1.png\')" // this didnt work for you, but works for me... maybe I have newer version of jQuery.UI
// anyway, once you have overlay as variable, Im sure you will be able to change its css
});
}
};
})();
I hope this will help others :)
I've searched everywhere, but I can't seem to find any help...
I have some textboxes that are created dynamically via JS, so I need to bind all of their classes to an autocomplete. As a result, I need to use the new .live() option.
As an example, to bind all items with a class of .foo now and future created:
$('.foo').live('click', function(){
alert('clicked');
});
It takes (and behaves) the same as .bind(). However, I want to bind an autocomplete...
This doesn't work:
$('.foo').live('autocomplete', function(event, ui){
source: 'url.php' // (surpressed other arguments)
});
How can I use .live() to bind autocomplete?
UPDATE
Figured it out with Framer:
$(function(){
$('.search').live('keyup.autocomplete', function(){
$(this).autocomplete({
source : 'url.php'
});
});
});
jQuery UI autocomplete function automatically adds the class "ui-autocomplete-input" to the element. I'd recommend live binding the element on focus without the "ui-autocomplete-input"
class to prevent re-binding on every keydown event within that element.
$(".foo:not(.ui-autocomplete-input)").live("focus", function (event) {
$(this).autocomplete(options);
});
Edit
My answer is now out of date since jQuery 1.7, see Nathan Strutz's comment for use with the new .on() syntax.
If you are using the jquery.ui.autocomplete.js try this instead
.bind("keydown.autocomplete") or .live("keydown.autocomplete")
if not, use the jquery.ui.autocomplete.js and see if it'll work
If that doesn't apply, I don't know how to help you bro
Just to add, you can use the .livequery plugin for this:
$('.foo').livequery(function() {
// This will fire for each matched element.
// It will also fire for any new elements added to the DOM.
$(this).autocomplete(options);
});
To get autocomplete working when loaded dynamically for the on() event used in jQuery > 1.7, using the syntax Nathan Strutz provides in his comment:
$(document).on('focus', '.my-field:not(.ui-autocomplete-input)', function (e) {
$(this).autocomplete(options)
});
where .my-field is a selector for your autocomplete input element.
.live() does not work with focus.
also keyup.autocmplete does not make any sense.
Instead the thing I have tried and working is this
$(document).ready(function(){
$('.search').live('keyup' , function()
{
$(this).autocomplete({ source : 'url.php' });
});
})
This works perfectly fine.
You can't. .live() only supports actual JavaScript events, not any custom event. This is a fundamental limitation of how .live() works.
You can try using this:
$('.foo').live('focus.autocomplete', function() {
$(this).autocomplete({...});
});
After reading and testing everyone else's answers I have updated it for the current version of JQuery and made a few tweaks.
The problem with using keydown as the event that calls .autocomplete() is that it fails to autocomplete for that first letter typed. Using focus is the better choice.
Another thing I have noticed is that all of the given solutions result in .autocomplete() being called multiple times. If you are adding an element dynamically to the page that will not be removed again, the event should only be fired once. Even if the item is to be removed and added again, the event should be removed and then added back each time the element is removed or added so that focusing on the field again will not unnecessarily call .autocomplete() every time.
My final code is as follows:
$(document).on('focus.autocomplete', '#myAutocomplete', function(e){
$(this).autocomplete(autocompleteOptions);
$(document).off('focus.autocomplete', '#myAutocomplete');
});
autocomplete is not an event rather a function that enables autocomplete functionality for a textbox.
So if you can modify the js that creates the textboxes dynamically to wrap the textbox element in as a jquery object and call autocomplete on that object.
I just noticed you edited your post with this answer. It was obvious to me so I'm posting it below for others. Thank you.
$(function()
{
$('.search').live('keyup.autocomplete', function()
{
$(this).autocomplete({ source : 'url.php' });
});
});
This works for me:
$(function()
{
$('.item_product').live('focus.autocomplete', function()
{
$(this).autocomplete("/source.php/", {
width: 550,
matchContains: true,
mustMatch: false,
selectFirst: false,
});
});
});
You can just put the autocomplete inside input live event, like this:
$('#input-element').live('input', function(){
$("#input-element").autocomplete(options);
});