jQuery, update content when necessary - javascript

I'm trying to update contents of a chat located in div (div1) but only when the contents of div1 change (a message was submitted into db and picked up in div1).
I tried the solution from here but my get fails to compare the data.
This solution works perfectly but without content comparison:
window.onload = startInterval;
function startInterval()
{
setInterval("startTime();",2000);
}
function startTime()
{
jQuery('#div1').load('index.php #div1 > *');
}
This is the modification based on this, which fails:
window.onload = startInterval;
function startInterval()
{
setInterval("startTime();",2000);
}
function startTime()
{
var $main = $('#div1');
$.get('chat.php #div1', function (data)
{
if ($main.html() !== data) $main.html(data);
});
}
I tried various modifications of this code but to no avail...
I can't reload the entire page and I don't want to do this if not necessary since it makes the chat harder to read if you have to scroll trough the messages.
How can this be fixed?
UPDATE
Based on #T.J's suggestions I modified the code which now works perfectly:
window.onload = startInterval;
function startInterval()
{
setInterval(startTime,3000);
scrolDown();
}
function startTime()
{
var $main = $('#div1');
$.get('#div1', function (data)
{
elements = $(data);
thisHTML = elements.find("#div1").html();
if ($main.html() !== thisHTML) {
$main.html(thisHTML);
scrolDown();
}
});
}
The other problem was that get required library:
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.pack.js"></script>
which apparently was not required by the load which I used previously.

You want to use get, but you want the fragment feature of load, so you'll have to do that work yourself. Then remember what you got last time, and only update if it's not the same:
var lastHTML;
function startTime()
{
var $main = $('#div1');
$.get('chat.php', function (data) // <== Or index.php, the question has both
{
var elements, html;
// Turn the HTML into elements
elements = $(data);
// Get the HTML of *only* the contents of #div1
html = elements.find("#div1").html();
// If that has changed, use it
if (lastHTML !== thisHTML) {
lastHTML = thisHTML;
$main.html(thisHTML);
}
});
}
Note that that's a fairly basic implementation of the fragment feature (it doesn't, for instance, strip out scripts the way load does). You may want to look at how load does its fragment stuff and replicate that (the joy of open source).

Related

window. onload=function() just works without cached DOM

The product image is displayed as inline SVG and receives a new color for specific paths, depending on the dropdown selection.
"use strict";
window.onload=function(){
var dropdownColor = document.getElementById('Color');
// When a new <option> is selected
dropdownColor.addEventListener('change', function() {
var selectPathSvg = document.getElementById('pathNumber');
//get value text
var colorValue= selectElemFerse.options[selectElemFerse.selectedIndex].text;
//Clear all Classes from SVGPath
selectPathSvg .classList = '';
// Add that class to the <p>
selectPathSvg.classList.add(colorValue);
})
}
But this Javascript code works only, if the page was read in the DOM for the first time. If you reload this page with F5, this will not lead to any errors in the console, but not to the desired result.
EDIT: Nothing here worked for me. But I noticed that if I delete the `woocommerce_recently_viewed``cookie, that the systems works fine. But how to fix such a thing?
It's generally bad practice to use onload = ... You should instead try using addEventListner("load", ...)
The reason your script does not run, is because it gets compiled after the page has been fully loaded, so you should also check if the load event has already been fired.
"use strict";
if(document.readyState === "complete") onLoad();
else addEventListener("load", onLoad);
function onLoad(){
console.log("Doing on load stuff here...");
}
Try this instead and see if it works:
window.addEventListener('DOMContentLoaded', (event) => {
var dropdownColor = document.getElementById('Color');
// When a new <option> is selected
dropdownColor.addEventListener('change', function() {
var selectPathSvg = document.getElementById('pathNumber');
//get value text
var colorValue= selectElemFerse.options[selectElemFerse.selectedIndex].text;
//Clear all Classes from SVGPath
selectPathSvg .classList = '';
// Add that class to the <p>
selectPathSvg.classList.add(colorValue);
})
});

Comparing strings using jQuery load function

Writing the code i am stuck with one thing. I am loading variable string through jQuery load function and there is where trouble starts. I want my code to check if string loaded through text file had any changes and if that is true make some actions. How do I set my variable as a string to compare it with the one in file? Part of the code
var follow, donate;
var auto_refresh = setInterval(function() {
follow = $('#followerid').load("../Muxy/most_recent_follower.txt");
donate = $('#donatorid').load("../Muxy/most_recent_donator.txt");
}, 100);
and then I want to make something like this:
someUpdateFunction() {
if($(#'followerid').get("innerHTML") != follow)
// actions (animations, div changes etc.)
}
That is probably totally wrong but I wasnt able to find any tips here. Thanks in advance
Try something like this:
$.get('../Muxy/most_recent_follower.txt', function (data) {
var followerid = $('#followerid').html();
if( followerid == data ){
// They are the same
}else{
// They are not the same
}
});
The .html() method will get the HTML inside #followerid. It sounds like that's what you want.
The jQuery.load function doesn't return the loaded file, it returns the element. Try out this:
var auto_refresh = setInterval(function() {
oldFollow = $('#followerid').html();
$('#followerid').load("../Muxy/most_recent_follower.txt");
oldDonate = $('#donatorid').html();
$('#donatorid').load("../Muxy/most_recent_donator.txt");
}, 100);
someUpdateFunction() {
if($('#followerid').html() !== oldFollow)
// actions (animations, div changes etc.)
}
}

Loading javascript files in js files. Which is best way to check whether all files are loaded or not?

I have a array where i have specified the files i need to load in javascript before calling specific script. Lets call those particular lines of code as myscript.
I did as follows
var fileNamesArray = new Array();
fileNamesArray.push("abc.js");
fileNamesArray.push("pqr.js");
fileNamesArray.push("xyz.js");
fileNamesArray.push("klm.js");
var totalFiles = jQuery(fileNamesArray).length;
var tempCount = 0;
jQuery.each(fileNamesArray, function(key, value) {
jQuery.getScript(value, function() {
tempCount++;
});
});
to check whether all files are being loaded or not, i done following thing but doesn't seems to be effective
var refreshIntervalId = setInterval(function() {
if (tempCount == totalFiles) {
clearInterval(refreshIntervalId);
return;
}
}, 10);
i have implemented these in object oriented javascript as follows
function Loader() {
this.jQuery = null;
// check for specifically jQuery 1.8.2+, if not, load it
if (jQuery == undefined) {
jQuery.getScript(
"/Common/javascript/jquery/map/javascript/jquery-1.8.2.js",
function() {
this.jQuery = jQuery.noConflict();
});
} else {
var jQueryVersion = $.fn.jquery;
jQueryVersion = parseInt(jQueryVersion.split('.').join(""));
if (182 > jQueryVersion) {
jQuery.getScript(
"/Common/javascript/jquery/map/javascript/jquery-1.8.2.js",
function() {
this.jQuery = jQuery.noConflict();
});
}
}
}
Loader.prototype.LoadAllFile = function() {
//here i am loading all files
}
Loader.prototype.bindMap = function(options) {
this.LoadAllFile();
//execute the script after loading the files... which we called as myscript
}
i am loading more than 12-14 js files via ajax.
if you observe Loader.prototype.bindMap, i am loading all the files first and then executing the script.
But it seems that myscript the script start executing before all files being loaded.
what are the better ways to execute the script only after all js files are loaded.
Take a look at jQuery's .load() http://api.jquery.com/load-event/
$('script').load(function () { });
Based on the documentation on Jquery.getScript , it is a shorthand for Jquery.ajax. By default this in async call. You might want to change it to do a synchronous call.
To set this property, you can refer to this
So instead of doing a setInterval, you can just loop in your array and do a Jquery.getScript.

Javascript window.print() issue on newly appended HTML

The problem is that the new content will not print (a few more elements).
When the user clicks my print link then I add more html to the document before window.print() is called.
I use ajax to fetch more chapters for a book before printing.
Code:
Print initialized:
var afterPrint = function () {
var timer = setInterval(function () {
afterContentPrint(); // Cleanup html (restore to initial state)
clearInterval(timer);
}, 900);
}
//window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
Event print click:
$("#print-test").click(function (e) {
e.preventDefault();
beforeContentPrint(); // ajax call for additional content, finishing by calling window.print()
});
In function beforeContentPrint():
var jqxhr = $.ajax({
type: "GET",
url: bookURL,
success: function(data) {
.....
.....
$(article).each(function () {
parent.append(article);
});
},
complete: function() {
var timer = setInterval(function () {
    window.print();
}, 900);
}
}
The new content is visibly added to the HTML document, so it should work. But only the initial content (before ajax call) is picked up for print.
This solution is for IE and Firefox (onbeforeprint and onafterprint).
Using window.matchMedia('print') seems to work fine in Chrome with this logic.
I don't know why this is happening but there is a working around in mozilla docs; printing a hidden iframe, then you open more chapters of the book with no need to shows up.
Here the link https://developer.mozilla.org/en-US/docs/Printing
Here the code:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>MDN Example</title>
<script type="text/javascript">
function closePrint () {
document.body.removeChild(this.__container__);
}
function setPrint () {
this.contentWindow.__container__ = this;
this.contentWindow.onbeforeunload = closePrint;
this.contentWindow.onafterprint = closePrint;
this.contentWindow.print();
}
function printPage (sURL) {
var oHiddFrame = document.createElement("iframe");
oHiddFrame.onload = setPrint;
oHiddFrame.style.visibility = "hidden";
oHiddFrame.style.position = "fixed";
oHiddFrame.style.right = "0";
oHiddFrame.style.bottom = "0";
oHiddFrame.src = sURL;
document.body.appendChild(oHiddFrame);
}
</script>
</head>
<body>
<p><span onclick="printPage('externalPage.html');" style="cursor:pointer;text-decoration:underline;color:#0000ff;">Print external page!</span></p>
</body>
</html>
1st Attempt : try putting asyn:false in the ajax request of beforeContentPrint, so that the elements will be added first then the print will be called.
var jqxhr = $.ajax({
type: "GET",
url: bookURL,
async:false,
success: function(data) {
.....
.....
$(article).each(function () {
parent.append(article);
});
},
complete: function() {
var timer = setInterval(function () {
window.print();
}, 900);
}
}
2ndAttempt: Take a look Here how to force execution of one function after another.
Hope this helps.
As the elements added aren't shown it can be a little hard to pinpoint the exact problem, but adding elements via appending/inserting into document doesn't always work that well for all browsers and in worst case you will need to add those elements manually by code (document.createElement(), appendChild() etc.).
In an attempt to create a work-around you can try to use MutationObservers to track changes for your article element which can hopefully help you trigger print when DOM is updated properly. The support is fairly good in new browsers (you may have to use prefix in some, f.ex. WebKitMutationObserver) and for older browsers you can provide a fallback - which of course then only get you so far.
This will monitor a target element for changes and fire a callback.
Generic example based on this article:
var article = document.querySelector('#articleID'),
doPrint = false, // must be available in global/parent scope
o,
useFallback = (typeof MutationObserver !== 'undefined');
if (!useFallback) {
o = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// you can do additional filtering here
// using the mutation object (.name, .type, ...)
if (doPrint) {
doPrint = false;
window.print();
}
});
});
var cfg = { attributes: true, childList: true, characterData: true };
o.observe(article, cfg);
}
Now that the observer is running you can do this modification in your success callback:
var timer; // keep track of setTimeout so we can cancel it
success: function(data) {
...
...
$(article).each(function () {
parent.append(article);
});
// after last element is added, add a "dummy" element
doPrint = true;
if (useFallback) {
// fallback to setTimeout or other solution
}
else {
parent.append('<br />');
}
}
I made an online demo here which sets up the observer and adds some elements. Open console to see actions. The demo is probably too limited data-wise to simulate your situation but can be useful to see the process.
The mechanism used here for triggering print dialog itself can be discussed if is the best - I just provide one for sake of example.
But you can see the observer is triggered when something is added to article. This way you know the DOM has been updated and it should be available for printing. Only the last element added need to trigger the print, hence the doPrint flag.
If you still have no success you will need to consider adding the elements manually the code way or perhaps predefine some elements that you inject when needed (as said, without knowing the full scenario here it has to be with the guess).
It looks like the setInterval, clearInterval is what is messing you up. Change to a setTimeout and get rid of the clearInterval in your afterprint function. I made a fiddle that works in FF and IE9. Fiddle
complete: function() {
var timer = setTimeout(function () {
window.print();
}, 900);
}

GetElementById of ASP.NET Control keeps returning 'null'

I'm desperate having spent well over an hour trying to troubleshoot this. I am trying to access a node in the DOM which is created from an ASP.NET control. I'm using exactly the same id and I can see that they match up when looking at the HTML source code after the page has rendered. Here's my [MODIFIED according to suggestions, but still not working] code:
ASP.NET Header
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
<script type="text/javascript">
$(document).ready(
var el = document.getElementById('<%= txtBox.ClientID %>');
el.onchange = alert('test!!');
)
</script>
</asp:Content>
ASP.NET Body
<asp:TextBox ID="txtBox" runat="server"></asp:TextBox>
Resulting Javascript & HTML from above
<script type="text/javascript">
$(document).ready(
var el = document.getElementById('MainContent_txtBox');
el.onchange = alert('test!!');
)
</script>
...
<textarea name="ctl00$MainContent$txtBox" id="MainContent_txtBox"></textarea>
I can only assume that the script is loading before the control id has been resolved, yet when I look at the timeline with Chrome's "Inspect Element" feature, it appears that is not the case. When I created a regular textarea box to test and implement the identical code (different id of course), the alert box fires.
What on earth am I missing here? This is driving me crazy >.<
EDIT: Wierd code that works, but only on the initial page load; firing onload rather than onchange. Even jQuery says that .ready doesn't work properly apparently. Ugh!!
$(document).ready(function() {
document.getElementById('<%= txtBox.ClientID %>').onchange = alert('WORKING!');
})
Assuming the rendered markup does appear in that order, the problem is that the element doesn't yet exist at the time your JavaScript is attempting to locate it.
Either move that JS below the element (preferably right at the end of the body) or wrap it in something like jQuery's document ready event handler.
Update:
In response to your edits, you're almost there but (as others have mentioned) you need to assign a function to the onchange event, not the return result of alert(). Something like this:
$(document).ready(function() {
// Might as well use jQuery to attach the event since you're already using
// it for the document ready event.
$('#<%= txtBox.ClientID %>').change(function() {
alert('Working!');
});
});
By writing onchange = alert('Working');, you were asking JavaScript to assign the result of the alert() method to the onchange property. That's why it was executing it immediately on page load, but never actually in response to the onchange event (because you hadn't assigned that a function to run onchange).
Pick up jQuery.
Then you can
$(function()
{
var el = document.getElementById('<%= txtBox.ClientID %>');
el.onclick() { alert('test!!'); }
});
Other answers have pointed out the error (attempting to access DOM nodes before they are in the document), I'll just point out alternative solutions.
Simple method
Add the script element in the HTML below the closing tag of the element you wish to access. In its easiest form, put it just before the closing body tag. This strategy can also make the page appear faster as the browser doesn't pause loading HTML for script. Overall load time is the same however, scripts still have to be loaded an executed, it's just that this order makes it seem faseter to the user.
Use window.onload or <body onload="..." ...>
This method is supported by every browser, but it fires after all content is loaded so the page may appear inactive for a short time (or perhaps a long time if loading is dealyed). It is very robust though.
Use a DOM ready function
Others have suggested jQuery, but you may not want 4,000 lines and 90kb of code just for a DOM ready function. jQuery's is quite convoluted so hard to remove from the library. David Mark's MyLibrary however is very modular and quite easy to extract just the bits you want. The code quality is also excellent, at least the equal of any other library.
Here is an example of a DOM ready function extracted from MyLibrary:
var API = API || {};
(function(global) {
var doc = (typeof global.document == 'object')? global.document : null;
var attachDocumentReadyListener, bReady, documentReady,
documentReadyListener, readyListeners = [];
var canAddDocumentReadyListener, canAddWindowLoadListener,
canAttachWindowLoadListener;
if (doc) {
canAddDocumentReadyListener = !!doc.addEventListener;
canAddWindowLoadListener = !!global.addEventListener;
canAttachWindowLoadListener = !!global.attachEvent;
bReady = false;
documentReady = function() { return bReady; };
documentReadyListener = function(e) {
if (!bReady) {
bReady = true;
var i = readyListeners.length;
var m = i - 1;
// NOTE: e may be undefined (not always called by event handler)
while (i--) { readyListeners[m - i](e); }
}
};
attachDocumentReadyListener = function(fn, docNode) {
docNode = docNode || global.document;
if (docNode == global.document) {
if (!readyListeners.length) {
if (canAddDocumentReadyListener) {
docNode.addEventListener('DOMContentLoaded',
documentReadyListener, false);
}
if (canAddWindowLoadListener) {
global.addEventListener('load', documentReadyListener, false);
}
else if (canAttachWindowLoadListener) {
global.attachEvent('onload', documentReadyListener);
} else {
var oldOnLoad = global.onload;
global.onload = function(e) {
if (oldOnLoad) {
oldOnLoad(e);
}
documentReadyListener();
};
}
}
readyListeners[readyListeners.length] = fn;
return true;
}
// NOTE: no special handling for other documents
// It might be useful to add additional queues for frames/objects
else {
if (canAddDocumentReadyListener) {
docNode.addEventListener('DOMContentLoaded', fn, false);
return true;
}
return false;
}
};
API.documentReady = documentReady;
API.documentReadyListener = documentReadyListener;
API.attachDocumentReadyListener = attachDocumentReadyListener;
}
}(this));
Using it for your case:
function someFn() {
var el = document.getElementById('MainContent_txtBox');
el.onclick = function() { alert('test!!');
}
API.attachDocumentReadyListener(someFn);
or an anonymous function can be supplied:
API.attachDocumentReadyListener(function(){
var el = document.getElementById('MainContent_txtBox');
el.onclick = function() { alert('test!!');
};
Very simple DOM ready functions can be done in 10 lines of code if you just want one for a specific case, but of course they are less robust and not as reusable.

Categories

Resources