Reload JavaScript files without refreshing HTML - javascript

I've a HTML which loads several Javascript files:
<script src="assets/js/a.js"></script>
<script src="assets/js/b.js"></script>
<script src="assets/js/jquery.min.js"></script>
As I debug/test my Javascripts in my browser's console, is it possible to reload these Javascript files without the need to reload the entire HTML page?

You could remove and then re-add them:
$('script').each(function() {
if ($(this).attr('src') !== 'assets/js/jquery.min.js') {
var old_src = $(this).attr('src');
$(this).attr('src', '');
setTimeout(function(){ $(this).attr('src', old_src + '?'+new Date()); }, 250);
}
});

Nope (at least not without a hack), in fact - be very careful reloading so much. It's quite possible that your javascripts become cached, which leads to many-a-headache trying to debug, since your updates are not applying.
https://superuser.com/questions/36106/force-refreshing-only-javascript-files-in-firefox-and-chrome

Based on PitaJ's solution.
Reload all javascript in a function. You can call this from anywhere you want.
$('script').each(function () {
if ($(this).attr('src') != undefined && $(this).attr('src').lastIndexOf('jquery') == -1) {
var old_src = $(this).attr('src');
var that = $(this);
$(this).attr('src', '');
setTimeout(function () {
that.attr('src', old_src + '?' + new Date().getTime());
}, 250);
}
});

Tested with jQuery 2.0.3 and chrome 43
function reloadScript(id) {
var $el = $('#' + id);
$('#' + id).replaceWith('<script id="' + id + '" src="' + $el.prop('src') + '"><\/script>');
}
Chrome is complaining, but works:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.
Your script tag has to have id.
Call in console:
reloadScript('yourid');
Does not remove event listeners, so for for example button click gets executed twice if once reloaded.

Related

jquery .load() with back/forward button without hash

I am using a jQuery script I wrote to load content on my site without refreshing the page, and everything works fine except the back/forward buttons. I am using hash links and loading in my php files based on that.
....
<li><a id="theShopLink" class="theMainLinks" href="#shopFrame">SHOP</a>
....
$('.theMainLinks').click(function() {
var dest = $(this).prop("hash").substring(1);
$('.theMainLinks').removeClass('active');
$(this).addClass('active');
if ($('#fullFrame > div').is(':visible')) {
$('#homeFrame').addClass('animated fadeOutLeft');
$('#homeFrame').html('');
}
console.log(dest);
$("<style>html { background: #000; }</style>").appendTo("head");
$('#nextFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/' + dest + '.php');
});
I tried searching and found some examples using html5 window.history.pushState(); but I'm not sure how to work that with my current code without having to rewrite the script. Also the # in the urls look ugly, anyway around this?
I'm not looking to use any kind of plugins/dependencies besides jQuery, and if possible the cleanest/simplest code. Please explain so I can understand because I will need to do something similar with my sub navigation links within the frames and will reuse the function.
UPDATE
On initial website load or refresh, I use the following function to determine what content to load. -
$(function() {
if (window.location.hash) {
var target = window.location.hash.substring(1);
var hash = window.location.hash;
if (hash.toLowerCase().indexOf("frame") >= 0) {
$('#homeFrame').html('');
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/' + target + '.php');
} else if (hash.toLowerCase().indexOf("shop-") >= 0) {
$('#homeFrame').html('');
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/shopFrame.php');
} else if (hash.toLowerCase().indexOf("news-") >= 0) {
......etc......
} else if (hash.toLowerCase().indexOf("/") >= 0) {
var newTar = target.split('/');
$('#homeFrame').html('');
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/general/' + newTar + ' #patchnotesMain');
} else {
// Fragment doesn't exist
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/' + target + ' #newContent');
}
} else {
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/homeFrame.php');
}
});
With window.history.pushState() I think you can obtain the desired result without rewriting your script and without using hash. You could try something similar to:
function handleState(state) {
// here the code you need to change the page
// more or less the body of $('.theMainLinks').click(function() {})
// in your question code
}
$('.theMainLinks').click(function(event) {
event.preventDefault();
const state = {/* here setup the state for next step */};
handleState(state);
window.history.pushState(state);
});
$(window).on("popstate", function(event) {
handleState(event.originalEvent.state);
});
Hope this helps.
In my opinion, # is usually used in detect anchor in the page (jump to anywhere in page) and not the way to change which page to load, the reason is it's very hard to detect and process the url. I suggest you could use ? for query url instead of using #. Simple example url can be like this: www.yoururl.com/index.php?page=frame.
For changing url and pushing state of page to history of browser. You can use the below function to change url
function change_url(title, html, urlPath){
document.title = title;
window.history.pushState({"html":html,"title":title},"", urlPath);
}
After change url, use your code to render new html
$('#homeFrame').html('');
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/' + target + '.php');
To detect event back/forward button, you can use window.onpopstate = function(e){ ... }. This time, your page has all of data that you've just pushed to history, now you can get the data out easily and assign it to html
window.onpopstate = function(e){
if(e.state){ // if state's data is existed
$('#homeFrame').html('');
$('#homeFrame').html(e.state.html);
document.title = e.state.title;
}
};
Please correct me if I were wrong. Hope this would help

How to wait for HTML document to load/render before printing it (plain JavaScript)

I am using this code to open and print image on new html page:
printView(dataUri:string){
var win = window.open();
win.document.write( '<img src="' + dataUri + '">');
win.print();
win.close();
}
When used like that and image is larger than few kB, print preview opens a blank page, because document is not rendered when print is invoked.
I solved that (temporarily) by introducing setTimeout with ~200ms delay before printing, like this:
setTimeout( () => {
win.print();
win.close();
}, 200);
And this works, but I am aware that I should use some DOM/window event to wait until content is loaded. But which one?
What I tried so far:
win.document.onload = ()=>{
console.log('event fired'); // never fired
win.print();
win.close();
}
and
win.addEventListener('load', ()=>{
console.log('event fired'); // never fired
win.print();
win.close();
}
I would like to keep this Vanilla JS, so please do not refer me to jQuery window.ready.
add an onload attribute to your image
win.document.write( '<img src="' + dataUri + '" onload="print()">');
remove win.print() and win.close() from printView()
and add them into another function print()
print() will be fired when the image is finished loading.
this time Hope It Works
I know it's already answered, but I needed to print a new window with a lot of html content and used something like this:
win.document.addEventListener('DOMContentLoaded', this.print());
including the script tag at the bottom of your page should work.
because the browser reads the html page from top to bottom,
it will fire the event after the page is loaded when the script is located at the bottom of the page.
Copy from What is the non-jQuery equivalent of '$(document).ready()'?
domready.js
(function(exports, d) {
function domReady(fn, context) {
function onReady(event) {
d.removeEventListener("DOMContentLoaded", onReady);
fn.call(context || exports, event);
}
function onReadyIe(event) {
if (d.readyState === "complete") {
d.detachEvent("onreadystatechange", onReadyIe);
fn.call(context || exports, event);
}
}
d.addEventListener && d.addEventListener("DOMContentLoaded", onReady) ||
d.attachEvent && d.attachEvent("onreadystatechange", onReadyIe);
}
exports.domReady = domReady;
})(window, document);
How to use it
<script src="domready.js"></script>
<script>
domReady(function(event) {
alert("dom is ready!");
});
</script>
Here it is, based mostly on Imtiaz's idea:
var win = window.open();
var img = win.document.createElement("img");
img.onload = function(){
win.print();
win.close();
}
img.src = dataUri;
win.document.body.appendChild(img);
I just thought that it's cleaner to do in script, instead of using a script to write another script to html…

Click event only works on second post

The below function works only after the page has been refreshed. When the page is refreshed again afterwards it stops working again and so on.
<button id="moreBtn" type="button" class="archive btn btn-default col-sm-12"></button>
function ShowHideBtn() {
var newss = 5;
var numItems = $(".news").length;
hidenews = "- Show Less Products";
shownews = "+ Show More Products";
$(".news:not(:lt(" + newss + "))").hide();
$("hr:not(:lt(" + newss + "))").hide();
if (numItems >= newss) {
$(".archive").show();
$(".archive").html(shownews);
$(".archive").on("click", function (e) {
e.preventDefault();
if ($(".news:eq(" + newss + ")").is(":hidden")) {
$("hr:hidden").show();
$(".news:hidden").show();
$(".archive").html( hidenews );
} else {
$("hr:not(:lt(" + newss + "))").hide();
$(".news:not(:lt(" + newss + "))").hide();
$(".archive").html(shownews);
}
return false;
});
} else {
$(".archive").hide();
}
}
Thanks in advance
This is a guess as there is insufficient information to confirm it. Please provide the full page HTML/code:
As browser page requests are stateless (so it can't know it is every other load), this sounds like a timing issue. The HTML would generally load slower the first time, so if the JS code is not positioned after the element it references (or is inside a DOM ready handler), then it may fail to find the .archive element. It is more likely random than "every other page load" though if it is a timing issue.
Try one of the following:
Place your JS code (or JS script include) after the element they reference. Just before the closing </body> tag is typical for this option.
Place your code inside a DOM ready handler, then its position does not matter. e.g. like:
$(document).ready(function(){
// Your code here
});
or the short-cut version of DOM ready:
$(function(){
// Your code here
});

How to use onhashchange with dynamic items

So, I have two select boxes on a webpage, but in different anchors (one on the page, the other in an iframe) and I'm trying to get the code to detect which anchor it's in, and then relay the selected value in that box to a link. Here's my code:
function locationHashChanged() {
if (location.hash === "#player") {
function setText(text) {
var selectVal = text;
var url = $('twitter').attr("href");
url = 'https://twitter.com/intent/tweet?button_hashtag=stream&text=Just enjoying ' + selectVal + ' on';
$('#twitter').attr("href", url);
}
}
if (location.hash === "#embeds") {
$(function () {
var $twitter = $('twitter');
$('#iframe').on('load', function () {
$(this).contents().find('#cds').change(function () {
var selectVal = $(this).val() || 'nothing much';
url = 'https://twitter.com/intent/tweet?button_hashtag=stream&text=Just enjoying ' + selectVal + ' on';
$('#twitter').attr("href", url);
}).change();
});
});
}
}
I know this is probably not right, or anywhere near right, but am I on the right track? I'm honestly a complete noob when it comes to javascript. Thanks in advance
Apart from what exactly your function looks like, it's not executed on hash change right now.
You use jQuery, so you can listen for hash change like this:
$(window).on('hashchange', function() {
// your locationHashChanged() function goes here
});
With this, every time the hash changes your function will be executed. The very base of your code is alright:
if (location.hash === "#player") {
// this is executed if hash changed to #player
}
if (location.hash === "#embeds") {
// this is executed if hash changed to #embeds
}
Although, inside your if blocks you declare functions (which doesn't make much sense here).
Also note that if the iframe is not from your domain, you won't be able to get any data from it. If that's the case, read more about same origin policy.

jQuery/Javascript: HTML pulled in by AJAX request does not include <script> elements

I have a dynamic page which uses an AJAX request kicked off by jQuery to pull in HTML elements from the server and insert them into the DOM.
The problem is that when I have elements within the response, they are stripped out.
For instance, if I request the following from the server:
<!-- content.html -->
<div>
There is some content here!
<script>
manipulateContent();
</script>
</div>
What actually gets injected into my dynamic page is the following:
<!-- content.html -->
<div>
There is some content here!
</div>
I have tested in Chrome, Firefox, and Safari with identical results.
The relevant Javascript which creates the AJAX request is here:
function loadContent(url){
var a = document.createElement('a');
a.href = url;
if (a.search == ""){
url = url + "?trim=true";
} else {
url = url + "&trim=true";
}
var ch = $('#content-container').height();
// var wh = $(window).height();
$("#content").animate({top: '-='+ch+'px'}, 500, function(){
$.get(url, function(data){
$("body").scrollTop(0);
$("#content").html(data);
$("#content").css({top: ch+'px'});
$("#content").animate({top: '0px'}, 500);
});
});
}
$(document).ready(function(){
// get the current path and save it for later
var currentPage = location.pathname+location.search;
$(".content-link").live("click", function(){
// using the HTML5 history API, add the requested path
// to the browser history, then load the new content
history.pushState({ path: this.path }, '', this.href);
// because the page is not reloaded, $(document).ready()
// is not called, so the currentPath must be updated manually
currentPage = this.href;
loadContent(currentPage);
return false;
});
window.addEventListener('popstate', function() {
// compare the current path to the one being loaded
// if they are different, then load the content
// else, nothing happens
if (currentPage != location.pathname+location.search){
// because the page is not reloaded, $(document).ready()
// is not called, so the currentPath must be updated manually
currentPage = location.pathname+location.search;
loadContent(currentPage);
}
});
});
How can I tell jQuery to include the tags in the response? I've tried browsing through the jQuery docs without much luck, or even mention of the fact that the tags are stripped out. Perhaps I'm just not looking in the right places.
You need to use load, since the whole purpose here is to load hml content to a element.
function loadContent(url) {
var a = document.createElement('a');
a.href = url;
if (a.search == "") {
url = url + "?trim=true";
} else {
url = url + "&trim=true";
}
var ch = $('#content-container').height();
// var wh = $(window).height();
$("#content").animate({
top : '-=' + ch + 'px'
}, 500, function() {
$("#content").load(url, function() {
$("body").scrollTop(0);
$("#content").css({
top : ch + 'px'
});
$("#content").animate({
top : '0px'
}, 500);
});
});
}
According to jQuery documentation (http://api.jquery.com/jQuery.ajax/) if dataType option is html:
Returns HTML as plain text; included script tags are evaluated when
inserted in the DOM.
By default this option is set to Intelligent Guess, so you may want to check the type of response from the server.

Categories