jQuery $.get being called multiple times...why? - ajax

I am building this slideshow, hereby a temp URL:
http://ferdy.dnsalias.com/apps/jungledragon/html/tag/96/homepage/slideshow/mostcomments
There are multiple ways to navigate, clicking the big image goes to the next image, clicking the arrows go to the next or previous image, and you can use your keyboard arrows as well. All of these events call a method loadImage (in slideshow.js).
The image loading is fine, however at the end of that routine I'm making a remote Ajax call using $.get. The purpose of this call is to count the view of that image. Here is the pseudo, snipped:
function loadImage(id,url) {
// general image loading routine
// enable loader indicator
$("#loading").show();
var imagePreloader = new Image();
imagePreloader.src = url;
loading = true;
$(imagePreloader).imagesLoaded(function() {
// load completed, hide the loading indicator
$("#loading").hide();
// set the image src, this effectively shows the image
var img = $("#bigimage img");
img.attr({ src: url, id: id });
imageStartTime = new Date().getTime();
// reset the image dimensions based upon its orientation
var wide = imagePreloader.width >= imagePreloader.height;
if (wide) {
img.addClass('wide');
img.removeClass('high');
img.removeAttr('height');
} else {
img.addClass('high');
img.removeClass('wide');
img.removeAttr('width');
}
// update thumb status
$(".photos li.active").removeClass('active');
$("#li-" + id).addClass('active');
// get the title and other attributes from the active thumb and set it on the big image
var imgTitle = $("#li-" + id + " a").attr('title');
var userID = $("#li-" + id + " a").attr('data-user_id');
var userName = $("#li-" + id + " a").attr('data-user_name');
$(".caption").fadeOut(400,function(){
$(".caption h1").html('' + imgTitle + '');
$(".caption small").html('Uploaded by ' + userName + '');
$(".caption").fadeIn();
});
// update counter
$(".counter").fadeOut(400,function() { $(".counter").text(parseInt($('.photos li.active .photo').attr('rel'))+1).fadeIn(); });
// call image view recording function
$.get(basepath + "image/" + id + "/record/human");
// loading routine completed
loading = false;
}
There is a lot of stuff in there that is not relevant. At the end you can see I am doing the $.get call. The problem is that it is triggered in very strange ways. The first time I navigate to a tumb, it is called once. The next time it is triggered twice. After that, it is triggered 2 or 3 times per navigation action, usually 3.
I figured it must be that my events return multiple elements and therefore call the loadimage routine multiple times. So I placed log statements in both the events and the loadimage routine. It turns out loadimage is called correctly, only once per click.
This means that it seems that the $.get is doing this within the context of a single call. I'm stunned.

Your problem may be:.imagesLoaded is a jQuery plug in that runs through all images on the page. If you want to attach a load event to the imagePreloader only, use
$(imagePreloader).load(function() {
...
}
Otherwise, please provide the code where you call the loadImage() function.
Update:
when clicking on a thumb That is the problem. $(".photos li a").live('click',... should only be called once on page load. Adding a click handler every time a thumb is clicked will not remove the previous handlers.
Another option is to change the code to $(".photos li a").unbind('click').live('click', ... which will remove the previously registered click handlers.

Related

JqGrid BeforeShow event of add dialog variables reset

I call the following function before the add dialog is shown; after clicking [+] on the JqGrid.
MVC Controller grid configuration
ordersGrid.ClientSideEvents.BeforeAddDialogShown = "initAddDialog";
The function makes an Ajax call to create a new order record either with or without a linking id, dependent on whether an existing order was selected when the [+] button was clicked.
The purpose is to make available the id necessary to make another Ajax call to retrieve additional linked information from another service, and to pre-populate the new record with date/time information and (where applicable) common information from an existing record.
function initAddDialog() {
var newOrderId = 0;
var newOrderLinkId = 0;
var selRow = jQuery('#clientOrderGrid').jqGrid('getGridParam', 'selrow');
var selRowData = jQuery('#clientOrderGrid').jqGrid('getRowData', selRow);
Get linking ID from selected row (if any)
var curOrderLinkId = (selRowData.OrderLinkId == null) ? 0 : selRowData.OrderLinkId;
Ajax call to create new 'Holding' Order
$.ajax({
url: '/Order/ajaxNewOrder?OrderLinkId=' + curOrderLinkId,
success: function (newOrderResponse) {
arr = newOrderResponse.split("|");
newOrderId = arr[0];
newOrderLinkId = arr[1];
},
error: function () { alert("There was an error creating an Order record"); }
});
If I break the code here using Firebug in Firefox, I can see that the variables newOrderId and newOrderLinkId have been set correctly with the id's from the newly created record, and if I hit F8 the (already displayed) dialog is populated with these //values.
If I don't break the code the dialog is displayed, but displays the values with which the variables were initialised i.e. newOrderId = 0, newOrderLinkId = 0.
$('#' + 'OrderId').val(newOrderId);
$('#' + 'OrderLinkId').val(newOrderLinkId);
$('#' + 'Stock').val(stock);
$('#' + 'SettlesTs').val(settlesTs);
$('#' + 'ReceivedTs').val(dtThis);
$('#' + 'ReceivedHHmm').val(dtTime);
I've tried calling the same function after the add dialog is shown, but get the same results.
Any thoughts as to why this is, or is there a better way of achieving the same result?
Thanks
I have taken the native add/edit dialog out of the equation and am using my own 'add' form along with the native inline editing of JqGrid. I'm sure with more research it would have been possible to find a solution, but with deadlines looming I had to find a workaround.

jQuery Drag-and-Drop Image Upload Functionality

I am trying to code my own simple AJAX image upload script via jQuery. I have found some plugins but they are way too customized for what's needed, and I cannot get any of them working properly.
I just want to somehow detect when the user drags and drops an image onto the page. From there I'm sure it's not hard to upload that data and move into a /cache/ directory and allow for further options..
but right now I'm totally stuck with the drag/drop functionality. Literally no idea how I should approach this. What kind of event handler is needed? Will I need to custom code my own event handler? Any advice would be more than appreciated
What kind of event handler is needed?
Drag'n'drop requires a HTML5 browser - but that's pretty much all of them now.
I'd recommend not starting from scratch as there's quite a bit of code needed - I quite like this wrapper that implements it as a jQuery plugin.
http://www.github.com/weixiyen/jquery-filedrop
After defining an element in the document with class div, you can initialise it to accept dropped files with:
function fileSetUploadPercent(percent, divID){
var uploadString = "Uploaded " + percent + " %";
$('#'.divID).text(uploadString);
}
function fileUploadStarted(index, file, files_count){
var divID = getDivID(index, file);
createFileUploadDiv(divID); //create the div that will hold the upload status
fileSetUploadPercent(0, divID); //set the upload status to be 0
}
function fileUploadUpdate(index, file, currentProgress){
//Logger.log("fileUploadUpdate(index, file, currentProgress)");
var string = "index = " + index + " Uploading file " + file.fileName + " size is " + file.fileSize + " Progress = " + currentProgress;
$('#status').text(string);
var divID = getDivID(index, file);
fileSetUploadPercent(currentProgress, divID);
}
function fileUploadFinished(index, file, json, timeDiff){
var divID = getDivID(index, file);
fileSetUploadPercent(100, divID);
if(json.status == "OK"){
createThumbnailDiv(index, file, json.url, json.thumbnailURL);
}
}
function fileDocOver(event){
$('#fileDropTarget').css('border', '2px dashed #000000').text("Drop files here");
}
$(".fileDrop").filedrop({
fallback_id: 'fallbackFileDrop',
url: '/api/upload.php',
// refresh: 1000,
paramname: 'fileUpload',
// maxfiles: 25, // Ignored if queuefiles is set > 0
maxfilesize: 4, // MB file size limit
// queuefiles: 0, // Max files before queueing (for large volume uploads)
// queuewait: 200, // Queue wait time if full
// data: {},
// headers: {},
// drop: empty,
// dragEnter: empty,
// dragOver: empty,
// dragLeave: empty,
// docEnter: empty,
docOver: fileDocOver,
// docLeave: fileDocLeave,
// beforeEach: empty,
// afterAll: empty,
// rename: empty,
// error: function(err, file, i) {
// alert(err);
// },
uploadStarted: fileUploadStarted,
uploadFinished: fileUploadFinished,
progressUpdated: fileUploadUpdate,
// speedUpdated
});
The bit of the web page that accepts uploads has this HTML.
<div class='fileDrop'>
Upload a file by dragging it.
<span id='fileDropTarget'/>
</div>
The file drop works on the outer <div> but it's nice to make a nice big target that says 'DROP HERE' so that users aren't confused about where they need to drop the file.
Probably too late. But you should checkout http://www.dropzonejs.com/

jQuery — a .live() > each() >.load.() finella

EDIT - URL to see the issue http://syndex.me
I am dynamically resizing images bigger than the browser to equal the size of the browser.
This was no easy feat as we had to wait for the images to load first in order to check first if the image was bigger than the window.
We got to this stage (which works):
var maxxxHeight = $(window).height();
$(".theImage").children('img').each(function() {
$(this).load( function() { // only if images can be loaded dynamically
handleImageLoad(this);
});
handleImageLoad(this);
});
function handleImageLoad(img)
{
var $img = $(img), // declare local and cache jQuery for the argument
myHeight = $img.height();
if ( myHeight > maxxxHeight ){
$img.height(maxxxHeight);
$img.next().text("Browser " + maxxxHeight + " image height " + myHeight);
};
}
The thing is, the page is an infinite scroll (I'm using this)
I know that you are not able to attach 'live' to 'each' as 'live' deals with events, and 'each' is not an event.
I've looked at things like the livequery plugin and using the ajaxComplete function.
With livequery i changed
$(".theImage").children('img').each(function() {
to
$(".theImage").children('img').livequery(function(){
But that didnt work.
ajaxComplete seemed to do nothing so i'm guessing the inifinte scroll i'm using is not ajax based. (surely it is though?)
Thanks
Use delegate:
$(".theImage").delegate('img', function() {
$(this).load( function() { // only if images can be loaded dynamically
handleImageLoad(this);
});
handleImageLoad(this);
});
The problem is that your infinite scroll plugin does not provide the callback functionality. Once your pictures are loaded there is no way to affect them.
I have tried to modify your plugin, so that it will serve your needs, please see http://jsfiddle.net/R8yLZ/
Scroll down the JS section till you see a bunch of comments.
This looks really complicated, and I probably don't get it at all, but I'll try anyway :-)
$("img", ".theImage").bind("load", function() {
var winH = $(window).height();
var imgH = $(this).height();
if (winH < imgH) {
$(this).height(winH);
$(this).next().text("Browser " + winH + " image height " + imgH);
}
});

What to do when users outrun ajax

My program does an ajax call when the user clicks on a radio button. Upon success, the background color of the table cell containing the radio button is changed to let the user know their selection has been posted to the database.
The problem is sometimes the background doesn't change. I'm trapping for errors, so I don't think it's because of an error. I'm wondering if the user is outpacing the success callback.
var setup = {};
setup.url = 'Gateway.cfc';
setup.type= 'POST'
setup.dataType='json';
$.ajaxSetup(setup);
var settings = {};
settings.data = {};
settings.data.method = 'Save';
settings.data.AssignmentID = $('input[name=AssignmentID]').val();
settings.error = function(xhr, ajaxOptions, thrownError) {
$('#msgErr').text(thrownError);
};
settings.success = function(result) {
$('#msg').empty();
$('#msgErr').empty();
if (result.RTN) { // uppercase RTN
$('#' + settings.data.AnswerID).addClass('answer');
} else {
$('#' + settings.data.AnswerID).next().append('<span class="err"> ' + result.MSG + '</span>');
}
}
$('input').filter(':radio').change(function() {
var myName = $(this).attr('name');
$('input[name=' + myName + ']').closest('td').removeClass('answer');
settings.data.AnswerID = $(this).val();
$.ajax(settings);
});
There is a delay between your Ajax post to the server and the ui element update on your screen. I do not know which Ajax library you are using, but you could plug into the Ajax framework and display a floating div element that covers the whole screen. This div could have other elements like an image or other divs, spans, p tags, etc. This is also called a dialog in some libraries.
I would recommend trying to find the before_Ajax_send and after_Ajax_receive functions in your Ajax library and attaching your functions to these events. The before_send function should display the floating div and the after_receive should close the div.
Hope this helps.
Gonna post this as an answer, on the off-chance that it does the trick :)
$('input').filter(':radio').change(function() {
$(this).closest('td').removeClass('answer');
var mySettings = $.extend(true, {data:{AnswerID: $(this).val()}}, settings);
$.ajax(mySettings);
});
This will make sure there are no race conditions with your settings if calls are made in quick succession.

Livequery fires click no matter where the user clicks in the document

I have replaced the traditional select/option form elements with a nifty little popup window when a triggering image is clicked. The page is for accounting purposes and so multiple line items are to be expected. I've written the javascript that will dynamically generate new line item select/option elements. When the page loads, the initial set of choices loads and the user can click on them, get a pop up with some choices, choose one and then the box closes. The move to the next choice and so on and so forth. I've added livequery to my code for those dynamic elements. However... the livequery("click"...) seems to fire no matter where the user clicks on the page. Very frustrating.
I've read on here how great "live()" is in jQuery 1.3, but I am not able to upgrade fully to jquery 1.3 because a custom JS file depends on 1.2, so using live() is out of the question, however I have invoked the livequery() plugin and I really need to understand if I'm using it correctly.
I will post partial code. There's just way too much to post all of it.
Basically, I'm searching for divs starting with "bubble" and then a number afterwards. Then run the event on each them. Only bubble1 is static, 2 and up are dynamic. Am I missing the whole usage of livequery?
>$jb('div[id^="bubble"]').each(function () {
> var divid = $jb('div[id^="bubble"]').filter(":first").attr("id");
>var pref = "bubble";
>var i = divid.substring((pref.length));
>var trigger = $jb('#trigger' + i, this);
>var popup = $jb('#pop'+ i, this).css('opacity', 0);
>var selectedoption = $jb('selectedOption' + i, this);
>var selectedtext = $jb('selectedOptionText' + i, this);
>$jb([trigger.get(0), popup.get(0)]).livequery("click",
> function () {
>//alert(i);
// code removed for brevity (just the contents of the popups)
>});
Live works by using event delegation. A click event is attached to the body, and anytime something is clicked the selector is tested against the target. If it passes the selector test it calls the function (thus simulating a click event).
You probably want something like this:
$('div[id^="bubble"]').livequery("click", function() {
var divId = $(this).attr("id");
var i = divId.substring("bubble".length);
var trigger = $("#trigger" + i, this);
var popup = $("#pop" + i, this).css("opacity", 0);
// alert(i);
}

Resources