views:

46

answers:

1

I am having a problem checking if a file exists using $.ajax(). I am looping through a json file with $.each and I want to see if the specified staff member has an image, and if not use the no_photo.jpg image. I keep getting the no_photo.jpg image even though there is the staff member's image in the directory.

Here is the entire $.getJSON() call.

$.getJSON('staff.json', function(data) {
                var last_check;
                var image_url = "no_photo";
              $.each(data.employees, function(i,employee){
                if ((i+1)%4==0) {last_check = " last";} else {last_check = "";}
                $.ajax({
                    url:'/images/staff/' + employee.first_name.toLowerCase() + employee.last_name.toLowerCase() + '.jpg',
                    type:'HEAD',
                    error:
                        function(){
                            image_url = "no_photo";
                        },
                    success:
                        function(){
                            image_url = employee.first_name.toLowerCase() + employee.last_name.toLowerCase();
                        }
                });
                $("div.staff-members").append('<a href="#" title="' + employee.first_name + ' ' + employee.last_name + ', ' + employee.title + '" rel="' + employee.location + '" class="' + employee.category + last_check + '"><img src="/images/staff/' + image_url + '.jpg"><span class="' + employee.category + '"></span></a>');
              });
            });
+3  A: 

I'd strongly recommend not to use jQuerys .ajax() (or any other XHR) method for that purpose. Use Javascripts Image object instead.

var testimg = new Image();
testimg.onload = function(){
    if(this.width > 0)
       image_url = this.src;
    else
       image_url = "no_photo";

    $("div.staff-members").append('<a href="#" title="' + employee.first_name + ' ' + employee.last_name + ', ' + employee.title + '" rel="' + employee.location + '" class="' + employee.category + last_check + '"><img src="/images/staff/' + image_url + '.jpg"><span class="' + employee.category + '"></span></a>');
};
testimg.onerror = function(){
    image_url = "no_photo";
    $("div.staff-members").append('<a href="#" title="' + employee.first_name + ' ' + employee.last_name + ', ' + employee.title + '" rel="' + employee.location + '" class="' + employee.category + last_check + '"><img src="/images/staff/' + image_url + '.jpg"><span class="' + employee.category + '"></span></a>');
};
testimg.src = '/images/staff/' + employee.first_name.toLowerCase() + employee.last_name.toLowerCase() + '.jpg';

This has less overhead than an Ajax request.

update

moved the .src = instruction to the bottom (msie requires this, credits to Nick Craver)

Since this approach uses asynchronous callbacks (as does .ajax()), you need to call your .append() within the event handlers.

jAndy
You would need to change your order around here, attaching an `onload` handler *after* setting the `src` won't fire your handler in many cases, as the event already occurred when it comes from cache.
Nick Craver
@Nick: actually, no you don't have to do that. Well at least I never had a problem by using this order, cache or not. Can you give a usecase for your statement?
jAndy
@jAndy - Sure, you can see a simple test here, try it in IE, even IE8: http://jsfiddle.net/nick_craver/qNFxq/ after the first load you won't get an alert...move the `.src` *after* the `onload` and you'll consistently get the alert :)
Nick Craver
jAndy
@jAndy - Another thing is your answer doesn't address the async issue, `image_url` will still be `"no_photo" every time with your answer, it needs to actually call the append when the load or error happens :)
Nick Craver
@Nick: I didn't mention a lot since I was only suggesting a (IMO) better way to accomplish that task :)
jAndy
@jAndy - Oh I realize that, I deleted b/c I agree this is a much better approach, but without mentioning that the `image_url` is `"no_photo" because no success or error function sets it...well the OP's back to the original problem the current question has :)
Nick Craver
@Nick: fair enough, convinced.
jAndy
+1 - Much better approach :)
Nick Craver