-1

I am "new" to JavaScript, making my first image- and media-slider for a website. I have searched for answers in the web and here in SO, but they did not work for me.

My last big change was to divide my script into two parts. One outside of $(document).ready() and one inside. I want the user to be able to call a function via a button in the HTML. To make this possible this function has to be global and can not be located inside the $(document).ready(). Am I right? Before I divided my script everything was inside the $(document).ready() area and it worked properly. But of cause I could not call the function via a button.

But now the part inside my $(document).ready(), which has to build the slider when the page is loaded, is not waiting for it. All my getElementById()'s are producing the error: "Can't set property 'style' of null." So the slider will not be built. This is telling me getElementById() returns "null" even if it is inside $(document).ready().

HTML:

  <!-- very content -->

  <link href="...css" />
  <script src="...js" />
  <div id="slider"></div>

  <!-- more content -->

  <div id="changeContent"></div>

  <!-- more content -->

</body>
</html>

JavaScript:

    // Configuration
var slidersParentId = 'imslider';
var slideShowTitle = '';
var thumbnailWidth = 20;
var slidesWidth = 281.25;
var slidesHeight = 144.5625;
var currentSlideWidth = 500;
var currentSlideHeight = 257;
var nextSlideWidth = 375;
var nextSlideHeight = 192.75;
var prevSlideWidth = nextSlideWidth;
var prevSlideHeight = nextSlideHeight;
var resizeDifference = currentSlideWidth - nextSlideWidth;
var slidesMargin = 20;
var animationDistance = slidesWidth + slidesMargin;
var animationSpeed = 2000;
var intervalSpeed = 7000;
var contentDiv = "descriptif_site_spip";

// Variables from slides.json
var numberOfSlides;
var jsonSlides = {};
var bgImgUrl;

// Cache the DOM
var $slideShow = $('#'+slidersParentId);
var $slideInner;
var $slides;
var $slideNav;
var $navThumb;
var $thumb;
var $hovers;
var $content = document.getElementById(contentDiv);

// Other global Variables
var interval;
var currentSlide = 1;
var nextSlide = currentSlide + 1;
var prevSlide = currentSlide - 1;
var lastSlide = currentSlide;
var lastCurrentDif;
var lastNextSlide = lastSlide + 1;
var lastPrevSlide = lastSlide - 1;
var thumbImgs = [];
var navTo;
var interval;
var i;

// Global Variables for dragging
var dragStartPosition;
var dragStopPosition;
var draggedDistance;
var slidesDragged;
var posSlidesDragged;
var negSlidesDragged;

// IRIS-MEDIA-MODUS ?!
var iris_mode = 1;

//global functions...
//global warming...


$(document).ready(function(){

  $.ajax({}

    //getting some json...

  });

  // Building the slideshow windows
  if (slideShowTitle !== 0) {
    $slideShow.append('<h2 class="slideShowTitle">'+slideShowTitle+'</h2>');
  }

  $slideShow.append('<div id="outerWindow"><div id="innerWindowPositioner"<div id="innerWindow"></div></div</div>');
  $slideInner = $slideShow.find('#innerWindow');
  $slideInner.css({'width': numberOfSlides*slidesWidth+numberOfSlides*slidesMargin*currentSlideWidth*3});


// Building the slides & hovers
for (i=1; i<=numberOfSlides; i++) {

    var idSlides = "slide_Nr"+i;
    alert(idSlides);
    var idHover = "hover_Nr"+i;
    var j = i-1;
        bgImgUrl = "url('" +jsonSlides[j].mediaUrl+ "')";
    var title = jsonSlides[j].title;
    var artUrl = jsonSlides[j].articleUrl;
    var subtitle = jsonSlides[j].subtitle;
    var text = jsonSlides[j].text;
    var date = jsonSlides[j].date;

    $slideInner.append('<div class="slide" id="'+idSlides+'"><div class="hover" id="'+idHover+'"></div></div>');
    $('#'+idSlides).css('top', '56.21875px');
    document.getElementById(idSlides).style.backgroundImage = bgImgUrl;

    $('#'+idHover).append('<div class="hover-title"><h3><a href="'+artUrl+'">'+title+'</a></h3><span class="hover-subtitle">'+subtitle+'</span></div><span class="hover-date">'+date+'</span><br clear="all" /><p class="hover-text">'+text+'</p>');
}

$slides = $slideInner.find('.slide');
$hovers = $slides.find('.hover');


// Building the thumbnail navigation
$slideShow.append('<div id="slideShowNavigation"><ul id="navigationThumbnails"></ul></div>');
$slideNav = $slideShow.find('#slideShowNavigation');
$navThumb = $slideNav.find('#navigationThumbnails');

for (i=0; i<numberOfSlides; i++) {
    thumbImgs[i] = jsonSlides[i].mediaUrl;
//  alert(thumbImgs);
}

for (i=1; i<=numberOfSlides; i++) {

        j = i-1;
    var idThumbs = "thumb_Nr"+i;
        bgImgUrl = "url('" +jsonSlides[j].mediaUrl+ "')";

    $navThumb.append('<li class="thumb" id="'+idThumbs+'"></li>');
    document.getElementById(idThumbs).style.backgroundImage = bgImgUrl;
    }

$thumb = $navThumb.find('.thumb');
$( '<li class="year">&nbsp;>&nbsp;2000&nbsp;>&nbsp;</li>' ).insertBefore( "#thumb_Nr62" );
$navThumb.prepend('<li class="year">1980&nbsp;>>&nbsp;</li>');
$navThumb.append('<li class="year">&nbsp;&nbsp;2020&nbsp>></li>');
$navThumb.append('<br clear="both" />');

// ...some
// ...more
// ...functions

});

With this HTML-structure it is not working. When I put the script-inclusion at the end of my HTML it works correctly and the slider will be built.

So why is my $(document).ready() firing too early? I also tried $(window).load() but it hat no effect.

Or is there any why to make function inside $(document).ready() globally available without removing it from $(document).ready()?

Nils
  • 159
  • 2
  • 12
  • 1
    I suspect, your script is dependent on response of ajax, hence, you need to move the dependent code in callback function. – Nikhil Aggarwal Jun 30 '15 at 15:29
  • Have you verified that `$slideShow` exists in the DOM? We're missing some relevant info. – Lye Fish Jun 30 '15 at 15:33
  • Dude, not sure where you went, but most likely the elements you're creating and adding to the DOM are not actually being added because you're trying to add them to elements that don't exist. jQuery kind of sucks in that it quietly fails when it should be giving errors. So the elements that you're appending new content to weren't found with a jQuery selector, then your `.append()` calls are doing nothing, therefore the new elements won't be found. So just make sure that all the stuff that *needs* to be in `.ready()` gets put back there. This includes DOM selection. –  Jun 30 '15 at 17:49
  • I am sorry, i forgot to show you my DOM-variables. I will Updated my JavaScript now. – Nils Jul 01 '15 at 07:47
  • I added all the vars i am using. @squint I try to add elements to other added elements. Is this procedure ok? Like i said this code works, when I do not split it into 2 parts inside and outside the ready(). – Nils Jul 01 '15 at 07:55
  • Besides... yes I tried to remove "unimportant" code from my JavaScript, because I do not know If someone here wants to read lines of code. The code worked before. And it is not working since I divided it. So I am sure the functions are correct, since they are working when I put the script-tag in the footer. If you think the complete code is needed here, i will post it. I just did not want to make it too complicated. – Nils Jul 01 '15 at 08:03
  • 1
    Yep, your DOM selection for the `$slideShow` and `$content` variables is now happening before the elements exist. Either move your scripts down to the bottom of the page just before the `

    ` tag, or perform those DOM selection inside the `.ready()` handler so that it doesn't happen until the DOM is loaded. That's the whole point of a `.ready()` handler. It makes sure the document is fully loaded before running so that the initial elements exist for selection.

    –  Jul 01 '15 at 15:27

2 Answers2

1

Probably because your script is running before the rest of the page loads. Try using $(window).ready().

EDIT:

Had wrong function .load() I meant to have .ready()... Whoops!

IE5Master
  • 363
  • 1
  • 2
  • 14
  • I think you're not understanding what `.ready()` does and how it differs from `.load()`. –  Jun 30 '15 at 15:35
  • Sure I do, I had to use it just the other day. – IE5Master Jun 30 '15 at 15:36
  • 1
    Super, then why would `.load()` be any better than `.ready()` here? –  Jun 30 '15 at 15:37
  • 1
    The OP is already using `.ready()`. He mentioned it about a dozen times in the question. Passing `window` instead of `document` makes no difference. Have no idea why someone would give this `+1`. Stop with the pity votes people. –  Jun 30 '15 at 15:39
  • Ok, I'll leave the answers up to you from now on squint. – IE5Master Jun 30 '15 at 15:41
0

My last big change was to divide my script into two parts. One outside of $(document).ready() and one inside. I want the user to be able to call a function via a button in the HTML. To make this possible this function has to be global and can not be located inside the $(document).ready().

Actualy, it can:

All global JavaScript objects, functions, and variables automatically become members of the window object.

I suppose you need something like this:

window.addEventListener('DOMContentLoaded', function () {
    window.my_magic_function = function (/* my magic params */) {
        /* doing my magic */
    };
});
<button onclick="my_magic_function(/* my magic params */)">Do magic</button>

window.addEventListener('DOMContentLoaded', ...) equivalent to $(document).ready(...)

outoftime
  • 633
  • 6
  • 20
  • `'DOMContentLoaded'` is basically equivalent to `.ready()`. And you wouldn't need to wait for the DOM to be ready to make a global function. –  Jun 30 '15 at 15:50
  • @squint, I know. So, why did you telling that, if it doesn't solve TC's problem in different way? – outoftime Jun 30 '15 at 15:54
  • I'm telling you that this doesn't help solve the OP's problem. He has some malfunctioning code somewhere, which has been excluded from the question. I'm guessing that he's removed some stuff from the `.ready()` handler that actually needs to be there. I don't know what you're trying to say with this answer. –  Jun 30 '15 at 15:56
  • @squint > Before I divided my script everything was inside the $(document).ready() area and it worked properly. – outoftime Jun 30 '15 at 16:33
  • All your answer is doing is telling him about a construct that *he already knows about*. It doesn't tell him *what* needs to wait for the DOM to load. This is unknown because he excluded a bunch of code. Furthermore, your code that is waiting for the DOM to load *doesn't need to wait* because you never have to wait for the DOM to be ready to create a global function. –  Jun 30 '15 at 17:43
  • @squint link with proof of "All global JavaScript objects, functions, and variables automatically become members of the window object." – outoftime Jun 30 '15 at 17:45
  • @squint I don't think it is hard to understand what it mean. – outoftime Jun 30 '15 at 17:46
  • You're not understanding any of this. Yes, any beginner knows that globals are a member of the `window` object. That's because the `window` object is the exposed "variable object" of the global execution context. I'm saying that your `DOMContentLoaded` handler is absolutely pointless. You can do the same thing without it. –  Jun 30 '15 at 17:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/82001/discussion-between-outoftime-and-squint). – outoftime Jun 30 '15 at 17:49
  • @outoftime So is this a possibility to call a function ( which is located inside my $(document).ready() ) with a html button? – Nils Jul 01 '15 at 14:11
  • 1
    @Nils I provide working example and proof link that it is, in post above. Not very relative, but https://github.com/pyinstaller/pyinstaller/wiki/How-to-Report-Bugs#information-we-need can answer the question how to make post. – outoftime Jul 01 '15 at 16:29