I have a basic example of the Module pattern that simply adds a class to the footer element on the page.
When the script is loaded in the body tag (after the footer element) it works and adds the class to the footer.
When the script is loaded in the head tag (before the footer element) it doesn't work even though the init shouldn't be getting called until the document is ready.
I assume the document.ready isn't working as expected and therefore it's not finding the footer element as it doesn't exist.
This has been bugging me for ages and I can't seem to find the solution, can someone please shed some light on this problem?
Example: https://jsfiddle.net/5x5skoq3/
var App = (function ($) {
"use strict";
// private alias to settings
var s;
return {
settings: {
footer: $("footer")
},
init: function() {
s = this.settings;
this.footer();
},
footer: function(){
s.footer.addClass("active");
}
};
})(jQuery);
jQuery(document).ready(function() {
App.init();
});
Thank you
It's not the problem that init
is called too early, but rather that settings: { footer: $("footer") }
is evaluated too early. You're already referencing the element here when the module is loaded, not when it's initialised.
Luckily that's easy to fix:
var App = (function($) {
"use strict";
var footer;
return {
settings: {
footerSelector: "footer"
},
init: function() {
footer = $(this.settings.footerSelector);
this.footer();
},
footer: function() {
footer.addClass("active");
}
};
})(jQuery);
In this case, App
is a self invoked function. The function executes creating the return object and all of it's properties. At the time that the function self invokes, footer: $("footer")
is called returning a jQuery object with length: 0
indicating that the selector returned no matched element or element sets. I've updated your jsfiddle to alert the number of matches found on your call to init
.
You can fix this in a variety of ways. The way I would probably fix it would be to convert settings
into an object constructor:
var App = (function ($) { "use strict"; // private alias to settings var s; return { settings: function () { this.footer = $('footer'); }, init: function() { s = new this.settings(); this.footer(); }, footer: function(){ s.footer.addClass("active"); } }; })(jQuery); jQuery(document).ready(function() { App.init(); });
footer.active { background-color: red; color: #fff; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <header> Header content </header> <footer> Footer content </footer>
Using this method, you still keep the logic out of the init
function but maintain the consistency with your original example where settings
returns an object.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.