Reputation:
I have searched every where and I've been working on this for hours. Basically, I have an Ajax call fetching data from a webpage that fetches data from a database. This code is for a slideshow for a gallery of images. The entire function is shown below, however the part that is not working properly is the two lines of code that gets the height and the width of the images.
The images are being fetched properly, and they are displayed fine (well not really, but they show up). The lines that are querying the images' width and height, return 0 most of the time. There's about a 5% chance that they return the correct values. This causes the if statement directly afterwards to always evaluate to false, which makes wide images extend past the edge of the webpage.
This problem is only present in Webkit based browsers. Gecko based browsers do not have this issue.
I think the problem is that jQuery is trying to query the images before the Ajax call has finished its request. Is there any way to make jQuery wait for Ajax to be finished with its request?
function LoadForm() {
GalleryDataSource = new kendo.data.DataSource({
transport: {
read: {
url: BaseAPI + "/PhotosByAlbum2",
dataType: "json",
data: { "location": locationID, "ID": $.getQuery('ID') }
}
}
});
$("#slides").kendoListView({
dataSource: GalleryDataSource,
template: kendo.template($("#SlidesTemplate").html())
});
$.ajax({
type: "Get",
contentType: "application/json; charset=utf-8",
url: BaseAPI + "/PhotosByAlbum2",
datatype: "json",
data: { "location": locationID, "ID": $.getQuery('ID') },
success: function (d) {
for (var i = 0; i < d.length; i++) {
$('#Show').append(
'<figure><img src="' + d[i].Path +
'" id="' + d[i].ID +
'"/><figcaption>Title: ' + d[i].Title + '<br />' +
'Description: ' + d[i].Description +
'</figcaption></figure>'
);
/*these do*/ var imgheight = $("#" + d[i].ID).height();
/*not work*/ var imgwidth = $("#" + d[i].ID).width();
if (imgheight < "768" && imgwidth > imgheight) {
$("#" + d[i].ID).addClass("wideimage");
} else {
$("#" + d[i].ID).addClass("tallimage");
}
}
$('#Show').innerfade({
animationtype: 'fade',
speed: 1050,
timeout: 2000,
type: 'sequence',
containerheight: '500px'
});
}
});
$('#back').click(function () {
window.location = 'Photos.aspx'
});
}
Note: I've tried using $.when(*ajax call here*).done(function() {*do stuff*});
. It behaved the exact same way.
And I've tried setting the async
option to false. Same behavior.
I've also tried adding a complete
event handler in the Ajax call. Again, it behaved the same way.
Upvotes: 1
Views: 898
Reputation: 707158
As I've said in my comments, you have to wait for the images to load before you can reliably obtain their width and set the class you want on them.
Here's a way to restructure your ajax call to only process the images once they have been loaded and to only start the animation once the images have all been loaded and tagged appropriately:
$.ajax({
type: "Get",
contentType: "application/json; charset=utf-8",
url: BaseAPI + "/PhotosByAlbum2",
datatype: "json",
data: { "location": locationID, "ID": $.getQuery('ID') },
success: function (d) {
var imagesRemaining = d.length;
for (var i = 0; i < d.length; i++) {
var img = new Image();
img.src = d[i].Path;
img.id = d[i].ID;
img.onload = function() {
--imagesRemaining;
var item = $(this);
var imgheight = item.height();
var imgwidth = item.width();
if (imgheight < 768 && imgwidth > imgheight) {
item.addClass("wideimage");
} else {
item.addClass("tallimage");
}
// now see if all images are loaded now
// so all classes are set so we can now start the animation
if (imagesRemaining === 0) {
$('#Show').innerfade({
animationtype: 'fade',
speed: 1050,
timeout: 2000,
type: 'sequence',
containerheight: '500px'
});
}
};
$("<figure>").append(img).append('<figcaption>Title: ' + d[i].Title + '<br />' +
'Description: ' + d[i].Description + '</figcaption>').appendTo("#Show");
}
}
});
Upvotes: 0
Reputation: 392
I did this ... of course, there could be a better way...
In the php script that runs at BaseAPI + "/PhotosByAlbum2" ... get each image's width and height, resize the images to the correct height and width for the slideshow, if needed, and then put those variables in the results array with Path, Title and Description ...
On the jQuery... read the array and adjust the width and height in your html...
Upvotes: 0
Reputation: 27012
As stated in the comments, you can't access an image's height and width until it has been loaded. I would do something like this to listen for the load event:
$.each(d, function (idx, item) {
$fig = $('<figure/>');
$('<figcaption/>')
.html('Title: ' + item.Title + '<br />Description: ' + item.Description)
.appendTo($fig);
$('<img/>')
.load(function () {
var $this = $(this);
var height = $this.height();
var width = $this.width();
if (height < "768" && width > height) {
$this.addClass('wideimage');
} else {
$this.addClass('tallimage');
}
}).attr('id', item.ID)
.attr('src', item.Path)
.appendTo($fig);
$fig.appendTo('#Show');
});
Upvotes: 1