bootstrap 3 - need to preload images for a bootstrap modal carousel

phillystyle123
phillystyle123 used Ask the Experts™
on
Go here: http://ikonltd.com/artists/baldessari/

Click on any of the thumbs and the modal carousel will pop up. The issue is that sometimes it is not populated with the image and the caption. Sometimes it is. It seems to be a preload issue, but every preload script I've tried doesn't work. Then, I got into lazy load, but that doesn't do the trick either.

My carousel images are dynamically generated and sometimes there can be 25 per page. So, I need to ensure that everytime my modal carousel opens, it will be populated with the corresponding image and caption.

I'm currently not preloading on the page example. But I am attempting to use lazy load. Here's my modal, carousel & lazy load scripts (which I have at the bottom of the code)

<script type="text/javascript">
 /* copy loaded thumbnails into carousel */
$('.row .thumbnail').click(function(e){
  
}).each(function(i) {
  if(this.complete) {
  	var item = $('<div class="item lazy-load"></div>');
    var itemDiv = $(this).parents('div');
    var title = $(this).parent('a').attr("title");
    
    item.attr("title",title);
  	$(itemDiv.html()).appendTo(item);
  	item.appendTo('.carousel-inner'); 
    if (i==0){ // set first item active
     item.addClass('active');
    }
  }
});

/* activate the carousel */
$('#modalCarousel').carousel({interval:false});

/* change modal title when slide changes */
$('#modalCarousel').on('slid.bs.carousel', function () {
  $('.modal-title').html($(this).find('.active').attr("title"));
})

/* when clicking a thumbnail */
$('.row .thumbnail').click(function(){
    var idx = $(this).parents('div').index();
  	var id = parseInt(idx);
  	$('#myModal').modal('show'); // show the modal
    $('#modalCarousel').carousel(id); // slide carousel to selected
  	
});

    </script>
    
<script type="text/javascript">
jQuery(window).load(function() { // wait for complete page loading with image
     jQuery('.carousel').find('img').not(":first").each(function(i, v) { // for each image inside the carousel (the element with .carousel class)
          var src = jQuery(this).attr("src"); // put the src value for each image in variable
          //alert(src);  remove this line if the script work fine 
          jQuery(this).attr("data-lazy-load-src", src); // put this src value inside data-src
          jQuery(this).removeAttr("src"); // remove the src attribute
     });
});

  </script>    
  


      <script type="text/javascript">
$(document).ready(function() {
$(".swipeThis").swiperight(function() {
$(this).carousel('prev');
});
$(".swipeThis").swipeleft(function() {
$(this).carousel('next');
});
});
</script> 

  <script type="text/javascript">
var cHeight = 0;

$('#modalCarousel').on('slide.bs.carousel', function (e) {
        var $nextImage = null;

        $activeItem = $('.active.item', this);

        if (e.direction == 'left'){
            $nextImage = $activeItem.next('.item').find('img');
        } else {
			if ($activeItem.index() == 0){
                $nextImage = $('img:last', $activeItem.parent());
            } else {
                $nextImage = $activeItem.prev('.item').find('img');
            }
	    }

        // prevents the slide decrease in height
        if (cHeight == 0) {
           cHeight = $(this).height();
           $activeItem.next('.item').height(cHeight);
        }

        // prevents the loaded image if it is already loaded
        var src = $nextImage.data('lazy-load-src');
        
        if (typeof src !== "undefined" && src != "") {
           $nextImage.attr('src', src)
           $nextImage.data('lazy-load-src', '');
        }
    });
</script>

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
added a jquery preload script to this as well. So, even after the images are preloaded, they don't show up sometimes in the bootstrap modal carousel
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
Did we not solve this in this post http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_28682375.html?

You still have this in your script
 if(this.complete) {

Open in new window

When that loop executes - if the image has not completed loading it is going to skip it - you need to remove the .complete - it is not necessary. The image does not have to be loaded to add the <img> tag to the carousel. They will show once the images have loaded.

A bit confused why the question seems to have gone backwards?

Author

Commented:
When I remove that line random images load in the carousel
Ensure you’re charging the right price for your IT

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Just for fun can you post your code with the row removed.

When I remove that line random images load in the carousel
Yup got that - but if we can't see it is very difficult to diagnose it.

To get to the bottom of this quickly either we need a link to the code or the missing stylesheets, preferably the former because we cannot guarantee the presence of the style sheet will cause the problem to manifest itself.

As I mentioned in my earlier post - your posted code does not appear to demonstrate the problem when that line is removed.

Author

Commented:
This has the proload script and the carousel script without

 if(this.complete) {

http://ikonltd.com/artists/preload-test.html
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
Have you noticed with that code everything is getting loaded twice?

$('.row .thumbnail').each(function(i) {

Open in new window


If you look in the code you will see that .thumbnail is declared on two different elements inside each row - so you are going to end up adding the item twice.

This sort of explains what is happening. The .complete was there to check for images. When .each()'ing through the .row .thumbnails you are going to find an <img class="thumbnail"> and an <a class="thumbnail"> for each .row. To avoid adding each thumb twice you use the this.complete which will be true if the element is an image AND the image has finished downloading - effectively filtering out the <a> elements.

Unfortunately, if the image is still in the process of downloading .complete will be false and it will skip the image altogether.

The fix is simple - just add the img to the .thumbnail selector like this
	$('.row img.thumbnail').each(function(i) {
		var item = $('<div class="item"></div>');
		var itemDiv = $(this).parents('div');
		var title = $(this).parent('a').attr("title");
	
		item.attr("title",title);
		$(itemDiv.html()).appendTo(item);
		item.appendTo('.carousel-inner'); 
		if (i==0) { // set first item active
			item.addClass('active');
		}
	});

Open in new window

Author

Commented:
Oh, yes. This seems to be working!

Any thoughts on getting those captions to load too? Sometimes, after the page first loads, the image will populate the carousel but not the caption.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Will have to pick this up a bit later but shouldn't be too difficult.

Author

Commented:
thanks julianH -

Author

Commented:
Something i noticed related to the caption loading.

After a gallery loads, if you click on the first thumb first, the caption won't load. Clicking on any other thumb, the image and caption load seamlessly. If you click on any other thumb before you click the first thumb, then click the first thumb, the caption for that first thumb will load.

Author

Commented:
click on any of these exhibitions to see what i mean:

http://ikonltd.com/past/
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
What is happening is that when you load the modal you don't load the title. This is loaded in the on-slide event handler which is only called when you click one of the slide handles - as soon as you do that the title is populated. So all you need to do is put the loading of the title in the onclick
$('#modalCarousel').on('slid.bs.carousel', function () {
  $('.modal-title').html($(this).find('.active').attr("title")); /* <== THIS .... */
})

/* when clicking a thumbnail */
$('.row .thumbnail').click(function(){
    var idx = $(this).parents('div').index();
  	var id = parseInt(idx);
        $('.modal-title').html($(this).find('.active').attr("title")); /* <== ADDED HERE */
  	$('#myModal').modal('show'); // show the modal
    $('#modalCarousel').carousel(id); // slide carousel to selected
});

Open in new window

Author

Commented:
I see what you did. I added the line:

$('.modal-title').html($(this).find('.active').attr("title"));

to the  /* when clicking thumbnail */ section, but I'm still not loading the title/caption when I click the first thumb. I have to click another thumb (which displays perfectly in the modal -caption and image), close that modal, then click on the first thumb again to get the title/caption.
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
The problem is caused by the fact that the .title is loaded when the carousel changes slides but is not initialised when it is created.

The fix I posted uses $(this) which is relative to the carousel - so that won't work but should work with this slight modification
$('#modalCarousel').on('slid.bs.carousel', function () {
  $('.modal-title').html($(this).find('.active').attr("title")); /* <== THIS .... */
})

/* when clicking a thumbnail */
$('.row .thumbnail').click(function(){
    var idx = $(this).parents('div').index();
  	var id = parseInt(idx);
        $('.modal-title').html($('.carousel-inner .active').attr("title")); /* <== CHANGED */
  	$('#myModal').modal('show'); // show the modal
    $('#modalCarousel').carousel(id); // slide carousel to selected
});

Open in new window

What we are saying here is when the thumbnail is clicked get the title attr of the active item of the carousel and set this to the modal title.

Author

Commented:
I believe this is working! I added a single quote before .carousel-inner:

$('.modal-title').html($('.carousel-inner .active').attr("title")); /* <== CHANGED */

I will dbl check and mark the question answered. I can't thank you enough for your patience and expertise.

Much appreciated.
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
I have updated the code snippet to correct the error.

Author

Commented:
Thanks again for all your help, JulianH! I had just about given up on this - it's hard to believe it's working seamlessly!
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
You are most welcome - good luck with your project.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial