I am selecting an image as part of a html form. Once selected, jQuery assigns a user-defined attribute of the image to a hidden form variable and passes it to form handler. Neat.

Problem is when I dynamically add images that can be selected. I am using live function to ensure that the dynamically added image is highlighted when clicked - but the user-defined attribute is not being grabbed by jQuery.

I think that when the page is first loaded, all the existing image attributes are loaded into the DOM, but when extra images are added with ajax, the DOM doesn't have the new attribute values, despite them appearing in the html on the page. I don't think I can use the live function in this instance, because an attribute is not an event. Out of ideas now. Anyone help?

HTML/PHP, with jQuery:

echo anchor_popup('gallery/addphoto', 'Add new image (opens in new window) »', $atts);?>
</p>		
						
<?if (!empty($images)) {?>											
<p class="smaller">
<?echo form_label('Image:', 'person_img');?>
<span id="new_image"></span>
<?$default = set_value('person_img', (isset($person_img)) ? $person_img : '');?>
<?$options = array();
	foreach ($images as $key => $row):?>
			<span><img src="img/thumbs/<?=$row['image_name']?>" alt="<?=$row['image_title']?>" image_id_val="<?=$row['image_name']?>" <?echo ($default == $row['image_name']) ? 'class="highlighted"' : 'class="faded"';?>></span>&nbsp;   								
				<?endforeach;?>
<input type="hidden" id="person_img" name="person_img" value="<?=$default?>">
</p>
<?} else {?>
<p class="small">Sorry - no images have been uploaded yet</p>
<?}?>
<script>
// highlighting images in forms function
$(document).ready(function(){

	loopimages();
	
});

function loopimages() {
	// Image selection highlighting
	$('img.faded').live('click', function() {
	
    // Set the form value
    $('#person_img').val($(this).attr('image_id_val'));

    // Unhighlight all the images
    $('form img').removeClass('highlighted').addClass('faded');

    // Highlight the newly selected image
    $(this).addClass('highlighted').removeClass('faded');
	});

// Image de-selection highlighting
$('img.highlighted').live('click', function() {

    // Set the form value
    $('#person_img').val('');

    // Unhighlight all the images
    $('form img').removeClass('highlighted').addClass('faded');
	});
	
	// Get precise time on server
          	$('#img_popup').click(function() {
		// Only call the ajax polling loop function if nothing in the new image span - i.e. first time of asking only to avoid multiple threads running and multiple images appearing if uploading lots of photos
		if ($('#new_image').html().length == 0)
		{
				do_image();
		}
	});
}

function do_image() {
$.ajax({
  url: "<?= site_url('ajax/time_now') ?>",
  success: function(unix)
	{
		setTimeout( function()
              	{
            		$.ajax({
				type: "POST",
				url: "<?= site_url('ajax/image_check') ?>",
				data: "unix=" + unix,
				success: function(html)
				{
					$(html).prependTo("#new_image");
            // Set the form value
            $('#person_img').val($(this).attr('image_id_val'));
        
            // Unhighlight all the images - unhighlights selected image on re-pass so commented out for now!
            // $('form img').removeClass('highlighted').addClass('faded');
        
            // Highlight the newly selected image
            $(this).addClass('highlighted').removeClass('faded');
			}
			});
		do_image();
		}, 3000);
  }
});
}
</script>

AJAX Scripts:

function time_now()
	{
		$this->db->select_max('image_last_updated');
			$query = $this->db->get('images');
      if ($query->num_rows() > 0)
      {
  		 	$result = $query->result_array();
				$last_image_time = $result[0]['image_last_updated'];
				echo $last_image_time;
			}
	}

	
	function image_check()
	{
		$html = '';
		$unix = $this->input->post('unix');
		$this->db->where('image_last_updated >', $unix);
		$query = $this->db->get('images');
    if ($query->num_rows() > 0)
    {
		 	$result = $query->result_array();
  		foreach ($result as $row)
			{
				$html .= '<img class="faded" image_id_val="' . $row['image_name'] . '" alt="' . $row['image_title'] . '" src="img/thumbs/' . $row['image_name'] . '">';
  		}
  	}
		echo $html;
	}

Recommended Answers

All 6 Replies

tK,

I'm in guesswork territory here.........

I think I'm right in saying that $('img.faded').live('click', ... and $('img.highlighted').live('click', ... will only keep up with matching elements at the time they are inserted, not when their highlighted/faded classnames are changed.

If so then the workaround would be to put in place a general .live handler for all relevant images and to test/branch within that handler to cater for highlighted/faded cases.

Airshow

Thanks, Airshow, for having a stab. As it is, the highlighting and fading is working perfectly, for the images that the ajax script inserts as well as the images that are there from the start. All good on that front. But when the image is highlighted, the script should also place the value of image_id_val into the hidden form variable for submission. This happens for pre-existing images, but not for new ones.

Maybe I included too much detail! Here is revised script, just focusing on real issue at hand. I really can't see a way round this. If anyone has any ideas, please let me know...

///////////////////////////////////////////////////////////////////////
// HTML generated by PHP

// Span into which jquery puts uploaded images
<span id="new_image"></span>

// Display all existing images
foreach ($images as $key => $row):?>

<span><img
src="img/thumbs/<?=$row['image_name']?>"
image_id_val="<?=$row['image_name']?>"
class="faded|highlighted">
</span>

<?endforeach;?>

// Hidden form input that will pass image_id_val when an image is selected.  The value is set using jQuery
<input type="hidden" id="person_img" name="person_img" value="">


///////////////////////////////////////////////////////////////////////////
// Onto jQuery magic...
<script>

$(document).ready(function(){

// When an image is clicked, do something - using live function so that newly uploaded images wil also trigger this function...

$('img.faded').live('click', function() {

//////////////////////////////////////////////////////////////////////////
//////////////           THIS IS PROBLEM BIT!      ///////////////////////
// Set the form value - this is what doesn't get set for newly uploaded images - so nothing submitted to form, and exercise of selecting image pointless!

$('#person_img').val($(this).attr('image_id_val'));

////////////////////////////////////////////////////////////////////////// 

// Unhighlight all the images
$('form img').removeClass('highlighted').addClass('faded');
// Highlight the newly selected image
$(this).addClass('highlighted').removeClass('faded');
});
 

// If user clicks to add a new image, start waiting for images to appear, using ajax polling...
$('#img_popup').click(function() {

  if (new image exists)
  {
    // Using ajax post request, get html for new img in correct form:
    html = '<img
src="img/thumbs/<?=$row['image_name']?>"
image_id_val="<?=$row['image_name']?>"
class="highlighted">';

    // Display new image in span - this works fine
    $(html).prependTo("#new_image");

    // Set the form value - this is the problem...
    $('#person_img').val($(this).attr('image_id_val'));

    // Do some messing about with highlighted and faded classes with images on page - all working as it should
    // ...
  }
});

});

</script>

It seems like the DOM has the values of image_id_val for all the pre-existing images but not for dynamically added ones. I think the live function just works for events, not attributes, so I don't think the solution lies that way. if it does, I'd love for someone to show me how.

When I try to get the value with val($(this).attr('image_id_val')), it's just not there for new images. There must be a way to make this work, but I can't see it...

tK,

OK, I understand a bit more now.

You are sort of right in saying that .live() just works for events, in that .live() is a variant of .bind() which (in simple terms) attaches a handler (function) to an event. However when the event fires, the attached handler will then have access to all the target element's (this's) attributes, as was your original assumption when you wrote the code. Therefore what you want to achieve should be eminently possible.

As far as I can see, your javascript for reading the custom attribute is correct. If the handler put in place with .live() fires, as you say, then it should cope with dynamically inserted images exactly the same as hard-coded images.

From the symptoms, it seems most likely that dynamically created images are not being correctly formed, in particular that the custom image_id_val attribute is not being put in place.

With Opera's Dragonfly plugin, you can use right-click > inspect element to see the current state of the DOM (not just the HTML with which it was initialised as with View Source). I think FF's Firebug does much the same.

What does it indicate?

Airshow

commented: Patient and helpful advice from airshow on subtle problem. Really helpful. +1

Airshow, thank you. I checked out DOM using Firebug, as you suggested. Surprised to find that the image_id_val was all present and correct for newly added images just as for existing images.

So, I looked in the DOM at the form element for the hidden form value, and discovered the root of the problem. When an image is selected, the value of image_id_val is indeed passed to the hidden form element - BUT after a second or two it is replaced with an empty string.

So, it must be the ajax polling process that is triggered by the add new image button that is then resetting the value for ANY of the images that are selected. Well, mystery solved. Now just need to debug my polling script. Will let you know how I get on. I'm away for a couple of days now, so hopefully get to it on Friday.

Thanks again for the pointers. Appreciate it. :)

The bug is on line 75 of the original code I posted. The code within the success brackets is being executed every time the script is called, which is every 3 seconds with the settimeout function. When the ajax call doesn't produce any html, nothing is added to the image span, but the hidden form value is updated to nothing.

I had even noticed this behaviour and commented out the line that highlighted the new image because it was being unhighlighted. Should have noticed this. Sorry. All I need to do is enclose the highlighting and assigning of the image value in a conditional statement about the length of the html variable returned by the ajax request. problem solved, and fully functional as required.

Pesky. Thanks for your help.

:cool:

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.