jquery function include only once? - javascript

I'm building single page application with jquery. so assume I have a sidebar like this
dashboard.html
order.html
and each time i click on it I load the content via ajax. It work fine but I go back and forth btw pages I notice the script got loaded twice or more. How to solve this?

Put the scripts and HTML in separate files. Then keep track of whether you've already loaded a script, and don't load it again.
var dashboard_js_loaded = false;
$("#dashboard").click(function() {
$("#content").load("dashboard.html", function() {
if (!dashboard_js_loaded) {
$.getScript("dashboard.js", function() {
dashboard_js_loaded = true;
});
}
});
});
Maybe a library like require.js can be used to manage this more generally. Or you can just write a simple function that keeps track of which JS files have been loaded in an object.

Related

Show all hidden elements when a page loads with override?

I have a page that forces some JS to load on a page that I need to override. I can load a separate JS file to do this. I want to have the page do the .show for any of the .below-the-folds on the page. I guess the best way to say it is, I want all the "more" things on the page to be expanded when the page loads, rather than making a person click more to see what's below the fold on all these.
This is the JS I need to override, I can't change it since it's loaded by the app automatically. There can be more than one of the lists hidden, I'm not sure how much harder that makes things.
function MoreFacets($more_facets_div) {
this.$more_facets_div = $more_facets_div;
this.bind_events();
};
MoreFacets.prototype.bind_events = function() {
var self = this;
self.$more_facets_div.find('.more').on('click', function (e) {
$(this).siblings('.below-the-fold').show();
$(this).hide();
});
self.$more_facets_div.find('.less').on('click', function (e) {
$(this).parent().hide();
$(this).parent().parent().find('.more').show();
});
};
$(function() {
$('.more-facets').each(function() {
new MoreFacets($(this));
});
});
It's loaded on the page and the HTML looks like this:
<h3>Additional filters: </h3>
<dl id="facets">
<dt>Collecting Area</dt>
<dd> Here's Something in the list</dd>
<dd> Here's the last in the list</dd>
<div class="more-facets">
<span class="more btn">∨ more</span>
<div class="below-the-fold">
<dd>Something That's hidden is here</dd>
<dd>Something more in this hidden list</dd>
So when the ∨ more is clicked is when the others below-the-fold appear, and that's what I want to load when the page loads. There's usually a few different lists like this on the page.
So I'm thinking what I need to do is something like run the ('.below-the-fold').show() for all the lists when the page loads?
Update A note to clarify: when the page loads now they're all hidden. I'd like them to all show when the page is loaded so no one has to click anything to have everything showing.
Another note based on another question below... It's loaded in a separate file, and I can load my file before that one. I do know that I can override other JS on the page, so I assume I can override this as well.
Based on your last edit, it sounds like you're already onto the fastest solution to your problem.
Please note, this will only work if the script is not loaded asynchronously, but if you have control of the order the scripts are loaded in, you can insert your script between the problem script and jQuery.
Your script can be something as easy as redefining the function it's using to something like this:
MoreFacets.prototype.bind_events = function() {
var self = this;
//Autostart in our open state without completely disabling the functionality
self.$more_facets_div.find('.below-the-fold').show();
self.$more_facets_div.find('.more').hide();
self.$more_facets_div.find('.more').on('click', function (e) {
$(this).siblings('.below-the-fold').show();
$(this).hide();
});
self.$more_facets_div.find('.less').on('click', function (e) {
$(this).parent().hide();
$(this).parent().parent().find('.more').show();
});
};
Now, that won't work if you don't have control over the script loading, but you might have hope even in that case, because document ready functions in jQuery are invoked in the order they're registered, so if you can't really control where your script is you might play with an alternative
$(function() {
$('.more-facets').each(function() {
$(this).find('.below-the-fold').show();
$(this).find('.more').hide();
});
});
The first will be cleaner, but the second is a fallback for more restrictive situations, and both should achieve your desired effect without completely removing the functionality, just changing the default state on load.

Execute jQuery after Other JS file Dynamically loads content

I'm working to modify some content which is dynamically loaded via another script(let's call is script #1) onto my site. Script #1 loads some markup and content and I've been using the setTimeout() function to call my script (Script #2) using a delay of a few seconds, in order to wait to be sure that Script #1 has executed and the content is present in the DOM.
My issue is that Script#1 has different loading times, based on the server load and can be slow or fast depending on these factors, and right now, playing it safe with setTimeout() I'm often left with a second or two where my scripts are still waiting to be fired and Script #1 has already loaded the content.
How can I execute my script as soon as Script#1 successfully loads it's dynamic content?
I've found this post which does seem to address the same issue but using the setInterval function as #Matt Ball has laid out there doesn't work at all for some reason. I'm using the code below where 'div.enrollment' is meant to find in the DOM which is dynamically loaded and execute..
jQuery(window).load(function ($)
{
var i = setInterval(function ()
{
if ($('div.enrollment').length)
{
clearInterval(i);
// safe to execute your code here
console.log("It's Loaded");
}
}, 100);
});
Any help on guidance on this would be greatly appreciated! Thanks for your time.
It seems that the healcode.js is doing a lot of stuff. There is a whole lot of markup added to the <healcode-widget> tag.
I would try to add another tag with an id inside and test for its existence:
<healcode-widget ....><div id="healCodeLoading"></div></healcode-widget>
Test in an interval for the existence of healCodeLoading inside <healcode-widget>: (Assuming jQuery)
var healCodeLoadingInterval = setInterval(function(){
var healCodeLoading = jQuery('healcode-widget #healCodeLoading');
if (healCodeLoading.length == 0) {
clearInterval(healCodeLoadingInterval);
// Everything should be loaded now, so you can do something here
}
}, 100);
healcode.js should replace everything inside <healcode-widget></healcode-widget> during init. So, if your <div>-element is no longer inside, the widget has loaded and initialized.
Hope that helps.
If you just want to load some markup and content and then run some script afterwards, you can use jQuery. You should use something like the following in script#1 to run a function in script#2
$.get( "ajax/test.html", function( data ) {
// Now you can do something with your data and run other script.
console.log("It's Loaded");
});
The function is called, after ajax/test.html is loaded.
Hope that helps

issue with Javascript in Rails View

In my Rails View template, I'm using some jQuery for tabbed panels functionality:
<section>
... content ommitted
</section>
<script>
$(document).ready(function () {
$('.accordion-tabs-minimal').each(function(index) {
$(this).children('li').first().children('a').addClass('is-active').next().addClass('is-open').show();
});
$('.accordion-tabs-minimal').on('click', 'li > a', function(event) {
if (!$(this).hasClass('is-active')) {
event.preventDefault();
var accordionTabs = $(this).closest('.accordion-tabs-minimal')
accordionTabs.find('.is-open').removeClass('is-open').hide();
$(this).next().toggleClass('is-open').toggle();
accordionTabs.find('.is-active').removeClass('is-active');
$(this).addClass('is-active');
} else {
event.preventDefault();
}
});
});
</script>
Because I'm also using this script in other View templates, and I want to organize my Javascript a bit better, I created a Javascript file (tabbed_panels.js) under app/assets/javascripts and moved the above script to the tabbed_panels.js file.
However now the panels on my page have no content the first time the page is loaded. Only when the page is refreshed, the panels get loaded with content.
Does someone have an idea what's going on and how this can be solved, so my tabbed panels have content at the first page load?
thanks for your help,
Anthony
Turbolinks
The likely issue you have will be that you're trying to load the $(document).ready function with Turbolinks running.
This simply won't work (if you're using Turbolinks), as since Turbolinks refreshes only the <body> tag of your page, it will typically prevent your JS from binding to the various elements in the DOM, as the JS has not been reloaded
The way to fix this is to develop your JS around Turbolinks (using Turbolinks' event handlers):
#app/assets/javascripts/tabbed_panels.js
var new_items = function() {
$('.accordion-tabs-minimal').each(function(index) {
$(this).children('li').first().children('a').addClass('is-active').next().addClass('is-open').show();
});
$(document).on('click', '.accordion-tabs-minimal li > a', function(event) {
if (!$(this).hasClass('is-active')) {
event.preventDefault();
var accordionTabs = $(this).closest('.accordion-tabs-minimal')
accordionTabs.find('.is-open').removeClass('is-open').hide();
$(this).next().toggleClass('is-open').toggle();
accordionTabs.find('.is-active').removeClass('is-active');
$(this).addClass('is-active');
} else {
event.preventDefault();
}
});
});
$(document).on("page:load ready", new_items);
This should allow your tabs to be populated on page load, regardless of whether Turbolinks is operating or not.
--
Unobtrusive JS
Something else to consider (you've already done this), is that you really need to use unobtrusive javascript in your application.
Unobtrusive JS basically means that you're able to abstract your "bindings" from your page to your Javascript files in the asset pipeline. There are several important reasons for this:
Your JS can be loaded on any page you want (it's DRY)
Your JS will reside in the "backend" of your app (won't pollute views)
You'll be able to use the JS to populate the various elements / objects you want on screen
It's always recommended you put your JS into separate files - including in the views sets you up for a big mess down the line

load widgets after loading conten

What am doing is writing wizards using existing forms and list views. we want to combine these forms in single page. here is a script we have used to get form from url then called function to bind widgets. first line is loading content of form but bindWidgets is not working. While bindWidgets is working on preloaded content which is default loaded with page.
<script>
$(document).ready(function() {
$("#template_form").load("/push_templates/pushtemplate/create/ #zform");
bindWidgets();
});
</script>
Do we need to wait for load, as it seems that 2nd line is executed prior to content loaded. How can we go to wait stat or better way to call bind function after load complete.
Use this;
<script>
$(document).ready(function() {
$("#template_form").load("/push_templates/pushtemplate/create/ #zform", function() {
bindWidgets();
});
});
</script>
You can see demo here: jsfiddle

how to load external javascript inside partial view dynamically?

I'm using jquery's .html() function to inject a html file into a partial div of the main page of my application. In the injected partial html page, there is a javascript reference such as script(src='../../javascripts/partialFunctions.js').
The jquery function and the main page are like:
$('.partialDiv').html(htmlResult);
<div>main page</div>
<div class='partialDiv'></div>
<input type='button'>button</input>
When the user click a specific button on the main application page, the jquery function will got called and the html file will got injected to the main page.
The problem is every time a new htm file got injected, the browser will load the script file. So there will be many duplicated javascript functions after the user clicked the button several times.
How can I do this dynamically and avoid the duplication of javascript functions?
Thanks in advance!
You can remove the script tags and references from the htmlResult page.
Then use $.getScript('myscript.js') to import the necessary JavaScript files.
More info on getScript() here
So to load in the script and make sure it only loads in once:
var window.foo = false; //Outside the document.ready
$('.partialDiv').html(htmlResult);
if(window.foo == false){
$.getScript("js/myScript.js", function(data, textStatus, jqxhr){
console.log('Script loaded');
window.foo = true;
});
}
I just did a quick test, it looks like script tags are stripped out anyways when you call .html(). So you should be able to simply do:
var html = "<html><script></script></html>",
cleanedHtml = $(html).html();
myEl.html(cleanedHtml);

Categories