Ajax Call to Reload Div Memory Leak - javascript
Any Suggestions on how i can make my question better?
So I have HTML and Javascript code that takes data out of a DB of a program that is used for statistical analysis of Lab Analysis. For example you have a plating bath say copper and you need to find out the concentration, you take the pH of the bath you then plug it into the program and it saves that information. On the webpage it shows you visually what has been recorded, when the next add is due and how long you have to make changes.
So I then would like to refresh the page every three seconds to show the times counting down till the next test is due, 'I have accomplished this with the code below, however there is a memory leak and as you can see i have tried a number of things to try to clear the memory, but no matter what it builds till the page freezes. Can anyone see what the issue is with the memory leak? It happens in FF and IE 8+ havent tested below that, in chrome no memory leak, but the images flash.
Let me say in advance, I know this is too long a question, so I am sorry, but I don't know how to ask it any other way. As I am sure all of you can see I have a limited understanding of writting web code, so I apologize for that too. I'm just trying to understand why the memory builds and builds. Hopefully there is a way to fix it, by changing the code or removing or adding some code.
To Reload script.
function UnloadHandler() {
window.removeEventListener('unload', UnloadHandler, true);
}
window.addEventListener('unload', UnloadHandler, true);
jQuery(window).unload(function () { $(window).unbind('unload'); });
jQuery.ajaxSetup ({
cache: false
});
loc = window.location.pathname; // grabs page url. \\
pathName = loc.substring(49, loc.lastIndexOf('.') + 4); // parses out url except for htm file name. \\
var script = jQuery(document).ready(function() {
var test = setInterval(function(){ // Sets the data refresh cycle at 3 seconds. \\
jQuery.get(pathName, function (response) {
var source = $('<div>' + response + '</div>');
jQuery("#GroupData").empty();
(document.getElementById("GroupData")).innerHTML = "";
jQuery('#GroupData').html(source.find('#GroupData').load());
timing(); UnloadHandler();
eval(script);
});
},3*1000); // 3 equals seconds to refresh the data thriugh Ajax \\
});
The HTML looks like this.
<div id="GroupInfo">
<table style="border:0px; border-style:solid; border-color:#FFFFFF; width:902px; height:20px; border-spacing:0px 1px;border-collapse:seperate; padding:0px; vertical-align:0;">
<tr>
<td style="background-color:#FFFFFF;color:000000;background-image: url(../Images/Blue-20x20-Button.png); background-size:30px 22px;width:26px; height:21px;"><div style="color:#000000; text-align:center; margin-bottom:-2px;font-weight:bold;"></div></td>
<td style="width:2px;"> </td>
<td style="background-color:#FFFFFF;color:000000;background-image: url(../Images/Blue-354x20-Button.png); background-size:365px 22px;width:336px; height:21px;"><div style="color:#000000; text-align:center; margin-bottom:-2px; font-weight:bold;">Process Tanks</div></td>
<!-- <td height='10' width='122' bgcolor="#0000FF" ><p align='center'><a><b>Sample</b></td>-->
<td style="width:14px;"> </td>
<td style="background-color:#FFFFFF;color:000000;background-image: url(../Images/Blue-122x20-ButtonTest.png); background-size:147px 22px;width:135px; height:21px;"><div style="color:#000000; text-align:center; margin-bottom:-2px; font-weight:bold;">Test Status</div></td>
<td style="width:15px;"> </td>
<td style="background-color:#FFFFFF;color:000000;background-image: url(../Images/Blue-122x20-ButtonTest.png); background-size:147px 22px;width:136px; height:21px;"><div style="color:#000000; text-align:center; margin-bottom:-2px; font-weight:bold;">Adds</div></td>
<td style="width:16px;"> </td>
<td style="background-color:#FFFFFF;color:000000;background-image: url(../Images/Blue-122x20-ButtonTest.png); background-size:148px 22px;width:134px; height:21px;"><div style="color:#000000; text-align:center; margin-bottom:-2px; font-weight:bold;">Corrective Action</div></td>
</tr>
</table>
</div>
<div id="GroupData" align="center">
<div id="DrawRows">
<table class="DrawRow">
<tr>
<td class="drawrows"></td>
</tr>
</table>
</div>
<SCRIPT type="text/javascript">[ItemsHTML]</script>
</div>
One more thing where you see <SCRIPT type="text/javascript">[ItemsHTML]</script> I'm not exactly sure how this works, I didn't write I'm just in charge of changing it. the [ItemsHTML] somehow pulls the data out of the DB from the program and displays it as shown below in place of [ItemsHTML] so there is a source file with this code and it creates a webpage called an out file and in the out file instead of;
<SCRIPT type="text/javascript">[ItemsHTML]</script>
it becomes this;
<SCRIPT type="text/javascript">DrawRow ("G54.HTM","0","00 Chem/Etch/Gain Calculations","","","","","","","","","42","42");
DrawRow ("G78.HTM","0","00 pH Indicators & Reagent Make-Up","","","","","","","Y","6/14/2014 10:21 AM","99","99");
DrawRow ("G55.HTM","6","01 Aurolectroless SMT 520 ENIG","6/9/2014 5:00 AM","6/9/2014 5:00 AM","6/15/2014 5:00 AM","6/15/2014 10:30 AM","","","Y","6/14/2014 7:59 AM","82","99");
DrawRow ("G56.HTM","127","02 Circuposit™ 3000-1 Process","6/6/2014 9:00 AM","6/6/2014 9:00 AM","6/13/2014 9:00 AM","6/14/2014 12:30 AM","","","Y","6/14/2014 1:56 AM","61","60");
DrawRow ("G57.HTM","36","03 Circubond™ 2200 Alternative Oxide","6/9/2014 5:00 AM","6/9/2014 5:00 AM","6/14/2014 5:00 AM","6/14/2014 11:01 AM","","","Y","6/15/2014 3:59 AM","12","9");
DrawRow ("G58.HTM","2","04 Cupulse™ Acid Copper","6/9/2014 6:00 AM","6/9/2014 6:00 AM","6/13/2014 6:00 AM","6/14/2014 9:25 PM","","","","","6","6");
DrawRow ("G59.HTM","0","05 Electroposit™ 1000 Acid Copper","","","","","","","","","16","16");
DrawRow ("G60.HTM","0","06 Electroposit™ 1100 Acid Copper","","","","","","","","","8","8");
DrawRow ("G61.HTM","36","07 EnviroStrip™ Tin Strippers","6/9/2014 5:00 AM","6/9/2014 5:00 AM","6/12/2014 11:00 AM","6/14/2014 9:30 PM","","","","","9","9");
This is not a published website it is all done by opening the "out" file and letting it run on a display so employees can see what is going on with the manufacturing process.
Timing function displays an updated time for the page.. showing the last change made. Also it shows current time
function timing(){ // Function for setting time formats for Current and Updated Time \\
var mydate=new Date()
var Time = "Current Time: ";
var Text = "Last Updated: ";
var build = Date.parse('[LastBuild]');
var build2 = dateFormat(build,"dddd m/dd/yy h:MM:ss TT"); // Format for updated time. \\
var build3 = Date.parse(mydate)
var build4 = dateFormat(build3, "dddd m/dd/yy h:MM:ss TT");
document.getElementById('time').innerHTML = Time+" "+ build4; // Sets the current time to chosen format. \\
document.getElementById('time2').innerHTML= Text + " " + build2; // Sets the updated time to format chosen for build2. \\
}
I also have this to refresh the page ever minute. This almost fixes the problem by clearing a lot of the allocated memory built up, but it doesnt release all of it. So if your looking at the memory profiled on a graph it goes up for a minute then dips down, but not all the way down after 30 minutes te memory used has doubled. See below for refresh with no scroll to top.
function refreshPage() { // Sets the page refresh to not scroll in IE \\
var page_y = document.documentElement.scrollTop;
var page_x = document.documentElement.scrollLeft;
window.location.href = window.location.href.split('?')[0] + '?page_y=' + page_y + "&page_x=" + page_x;
}
window.onload = function () {
timing();
UnloadHandler();
setTimeout(refreshPage, 1*60*1000); // Change fist number in equation, the first number represents minutes \\
var match = window.location.href.split('?')[1].split("&");
if (window.location.href.indexOf('page_y') != -1) {
document.documentElement.scrollTop = match[0].split("=")[1];
}
if (window.location.href.indexOf('page_x') != -1) {
document.documentElement.scrollLeft = match[1].split("=")[1];
}
}
We are going to do this by steps :)
Remove the eval(script); (eval must not be used, check stackoverflow discussion : Why is using the JavaScript eval function a bad idea? )
Instead, just call a declared function. Here is your code modified :
var timer = '';
jQuery.ajaxSetup ({
cache: false
});
loc = window.location.pathname;// grabs page url. \\
pathName = loc.substring(49, loc.lastIndexOf('.') + 4); // parses out url except for htm file name. \\
function script(){
timer = setInterval(function(){// Sets the data refresh cycle at 3 seconds. \\
clearInterval(timer);
jQuery.get(pathName, function (response) {
var source = $('<div>' + response + '</div>');
jQuery("#GroupData").empty();
(document.getElementById("GroupData")).innerHTML = "";
jQuery('#GroupData').html(source.find('#GroupData').load());
timing();
$(window).unbind('unload');
script();
});
},3*1000); // 3 equals seconds to refresh the data thriugh Ajax \\
}
jQuery(document).ready(function() {
script();
});
After modifying this, what does the "timing()" function do ? can you past your code ? Maybe the function creates a memory leaks too.
Watch : http://www.w3schools.com/jsref/met_win_clearinterval.asp
I think your Memory leak comes from a clearInterval that you don't use. Every time you use a recursive function with interval, you have to clear previews calls (for avoid memory leak).
Best regards
Related
Is there a way to remove and HTML element after six hours?
I have a picture with the word "NEW" over it to designate a new document that has been posted to our website. I would like to have jQuery remove the picture after 6 hours of it being posted. How would I go about doing this? Here is the element: <tr class="pointer"> <td> <img class="germ" src="~/Image" width="40px" /> <i class="created" hidden="hidden">April 3, 2020 13:13:00</i> Document Title </td> <td>PDF</td> <td>March 2020</td> </tr> As you can see, I have a hidden <i> element that designates when the document was posted to the website. I need to remove the <img> tag 6 hours from the time in the <i> tag. How can I do this using jQuery or JavaScript?
This would be better done server-side. The way you want to do it assumes that the user will have this same page up for 6+ hours, or come back to this page in the same state, which is pretty unlikely. What I would do is add a property to the post for created and have it set a default time of Date.now(), and then have front end code look for whether that created value was less than 6 hours ago (1000 * 60 * 60 * 6 miliseconds). If so, show the 'New' graphic. If not, don't. Another way to do it so that you don't have to update server-side stuff that might be more set in stone is to have the default display for the "New" graphic to be true, then: let createdTime = new Date(document.queryselector('i.hidden').textContent); if (Date.now() - createdTime > (1000 * 60 * 60 * 6)){ //code to hide the "New" graphic } A little extra two cents for free: I would add an id attribute to that hidden i element to make sure you're selecting only that and not something else that may have the same class
Since you asked how to do this with JavaScript or JQuery, this is how. I also included a 3-second example to show that it does work. window.setTimeout(function() { document.getElementById('sixHours').outerHTML = ''; }, 2160000); window.setTimeout(function() { document.getElementById('threeSeconds').outerHTML = ''; }, 3000); <div id="sixHours">This will be removed after six hours</div> <div id="threeSeconds">This will be removed after three seconds</div> Keep in mind, that as soon as the page is refreshed, the timer will start over. If you want to avoid this and still have JavaScript handle it, you could have it removed at a definite time. Edit The snippet below will parse the date in expiration and find the milliseconds from that till now. Then like the snippet above, the remove element will get removed when the timer expires. 6 hours are added to the timer to make it expire 6 hours from the given time. var expiration = Date.parse(document.getElementById('expiration').innerHTML); var diff = expiration - Date.now(); window.setTimeout(function() { document.getElementById('remove').outerHTML = ''; }, diff + 2160000); //2160000ms = 6 hours <div id="expiration">April 3, 2020 20:00:00</div> <div id="remove">Will be removed by the date above</div>
Use setTimeout(), but bear in mind that people aren't likely going to sit at a single page for 6 hours meaning this will fail as soon as they navigate away. You'll have to change the time sent over every time they refresh. const testing = true; if (testing) { // BEGIN - Fake date for testing const tmpNow = new Date(); document.querySelector("i.created").innerHTML = tmpNow.toUTCString(); // END - Fake date for testing } const d = document.querySelector("i.created").innerHTML; const dd = new Date(d); if (testing) { dd.setSeconds(dd.getSeconds() + 3); } else { dd.setHours(dd.getHours() + 6); } const ddd = dd.getTime(); const now = Date.now(); if (ddd < now) { console.log("Too late"); } const dt = Math.max(ddd - now, 0); setTimeout(() => { const img = document.querySelector("img.germ"); img.parentNode.removeChild(img); }, dt); <tr class="pointer"> <td> <img class="germ" src="~/Image" width="40px" /> <i class="created" hidden="hidden">April 3, 2020 13:13:00</i> 03.21.2020 GOA - Alaska Businesses Now Eligible for SBA Economic Injury Disaster Loans (2) </td> <td>PDF</td> <td>March 2020</td> </tr>
You don't understand the problem here. As R Greenstreet said it needs to be done server-side. You need a Create Post Date to be sent to UI. Let's assume you have a JSON coming from a server where you can add createDate property of a post form bata base. {createDate: date, name......} You need to compare that date with Date.now() Pseodu Code here: if(createDate + 6 hours >= Date.now()) then hide your Icon.
You will need to use Date to convert the String into a Date Object: new Date("April 3, 2020 13:13:00"); This will create a Date Object, yet since there is no Timezone Offset, the script might assume UTC. Your result might be: "2020-04-03T13:13:00.000Z" So consider specifying a Time Zone. Some browsers will assume the Users local Timezone. $(function() { function getDate(cObj, tz) { if (tz == undefined) { tz = "GMT-07:00"; } var str = cObj.text().trim() + " " + tz; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date var nDt = new Date(str); console.log(str, nDt); return nDt; } function getHoursPast(thn) { // https://stackoverflow.com/questions/19225414/how-to-get-the-hours-difference-between-two-date-objects/19225463 var now = new Date(); return Math.floor(Math.abs(now - thn) / 36e5); } var hours = getHoursPast(getDate($(".created"))); console.log(hours + " have passed since", getDate($(".created"))); if (hours > 5) { $(".germ").remove(); } }); <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <table> <tr class="pointer"> <td> <img class="germ" src="~/Image" width="40px" /> <!-- Would advise better format Example: 2020-04-03T13:00.000-7:00 --> <i class="created" hidden="hidden">April 3, 2020 13:13:00</i> Document Title </td> <td>PDF</td> <td>March 2020</td> </tr> </table> References https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date How to get the hours difference between two date objects? Getting the client's timezone offset in JavaScript
create an automatic bold for table by the ID ?? with javascript
first of all I apologize for my bad English, I want to make a JavaScript for a tabele who makes himself automatically by the ID Bold, just like this one here but the code is not only for weeks for tabele the table has therefore different time input I will when the time is for example 08:00 clock, the tabele from 08:15 to mark Irish always +1 <td id="1">08:00</td> <td id="1">BEKA-KAQANIK</td> </tr> <tr> <td id="2">08:15</td> <td id="2">MEDINA</td> Here is an example but it is only on weekdays http://jsfiddle.net/c5bHx/ var days = 'sunday,monday,tuesday,wednesday,thursday,friday,saturday'.split(','); document.getElementById( days[(new Date()).getDay()] ).className = 'bold'; .bold { font-weight:bold; } <div id="monday">Monday: 12:00-2:00</div> <div id="tuesday">Tuesday: 11:00-3:00</div> <div id="wednesday">wednesday: 12:00-2:00</div> <div id="thursday">thursday: 11:00-3:00</div> <div id="friday">friday: 12:00-2:00</div> <div id="saturday">saturday: 11:00-3:00</div> <div id="sunday">sunday: 12:00-2:00</div>
I'm not sure if I understand your question correctly, but here is an example JSFIDDLE. It might help with what you're trying to accomplish. <table> <tr id="1530"> <td>15:30</td> <td>A</td> </tr> <tr id="1545"> <td>15:45</td> <td>B</td> </tr> <tr id="1600"> <td>16:00</td> <td>C</td> </tr> </table> // Initialize new Date object. var currentDate = new Date(); // Get the hour var currentHour = currentDate.getHours(); // Get the minutes var currentMinute = currentDate.getMinutes(); // Bin the minutes to 15 minute increments by using modulus // For example, xx:33 becomes 30 var minuteBin = currentMinute - (currentMinute % 15); // Create a string that matches the HTML ids var idString = "" + currentHour + minuteBin; // Set the matching div class to 'bold' document.getElementById(idString).className = 'bold'; // Log variables to console for debugging console.log("Time =",currentHour,":",currentMinute,"bin =",minuteBin,"idString =",idString); This example is meant for GMT-0400 (EDT). This will give different results in different time zones. If I've misunderstood anything, please let me know and I will do my best to update my answer. Hope that helps!
Update View After Selecting Date Range (Rails, Javascript)
I have a table that shows sales by event for a bunch of different date ranges (last month, last week, etc.) <% #events.each do |event| %> <tr class="<%= cycle("odd", "even") -%>"> <td class=" "><%= number_to_currency(stripe_to_display(event.sales(VARIABLE_1,VARIABLE_2))) %></td> <td class=" "><%= number_to_currency(stripe_to_display(event.sales(0,0))) %></td> <td class=" "><%= number_to_currency(stripe_to_display(event.sales(7,0))) %></td> <td class=" "><%= number_to_currency(stripe_to_display(event.sales(30,0))) %></td> <td class=" "><%= number_to_currency(stripe_to_display(event.sales)) %></td> </tr> <% end %> That first td row calculates sales based on a CUSTOM date range. An event instance can calculate sales based on two integers (start_day and end_day). (They represent the number of days from today.) And when a date range is selected, this Javascript is called: $(document).ready(function() { $('#sales_date_range').daterangepicker( { format: 'YYYY-MM-DD', startDate: $.now, endDate: $.now }, function(start, end, label) { var now = new Date(); var start_days_ago = (now - start) / 86400000; var end_days_ago = (now - end) / 86400000; start_days_ago = start_days_ago.toFixed(); end_days_ago = end_days_ago.toFixed(); } ); }); Importantly, that last Javascript function calculates start_days_ago and end_days_ago which are what an event instance needs to calculate sales for a custom date period. So my problem: I can figure out the required arguments in JS, but don't know how to get them to the ERB file. I assume it has something to do with AJAX and conceptually this is wrong, but my hours of searching haven't gotten me any closer to a solution.
Figured it out: I created params with the JS days variables: var path = '?start_day=' + start_days_ago + '&end_day=' + end_days_ago and then refreshed the page with the new path: window.location = path; Then my controller has access to the two arguments: #start_day = params[:start_day].to_i #end_day = params[:end_day].to_i
In case you want a more snappy update (not refreshing the whole page), you could also load part of the page in. Keep the changes you made (Using params[:start_day] etc.), but change your javascript to something like: $("#events").load('path/to/action #events', {start_day: start_days_ago, end_day: end_days_ago}); And give your table the id of events. Then only the table it self will update, ajax style. Note that you might have to deal with error handling and that the page url won't update this way.
Reloading using Angular
Hello friends from SO! I'm new into angular, and I'm trying to keep a table always updated with the information comming from a PHP webservice. I'm demanding the information the first time using the following: HTML <div class="block" ng-controller="demandar_informacion" ng-init="visualizacion_masiva()"> <h1 class="block_header">Welcome admin</h1> <p class="block_info"></p> <table> <thead> <tr> <th ng-repeat="header in headers ">{{header}}</th> </tr> </thead> <tr ng-repeat="disponible in disponibles"> <td ng-repeat="(variable, valor) in disponible">{{valor}}</td> </tr> </table> </div> Then I'm using the following code to get the information: Js Angular: function demandar_informacion($scope, $http) { //pedido de visualización masiva $scope.visualizacion_masiva = function() { var address = "http://127.0.0.1/usa/_code/index_records.php" + "?ac=view_all" var pedido = $http({ method: 'GET', url: address }) .success(function(data, status) { $scope.errors = data.error; $scope.headers = data.headers; $scope.disponibles = data.disponibles; $scope.eliminados = data.eliminados; $scope.info = data.info; }); }; } Main Q: Is there any way I could re-send the HTTP packet and update the information every, let's say, 3 or 5 seconds? as It's rapidly changing. Auxiliary: At the same time, this fragment of code, seems to be altering the order of the values I have on the array, or it might be previously altered somewhere in the Angular code. I've checked the PHP and the Json string seems to be in right conditions, but when it comes to printing the values, it completely looses it's native order (shows the elements in an improper / unknown order)... anyone has a clue? <tr ng-repeat="disponible in disponibles"> <td ng-repeat="(variable, valor) in disponible">{{valor}}</td> </tr> Thanks in advance! Chris C. Russo
Update $scope.update = function() { $timeout(function() { $http.get('lol').success(function() { $scope.update(); }); }, 5000); }; Old Simplest way to do this: $interval(function() { demandar_informacion(); }, 5000); buuuuutttt as MichaL pointed out in the comments what will happen is that 5 seconds will get eaten up as it becomes 5, 4, 3, 2, 1, DDOSing yourself due to the time it takes to complete the request. Other ways: Use firebase to wait and call the load function. Long poll your php script.
You can use the $timeout service to call the server every few seconds. Or use websockets to push the changes from the server to your Angular app (with Ratchet, perhaps (http://socketo.me/))
Countdown timer layout - Keith Wood
I'm trying to use the basic .js countdown timer from Keith Wood but am running into troubles when trying to adjust the layout. Because I cannot inspect the element (every time I inspect it it reloads and vanishes so I can't work out what CSS needs to be adjusted). I want it to output as : XX days XX hours xx minutes I tried adding a layout code to the script but it does nothing. <script type="text/javascript"> $(function () { var austDay = new Date(); austDay = new Date(austDay.getFullYear() + 1, 1 - 1, 26); $('#defaultCountdown').countdown({until: austDay}); $('#year').text(austDay.getFullYear()); $('#textLayout').countdown({until: liftoffTime, layout: '{sn} {sl}, {mn} {ml}, {hn} {hl}, and {dn} {dl}'}); }); </script> This part in particular apparently should make it output as I want but it doesn't $('#textLayout').countdown({until: liftoffTime, layout: '{sn} {sl}, {mn} {ml}, {hn} {hl}, and {dn} {dl}'}); }); Here is the live site: username is admin password is gogogo http://www.francesca-designed.me/fyp/
What you need is to define "liftoffTime". Example of missing code: <script> var liftoffTime = new Date(); liftoffTime.setDate(liftoffTime.getDate() + 5); /* 5 days countdown */ </script> *I think in Your case You need to replace "liftoffTime" by "austDay" (since You've defined austDay)
<div id="defaultCountdown" class="hasCountdown"> <span class="countdown_row countdown_show4"> <span class="countdown_section"> <span class="countdown_amount">366</span><br>Days</span> <span class="countdown_section"> <span class="countdown_amount">6</span><br>Hours</span> <span class="countdown_section"> <span class="countdown_amount">57</span><br>Minutes</span> <span class="countdown_section"> <span class="countdown_amount">39</span><br>Seconds</span> </span> </div> There you go! All you do if you get this problem (and assuming you are using google chrome) is righ-click -> inspect Then get the parent container and right click -> copy as HTML and then paste into an editor EDIT To address your code giving the wrong output (and not the CSS layout part - layout: '{mn} {ml}, {hn} {hl}, and {dn} {dl}' just remove the {sn} {sl}