0

I'm new to JavaScript and pulling my hair out over this...

A demo of the problem is here: http://codepen.io/sol_b/pen/PzgdWy

And this is the script:

var sections = function() {
  $('.image').each(function() {
    var $this = $(this),
        x = $this.find('img').width()
    $this.width(x);
  });
};

$(document).ready(function() { 
  sections();
 });

$(window).resize(function() {
  sections();
})

The width of an image is calculated and assigned to the image's container. The idea is that the row of images will always maintain their aspect ratio, without gaps between the containers.

The problem is the code fails about 50% of the time and the images just squish together. Resizing the window fixes it so I think it's something to do with the loading sequence.

I've tried using window.onload and img.onload instead of document.ready, and these didn't solve it. Have I missed something in my script?

sol
  • 22,311
  • 6
  • 42
  • 59
  • 2
    From [the docs](https://api.jquery.com/ready/): _"In cases where code relies on loaded assets (for example, if the dimensions of an image are required), the code should be placed in a handler for the `load` event instead."_ – James Thorpe Aug 23 '16 at 12:22
  • [Documentation](https://api.jquery.com/ready/) states "In cases where code relies on loaded assets (for example, if the dimensions of an image are required), the code should be placed in a handler for the load event instead." – Sohil Aug 23 '16 at 12:27
  • @JuanMendes please remove the duplicate here. This is not the question! It is not about `all` images. – eisbehr Aug 23 '16 at 12:33
  • There's an example on how to wait for specific images http://stackoverflow.com/questions/15134468/waiting-for-multiple-images-to-load-before-sliding-div-down Just be careful that the images may be cached so the load event may have already fired by the time you register a listener – Ruan Mendes Aug 23 '16 at 12:36

5 Answers5

3

Use load on the images and count till all are loaded, then execute your function.

var images $('.image');
var amount = images.length;

images.on('load', function() {
    if( --amount == 0 ) {
        sections();
    }
});

To prevent cached images to be executed from the listener, you could trigger them manually (even on window.load). This lines will fire the event for cached elements:

images.each(function() {
    $(this).complete && $(this).trigger('load');
});
eisbehr
  • 12,243
  • 7
  • 38
  • 63
  • That's just overcomplicating it when you could just use the window load event – A. Wolff Aug 23 '16 at 12:31
  • 1
    This is only needed if the images are created dynamically. Note that the load event may not fire if the image is cached. The load event on the window already waits for all images – Ruan Mendes Aug 23 '16 at 12:31
  • @JuanMendes `This is only needed if the images are created dynamically` What do you mean? – A. Wolff Aug 23 '16 at 12:32
  • @A.Wolff Using the windows `load` event waits for all resources to load. Using the images own `load` event makes sure your code is ran when the images load... which is exactly what you want. – Birjolaxew Aug 23 '16 at 12:32
  • Yes & no. `window.load` will wait till everything and every image. Not just the `.image` elements. So the execution yould be possible delayed too long as needed. @A.Wolff – eisbehr Aug 23 '16 at 12:32
  • @eisbehr Ya, this is a good point but most of the time the page wait for images only because anyway script are run sync. EDIT: oops sorry, you mean all images and not just `.image img` ones, my bad! – A. Wolff Aug 23 '16 at 12:33
  • 1
    @A.Wolff Scripts can be loaded async (and should be, unless they require being ran sync), and stylesheets and subframes can take longer to fetch than images (especially if the images are cached). – Birjolaxew Aug 23 '16 at 12:36
  • @Birjolaxew You are right, these are correct points for sure! – A. Wolff Aug 23 '16 at 12:38
2

Use instead:

$(window).on('load resize', sections);
A. Wolff
  • 74,033
  • 9
  • 94
  • 155
0

Try using 'on load' event handler instead of $(document).ready:

$(window).on('load', function() { 
  sections();
});

instead of:

$(document).ready(function() { 
  sections();
});


Or you can use:

$(window).on('load resize', function() { 
  sections();
});

To handle both events :)

Alan Jurczak
  • 479
  • 5
  • 14
-1

I believe what you're looking for is the timeout() function.

If my understanding is correct you can call window.timeout([function to call], [time in ms] and the function to call will execute that many ms AFTER the code is executed. It will not wait like a sleep().

pig__man
  • 7
  • 2
-1
setTimeout(
    function(){
        console.log("this line will be logged with 1000ms delay");
    },1000
)

W3C documentation

Maciej Treder
  • 11,866
  • 5
  • 51
  • 74