107

I have a page that is loading a script from a third party (news feed). The src url for the script is assigned dynamically on load up (per third party code).

<div id="div1287">
    <!-- dynamically-generated elements will go here. -->
</div>

<script id="script0348710783" type="javascript/text">
</script>

<script type="javascript/text">
    document.getElementById('script0348710783').src='http://oneBigHairyURL';
</script>

The script loaded from http://oneBigHairyURL then creates and loads elements with the various stuff from the news feed, with pretty formatting, etc. into div1287 (the Id "div1287" is passed in http://oneBigHairyURL so the script knows where to load the content).

The only problem is, it only loads it once. I'd like it to reload (and thus display new content) every n seconds.

So, I thought I'd try this:

<div id="div1287">
    <!-- dynamically-generated elements will go here. -->
</div>

<script id="script0348710783" type="javascript/text">
</script>

<script type="javascript/text">
    loadItUp=function() {
        alert('loading...');
        var divElement = document.getElementById('div1287');
        var scrElement = document.getElementById('script0348710783');

        divElement.innerHTML='';
        scrElement.innerHTML='';
        scrElement.src='';
        scrElement.src='http://oneBigHairyURL';
        setTimeout(loadItUp, 10000);
    };
    loadItUp();
</script>

I get the alert, the div clears, but no dynamically-generated HTML is reloaded to it.

Any idea what I'm doing wrong?

Jonathan M
  • 17,145
  • 9
  • 58
  • 91
  • 1
    I don't know if the browser understands that you want it to download the js again, since you're trying to load the same url over and over. it probably sees it as the same and doesn't bother. try a caching technique when you change the src: `scrElement.src='http://oneBigHairyURL?v=2'; //auto-increment this value` – Matt K Mar 09 '12 at 23:22
  • @Matt K. Yes, I should have posted that I've tried this, but to no avail. Sorry it wasn't part of the original post. – Jonathan M Mar 12 '12 at 19:51
  • @JonathanM that by generating new script tag, it does work. How about loading the same tag but just changing the value of 'src' attribute? – Parth Oct 02 '15 at 15:05
  • @Dr..Net, the selected answer was the only thing I got to work. Tried changing `src` to no avail. To trim down the DOM, I remove old ` – Jonathan M Oct 02 '15 at 16:44

9 Answers9

94

How about adding a new script tag to <head> with the script to (re)load? Something like below:

<script>
   function load_js()
   {
      var head= document.getElementsByTagName('head')[0];
      var script= document.createElement('script');
      script.src= 'source_file.js';
      head.appendChild(script);
   }
   load_js();
</script>

The main point is inserting a new script tag -- you can remove the old one without consequence. You may need to add a timestamp to the query string if you have caching issues.

Chuck Le Butt
  • 47,570
  • 62
  • 203
  • 289
Kelly
  • 40,173
  • 4
  • 42
  • 51
  • 28
    For cache problems, the best thing is to add a timestamp to the url `'hello.js?cachebuster='+ new Date().getTime() ` – Ruan Mendes Mar 09 '12 at 23:36
  • @Juan Mendes, thats correct because a news feed has to be loaded again. Skip it only when cache is wanted in case only rerun is needed and a new unnessecary load would be a slow down, for example a script that doesnt change. –  Aug 04 '19 at 21:54
46

Here's a method which is similar to Kelly's but will remove any pre-existing script with the same source, and uses jQuery.

<script>
    function reload_js(src) {
        $('script[src="' + src + '"]').remove();
        $('<script>').attr('src', src).appendTo('head');
    }
    reload_js('source_file.js');
</script>

Note that the 'type' attribute is no longer needed for scripts as of HTML5. (http://www.w3.org/html/wg/drafts/html/master/scripting-1.html#the-script-element)

Luke
  • 18,811
  • 16
  • 99
  • 115
16

Creating a new script tag and copying the contents of the existing script tag, and then adding it, works well.

var scriptTag = document.createElement('script');
scriptTag.innerText = "document.body.innerHTML += 'Here again ---<BR>';";
var head = document.getElementsByTagName('head')[0];
head.appendChild(scriptTag);

setInterval(function() {
    head.removeChild(scriptTag);
    var newScriptTag = document.createElement('script');
    newScriptTag.innerText = scriptTag.innerText;
    head.appendChild(newScriptTag);
    scriptTag = newScriptTag;    
}, 1000);

This won't work if you expect the script to change every time, which I believe is your case. You should follow Kelly's suggestion, just remove the old script tag (just to keep the DOM slim, it won't affect the outcome) and reinsert a new script tag with the same src, plus a cachebuster.

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
7

Small tweak to Luke's answer,

 function reloadJs(src) {
    src = $('script[src$="' + src + '"]').attr("src");
    $('script[src$="' + src + '"]').remove();
    $('<script/>').attr('src', src).appendTo('head');
}

and call it like,

reloadJs("myFile.js");

This will not have any path related issues.

fugu
  • 6,417
  • 5
  • 40
  • 75
Maleen Abewardana
  • 13,600
  • 4
  • 36
  • 39
6

Use this function to find all script elements containing some word and refresh them.

function forceReloadJS(srcUrlContains) {
  $.each($('script:empty[src*="' + srcUrlContains + '"]'), function(index, el) {
    var oldSrc = $(el).attr('src');
    var t = +new Date();
    var newSrc = oldSrc + '?' + t;

    console.log(oldSrc, ' to ', newSrc);

    $(el).remove();
    $('<script/>').attr('src', newSrc).appendTo('head');
  });
}

forceReloadJS('/libs/');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
stomy
  • 1,778
  • 1
  • 15
  • 16
0

Using PipesJS I can dilute this to

 <dyn insert="here" id="clickity" ajax="url">Click for refresh</dyn>
 <!-- <dyn> is a dynamic linker in PipesJS -->
 <article id="here"></article>

You would use this state to affect the article in the same as the source for the JS.

So using

 <dyn attribution="src-attr" class-attr="src:newjs.js;" id="clickity">Click for refresh</dyn>
 <!-- attribution is the class of tags getting the new attr, src="newjs.js"-->
 <script class="src-attr" src="scripty.js"></script>

will do the same thing as <article> in this scope. It will fill the innerHTML.

if you want to, use an id on the <head> tag.

You can insert preemptive functions and use them in tandem with PipesJS. you can also use functions that come after the call.

If you would rather use a timer this would be performed by creating a

setInterval(function(input) { document.getElementById("clickity").click(); }, 3000);

setInterval() object. 3000 is in ms.

You can see PipesJS here.

Anthony Pulse
  • 71
  • 1
  • 7
0

I thing just call the function for the new elements after it appended to DOM instead reload all scripts.

aldrian
  • 13
  • 4
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 18 '23 at 06:26
0

add a class to your script tag and then wrap your script in a function and add the wrapper function name as an atribute

then do this

const reloadStaticBlocks = () => {
    [...document.querySelectorAll('.script')].map(script => {
        let scriptInnerHtml = script.innerText;
        let scriptAttribute = script.getAttribute('data-function-name')
        let parent = script.parentNode;
        parent.removeChild(script);
        
        var newScriptTag = document.createElement('script');
        newScriptTag.innerText = scriptInnerHtml;
        newScriptTag.className = "static-block-script";
        newScriptTag.setAttribute('data-function-name', scriptAttribute);
        parent.appendChild(newScriptTag);
        return newScriptTag;
    }).map(script => {
        eval(script.getAttribute('data-function-name'))()
    })
};
-1

I know that is to late, but I want to share my answer. What I did it's save de script's tags in a HTML file, locking up the scripts on my Index file in a div with an id, something like this.

<div id="ScriptsReload"><script src="js/script.js"></script></div>

and when I wanted to refresh I just used.

$("#ScriptsReload").load("html_with_scripts_tags.html", "", function(
    response,
    status,
    request
  ) {

  });