Reload updated java<script> code without fully reloading the html page - javascript

I am developing a single page web application, that has many different features and forms. When developing a deep (I mean something that is not on the home page) feature, I go through this cycle:
develop the code, editing classes and functions
refresh the whole page
clicking all the way till I get to the part that I need to test (that adds up to about a minute sometimes)
testing the new code
back to the (1) code editor doing updates
doing about 15 minor edits, can take a frustrating 30 minutes of repeated reloading and clicking
Is there any plugin, piece of javascript, or method, that allows to reload the updated javascript without reloading everything, so one can skip the 2. and 3. from the cycle above and continue doing live tests?
If there's no such thing, I am planning on developing a little javascript plugin that will reload the scripts, and probably with socket.io connection to a backend node.js server that will watch the files for any updates and push the load events to the browser.
So, I am interested in any idea about this, any thing that I should take into consideration when writing the plugin.
Thanks : )

You could do something like this.
function LoadMyJs(scriptName) {
var docHeadObj = document.getElementsByTagName("head")[0];
var dynamicScript = document.createElement("script");
dynamicScript.type = "text/javascript";
dynamicScript.src = scriptName;
docHeadObj.appendChild(newScript);
}
Call the LoadMyJs function on page load
<body onLoad="LoadMyJs()">
Then reload with the click of a button (or from your console)
<input type="button" name="reloadjs" value="Reload JavaScript" onclick="LoadMyJs('my_live_loading_script.js')">
This could be simplified using e.g jQuery
Thanks to:
http://www.philnicholas.com/2009/05/11/reloading-your-javascript-without-reloading-your-page/

Here's what I came up with: a Node.js module that watches for changes in .js & .coffee scripts, and pushes the changes to the browser upon editing the files.
It works standalone, even if you are developing on filesystem file:/// without using a web server.
It works with any framework, just launch the standalone script and point it to your js/ directory.
It has an express.js helper, that make it run using the same server instance.
It is as easy as
adding a single line of <script> tag to your existing code, and
running the live script, pointing it to the html root.
code: 🐱/etabits/live.js

That's may be not the best answer but for local developments I use that firefox plugins:
https://addons.mozilla.org/en-US/firefox/addon/auto-reload/
This reload the css, js or anything present in a directory
For dev which really needs to be remotely , I use that small js code you can adapt for reloading js.
function refreshCss(rule){
if (rule == null)
rule = /.*/;
var links = document.getElementsByTagName("link");
for(var i=0;i<links.length;i++)
{
if (!links[i].href.match(rule))
continue;
if (! links[i].href.match(/(.*)time=/)){
if (links[i].href.match(/\?/))
var glue = '&';
else
var glue = '?';
links[i].href += glue+"time="+new Date().getTime();
}
else{
links[i].href.replace(/time=\d+/, "time"+new Date().getTime());
}
}
if (!no_refresh)
{
setTimeout(function(){refreshCss(rule)}, 5000);
}
};
// and then call it refreshCss("regex to match your css, or not"); var no_refresh=false;
Edit: this is a version with "setTimeout", but you can easily made a "keypress" version of it

Replace with dynamic script.
function LoadMyJs(scriptName)
{
var docHeadObj = document.getElementsByTagName("head")[0];
var dynamicScript = document.createElement("script");
dynamicScript.type = "text/javascript";
dynamicScript.src = scriptName;
docHeadObj.appendChild(dynamicScript);
}

Related

Locate and check script (within webpage) is correct using nightwatchjs

I'm using nightwatchjs as my testing tool and I need to test that an injected script is correctly displayed on a page, and that the script is correctly populated.
So, the following script html is to be tested (to ensure that it is correctly displayed):
<script type="text/javascript">
(function() {
window.dm = window.dm ||{ AjaxData:[]};
window.dm.AjaxEvent = function(et, d, ssid, ad) {
dm.AjaxData.push({ et:et, d:d, ssid:ssid, ad:ad});
window.DotMetricsObj && DotMetricsObj.onAjaxDataUpdate();
};
var d = document, h = d.getElementsByTagName('head')[0], s = d.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src='https://uk-script.dotmetrics.net/door.js?id=11373';
h.appendChild(s);
} ());
</script>
So firstly, I'd like to test that this script is present on the page, but in a way that is as less brittle as possible. I can test for /html/head/script[13]/text() but this is really brittle and far from ideal.
Is there something in the script itself that I can reference, so the test won't be as brittle?
Secondly, I want to ensure that the script details are correct. This can be a test that will check for the presence of the https://uk-script.dotmetrics.net part of the script for example.
However, I've tried to use my usual css and xpath ways of locating this part of the script but with no luck.
Any help would be appreciated. Thanks.
In line with the paradigm of "assert the what, not the how", the "what" here seems to be making sure that a script got injected into the page. You could use a selector like this one: script[src^="https://uk-script.dotmetrics.net/"], in conjunction with Nightwatch's element function. You could add more selectors to assert the script has the expected attributes like type and async.
In this way, you can skip the implementation detail (the presence of the injecting script) and focus on what I think you really care about (that a script with a correct URL got injected into the page).

Browser does not replace an include file by its including file

I am an absolute beginner in JS.
1) What I'm trying to do:
My web pages are composed of an index.php which is the same for all the files of a directory and one of a set of content.inc, like this: index.php?open=content.inc. This is done by a PHP snippet in the index.php and works well.
However, Google indexes all the content.inc files. The user's browser then displays the content.inc without the framing index.php. This I want to avoid. I therefore add a modest script at the beginning of each content.inc (which I would convert into a function once it runs) to tell the browser that instead of displaying the content.inc, it should display index.php?open=content.inc.
2) My unworkable solution:
var url = window.location.pathname;
var filename = url.substring(url.lastIndexOf('/')+1);
if (filename.indexOf("index.php") = -1)
{ var frame_name = "index.php?open="+filename;
window.location.replace(frame_name);
};
The browser (Firefox 60) ignores this; it displays content.inc. (I also have versions of this script which get the browser into an endless loop.)
What is wrong here? Please help!
PS: Please be assured that I have done extensive web search on this problem and found many pages of complaints about location.replace getting into an infinite loop; but none matches my situation. However, I gratefully accept a helpful link as an answer.
For starters, you have an error in this line:
if (filename.indexOf("index.php") = -1)
That's an assignment and will always evaluate to true, you need to use == or === (which should be more performant).
The guilty line is on your test case (see JP de la Torre answer). And to improve, here's a snippet to demo how to analyze the url with a regular expression :
function redirect(url) {
if(url && url.indexOf('.inc') >= 0) {
return url.replace(/\/(\w+)\.inc/, '/index.php?open=$1');
}
return url;
}
let urls = [
window.location.href,
'http://google.fr',
'http://example.com/index.php?open=wazaa',
'http://example.com/wazza.inc'
];
urls.forEach(url => {
console.log(url, ' => ', redirect(url));
});
The regexp will capture any text between a / and .inc. You can use it then as replacement value with the $1.
And applied to your case, you simply need :
if(window.location.href.indexOf('.inc') >= 0) {
window.location.href = window.location.href.replace(/\/(\w+)\.inc/, '/index.php?open=$1');
}
You can also use .htaccess server side to redirect request for .inc files on your index.php if mod_rewrite is enabled.
The solution to the problem of including an INC file called separately is the one proposed by Bertrand in his second code snippet above. It presupposes (correctly) that the inc extension is omitted in the replacement.
As I reported above, Firefox may get into an endless loop if it opens a PHP file directly, i.e. without involving the local host (with its php module).

Stop Javascript and HTML from Loading From Cache

I am building a single page javascript app and when the application starts I use a single javascript file to load every other file I need on the fly. When I hit refresh, according to firebug, my HTML page as well as javascript pages will load with a 304 Not Modified Error and my javascript stops working.
I understand this is due to browser caching, but how can I avoid this? I load the initial HTML page with a single script call
<script src="js/config.js" type="text/javascript"></script>
and then continue to load the rest dynamically from within that script
window.onload = function () {
var scripts = ['http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js', 'js/core.js', 'js/sandbox.js']; //Application scripts
var loaded = 0;
//Callback is executed after all scripts have been loaded.
var callback = function () {
if (loaded + 1 == scripts.length) {
//Create Modules
CORE.loader("js/modules/Login.js", function () {
CORE.createModule('loginForm', Login);
});
//Create HTML bindings.
CORE.createBinding('appContainer', '#Login', 'login.html');
CORE.bindHTML(window.location.hash); //Loads hash based page on startup
} else {
loaded++;
loadScript(scripts[loaded], callback);
}
};
loadScript(scripts[0], callback);
function loadScript(scriptSrc, callback) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = scripts[loaded];
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == 'loaded' || script.readyState == 'complete') {
script.onreadystatechange = null;
callback();
}
};
} else {
script.onload = function () {
callback();
};
}
document.getElementsByTagName('head')[0].appendChild(script);
}
};
I know that Gmail uses cookies to prevent this. Does anyone have any idea how to take that approach? Should I set the cookie on the server and then check it with JS on each page load/refresh and use something like window.location.refresh() if the cookie tells me the page is loaded from cache?
To expand on #Ramesh's answer:
to force a reload of the js file, instead of the cache, use this html:
<script src="js/config.js?v=42" type="text/javascript"></script>
The next time you make changes to that file just +1 the v. This also works with css files by the way.
Caching is an important for performance reasons. I would recommend you pass a version number in your query string and with every update, increment the version number. This will force the browser to resend the request and it will load from cache if it already has the same version.
I agree with all the other answers. 304 is not an error and there are many reasons why this behavior is correct.
That being said, there is a simple "hack" you can use. Simply attach a unique URL parameter to the JS call.
var timestamp = +new Date;
var url = "http://mysite.com/myfile.js?t=" + timestamp;
Again, this is a hack. Performance wise, this is horrible.
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
Add this into your HTML HEAD.
<?php
$xn = date("YmdHis");
echo " <script src='root.js?$xn'></script>";
?>
I would suggest to use Javascript to generate a random number using Math.random multiply it and then Math.floor to return the integer of it. Then, I would add this number to the URL as a variable. Since the number changes during every page load, the file should never be cached.
<script>
var url="yourscript.js";
var extra="?t=";
var randomNum = String((Math.floor(Math.random() * 200000000000000)));
document.getElementById('myScript').src = url+extra+randomNum;
</script>
<script id="myScript"></script>
You need to set script.src = scripts[loaded]; after adding the onreadystatechange/onload handlers. Otherwise the event is going to fire before the handlers are added, since the cached version loads instantly.
After struggling with the cache issue for months, trying just about anything (including a script which changes the URLs using a parameter) I found a post which explains how to do that using the IIS.
Start IIS Manager (INETMGR from the start menu works for me)
Navigate to desired site in the Connections tree
Open Output Caching
Edit Feature Settings
Uncheck Enable cache and Enable kernel cache
If you cannot save changes, make sure your web.config file is not marked read only
IISRESET is required for the changes to take place
This is the original post, which mentions that it is relevant for IIS 7.5 (in Windows 7)
https://forums.iis.net/t/959070.aspx?How+do+you+disable+caching+in+IIS+
One of the things I tried before that was adding .html and .js in Output Caching, and checking "Prevent All Caching". So if it doesn't work after the IISRESET, try that, though I'm not sure it is actually required.
EDIT:
If it does not work, still in the IIS go to HTTP Response Headers and add new actions:
Name: cache-control, Value: no-cache
Name: expires, Value: 0

How can I delay the execution of a script block until after an external script has loaded?

I'm trying to dynamically insert and execute a couple of scripts, and I think I'm hitting a race condition where the second is trying to execute before the first is loaded.
The project I'm working on has an unusual requirement: I am unable to modify the page's HTML source. It's compiled into an app for localization purposes.
Therefore, I'm unable to insert <script> tags like I normally would to link in JavaScript files.
It turns out that the client wants to use a hosted web font, so I decided to build and append the two required <script> tags dynamically in an already-linked JavaScript file.
The <script> blocks are appending correctly in the head of the document, but function in the second block seems to be firing before the external script linked in the first <script> tag is fully loaded, and it's throwing an undefined error.
Here's the relevant piece of code:
document.getElementsByTagName("head")[0];
var tag = document.createElement('script');
tag.setAttribute("src", "http://use.typekit.com/izj3fep.js");
document.getElementsByTagName("head")[0].appendChild(tag);
try {
Typekit.load(); // This is executing too quickly!
} catch(e){
console.log("Hosted fonts failed to load: " + e);
}
I tried moving the try block to the window.onload event, but that fires before any of this code is called.
I guess I could dynamically load jQuery and then use it's ready event, but that seems pretty heavy-handed. I'm hesitant to pull in a library on this project, as the client has a lot of custom JavaScript that could potentially clash with it.
What else can I try?
You need to hook into the script element's onload event and execute your code there:
document.getElementsByTagName("head")[0];
var tag = document.createElement('script');
tag.onload = onTagLoaded;
tag.setAttribute("src", "http://use.typekit.com/izj3fep.js");
document.getElementsByTagName("head")[0].appendChild(tag);
function onTagLoaded() {
try {
Typekit.load(); // This is executing too quickly!
} catch(e){
console.log("Hosted fonts failed to load: " + e);
}
}
You can load it with yepnope ( http://yepnopejs.com/ ). I know it's a library, but it's very light (free if your client is already using modernizr). It's well worth it. Hopefully the client doesn't have another yepnope function, and you don't have to worry about the clash.
Are you using jQuery? If not, I highly recommend it. It'll make your life so much easier:
$.getScript('http://use.typekit.com/izj3fep.js', function(data, textStatus){
try {
Typekit.load(); //executes properly now!
} catch(e) {
console.log("Hosted fonts failed to load: " + e);
}
});
Combining the scripts into one big seems to be the easiest solution.

Javascript in Safari not always running

Am having an issue with Safari. I have a basic script using jQuery that makes some changes to a form field and adds some behaviours to it. When I run this script on using the document ready method it's fine in Firefox but in Safari it doesn't always run the initial changes. I can hit refresh and get it running fine 4/5 times, but sometimes it just doesn't initialise like it should.
This is running on a local server so the refresh is pretty quick, I'm wondering if the javascript is executing before the page has finished loading. I've tried calling the script in the foot of the page rather then the header but that hasn't helped. I remember hearing about different browsers firing document ready at different times and thought this would help remedy it but it hasn't and I can't find any further information on that topic.
Anything I'm missing that could be the issue or a workaround? The script itself doesn't seem to be at fault. Am using the jQuery colours plugin, apart from that it's only jQuery and my script.
Help is always appreciated, thanks people!
Here is the code. initSearchBox() is run using the line below in the header.
$(document).ready(function() { initSearchBox() ; });
function randomFieldValue(){
var options = new Array(
'Lorem',
'Ipsum',
'Dolor',
'Sit',
'Amet'
)
t = Math.floor(Math.random()*(options.length - 1));
return options[t] ;
}
function initSearchBox(){
instanceDefText = randomFieldValue() ;
$('#search-form-field')
.attr('value',instanceDefText)
.css('color','#fff')
.animate({color:'#999'},1500)
.focus(function(){
if($(this).attr('value') == instanceDefText){
$(this).attr('value','')
.css('color','#000')
}
})
.blur(function(){
if($(this).attr('value') == ''){
instanceDefText = randomFieldValue() ;
$(this).attr('value',instanceDefText)
.css('color','#fff')
.animate({color:'#999'},1500)
}
});
}

Categories

Resources