Having some code inside setInterval execute only once - javascript

I have a setInterval call inside my Javascript which checks if there are new notifications for the user. This interval makes an AJAX call and updates the DOM based on the response. This interval is set to repeat every 10 seconds.
There is a little box that needs to popup if there are new notifications and it is inside this interval. In the current code, this box shows up every 10 seconds if there are new notifications that are not marked as seen and that's pretty annoying.
Is there a way to make this little box appear only once per notification set? So for example there are X new notification and after 10 seconds this number didn't change, don't show this box. How do I achieve this? I'm stuck here.
This is how my interval code looks like:
setInterval(function(){
$.get(generate_site_url() + 'user.php?action=get_notifications', function(data) {
response = $.parseJSON(data);
if ('error' in response)
{
return;
}
if (response.notification_array.length == 0)
{
return;
}
$('.user-notification').text(response.notification_count);
$('.no-notes').hide();
var notificationStr = '';
for (var key in response.notification_array)
{
var notification = response.notification_array[key];
var notificationHTML = '<li' + ((notification.notification_seen == false) ? ' style="background: #fffaf1;"' : '') + '>';
notificationHTML += '<a href="' + notification.notification_target + '" id="nid-' + notification.notification_id + '">';
notificationHTML += '<span class="glyphicon glyphicon-' + ((notification.notification_type == 'like') ? 'thumbs-up' : (notification.notification_type == 'dislike') ? 'thumbs-down' : (notification.notification_type == 'favorite') ? 'heart' : 'bell') + '"></span> ';
notificationHTML += notification.notification_message;
notificationHTML += '</a></li>';
notificationStr += notification.notification_message + '<br />';
$('.notifications-dropdown').prepend($(notificationHTML));
}
display_alert(notificationStr, 'danger', 5000, 'bottom'); // This shows the box
});
}, 10000);

I'll expand my original comment answer here.
Set a variable accessible outside the interval function, in which you track the last count of new notifications. Next time the interval runs, compare the counts and check if there are any new ones.
var lastNewMessageCount = 0;
setInterval(function(){
// ajax stuff
if( response.notification_array.length > lastNewMessageCount ){
// show notices
}
lastNewMessageCount = response.notification_array.length;
});

Try making a global Array, then adding a conditional if(response.notification_array.length > nameOfGlobalArray.length) before the execution of display_alert() and update nameOfGlobalArray to match response.notification_array if the conditional returns true, like:
var notificationsArray = [];
setInterval(function(){
$.get(generate_site_url() + 'user.php?action=get_notifications', function(data) {
response = $.parseJSON(data);
if ('error' in response)
{
return;
}
if (response.notification_array.length == 0)
{
return;
}
$('.user-notification').text(response.notification_count);
$('.no-notes').hide();
var notificationStr = '';
for (var key in response.notification_array)
{
var notification = response.notification_array[key];
var notificationHTML = '<li' + ((notification.notification_seen == false) ? ' style="background: #fffaf1;"' : '') + '>';
notificationHTML += '<a href="' + notification.notification_target + '" id="nid-' + notification.notification_id + '">';
notificationHTML += '<span class="glyphicon glyphicon-' + ((notification.notification_type == 'like') ? 'thumbs-up' : (notification.notification_type == 'dislike') ? 'thumbs-down' : (notification.notification_type == 'favorite') ? 'heart' : 'bell') + '"></span> ';
notificationHTML += notification.notification_message;
notificationHTML += '</a></li>';
notificationStr += notification.notification_message + '<br />';
$('.notifications-dropdown').prepend($(notificationHTML));
}
if(response.notification_array.length > notificationsArray.length)
{
display_alert(notificationStr, 'danger', 5000, 'bottom');
notificationsArray = response.notification_array;
}
});
}, 10000);
[EDIT] BotskoNet's method uses less data, and apparently my brain wasn't turned on :P Both will work, though.

Does user.php mark a notification as seen once it has been delivered? I will assume not, but if so you just need to check if new notifications came in and only call the display_alert() if so.
Keeping track of notification count or comparing string is not enough. There are plenty of use cases where this will result in false positives. But I see there is a notification_id field:
var delivered= [];
setInterval(function(){
// ajax stuff
for (var key in response.notification_array){
var notification = response.notification_array[key];
// check if the notification has been delivered
if ($.inArray(notification.notification_id, delivered) === -1){
// notification has not been delivered
delivered.push(notification.notification_id);
// process notification as normal
}
}
// only display the alert if there is something to display...
if (notificationStr.length > 0)
display_alert(...);
}, 10000);

Related

Add class to div in jQuery based on a date

I admit not being so great with JavaScript.
I've been tasked to build a utility that will run a check to see if a campaign date is going to expire in 2 weeks or less and add a class if it's going to.
The date is coming from a service and it's built (datatables map) as follows.
The data is coming back undefined but that's a different issue.
Any feedback would be greatly appreciated because I don't seem to be having any luck whatsoever.
Initially I had a date object in there but wasn't sure it was necessary.
/*HTML Rendered Out for that table cell (there are multiple but this is how it
comes out*/
<td class=" campaign_start_date small-screen small-screen-2-col">06/14/2017 -
<div class="campaign-end-date">06/29/2017</div></td>
JS
//Datatables Code & modified for our project
{title:ax.L(114), class:'campaign_start_date small-screen small-screen-2-col', data:function(row, type, val, meta) {
var campaignEndDate = ax.Utils.deNull(row.campaign_end_date, '');
campaignEndDate = ax.Utils.RFCFormat(campaignEndDate, { excludeTime: true });
var campaignStartDate = ax.Utils.deNull(row.campaign_start_date, '');
campaignStartDate = ax.Utils.RFCFormat(campaignStartDate, { excludeTime: true });
var campaignDateString;
if (campaignEndDate && campaignStartDate ) {
campaignDateString = campaignStartDate + ' - ' + '<div class="campaign-end-date">' + ax.Utils.campaignEndDateAlert(campaignEndDate) + '</div>';
} else {
if (!campaignEndDate && campaignStartDate) {
campaignDateString = campaignStartDate + ' - ? ';
}
else if (!campaignStartDate && campaignEndDate) {
campaignDateString = ' ? - ' + campaignEndDate;
}
else {
campaignDateString = ' ';
}
}
return campaignDateString
//My attempt at doing this from the Utility file - the code that i'm having no luck with.
publicMethods.campaignEndDateAlert = function (data) {
var campaignDateEnd = data.campaign_end_date;
var $orderTable = $('#order-table');
var $campaignDate = $orderTable.find('.campaign-end-date')
if (campaignDateEnd <= campaignDateEnd + 86400000) {
$campaignDate.addClass('green');
}
}

Refreshing / Cycling through a parsed RSS feed every 5 mins

I am working on a monitor signage display and have a "welcome to RSS" feed with just a title and desc. I have code from feedEk that's been tweaked a bit to parse the feed and cycle it so I only have one title and desc. showing at a time. This feed could be added to or deleted info at any time so I need it to refresh every five mins. I've tried several solutions on here and just can't seem to work it out.
Here is the adjusted FeedEk code with comments on the adjustments:
(function (e) {
e.fn.FeedEk = function (t) {
var n = {
FeedUrl: "http://myrss.com/",
MaxCount: 1,
ShowDesc: true,
ShowPubDate: false,
CharacterLimit: 100,
TitleLinkTarget: "_self",
iterate: false
};
if (t) {
e.extend(n, t)
}
var r = e(this).attr("id");
var i;
processFeedData = function (t) {
//This just makes it flash too much
//e("#" + r).empty();
var s = "";
en = t.responseData.feed.entries;
if (n.iterate == true) {
//Setting a variable to store current item
i = window.feedcur = typeof(window.feedcur) === 'undefined' ? 0 : window.feedcur;
t = en[i];
s = makeString(t);
//incrementing the current for the next time we loop through
window.feedcur = ((i+1)%en.length);
} else {
for (i=0;i<en.length;i++) {
t = en[i];
s += makeString(t);
}
}
//Changing this to just replace what was there (less blinky feeling)
e("#" + r).html('<ul class="feedEkListSm">' + s + "</ul>");
}
makeString = function (t) {
s = '<li><div class="itemTitleSm"><a href="' + t.link + '" target="' + n.TitleLinkTarget + '" >' + t.title + "</a></div><br>";
if (n.ShowPubDate) {
i = new Date(t.publishedDate);
s += '<div class="itemDateSm">' + i.toLocaleDateString() + "</div>"
}
if (n.ShowDesc) {
if (n.DescCharacterLimit > 0 && t.content.length > n.DescCharacterLimit) {
s += '<div class="itemContentSm">' + t.content.substr(0, n.DescCharacterLimit) + "...</div>"
} else {
s += '<div class="itemContentSm">' + t.content + "</div>"
}
}
return s;
}
if (typeof(window.feedContent) === 'undefined') {
e("#" + r).empty().append('<div style="padding:3px;"><img src="loader.gif" /></div>');
e.ajax({
url: "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=" + n.MaxCount + "&output=json&q=" + encodeURIComponent(n.FeedUrl) + "&hl=en&callback=?",
dataType: "json",
success: function (t) {
window.feedContent = t;
processFeedData(window.feedContent);
}
});
} else {
processFeedData(window.feedContent);
}
}
})(jQuery)
On the php page I have the following code which cycles through on an interval. I've tried wrapping this into another function that refreshes it but that didn't work. I've also tried just refreshing the page, but that just makes the whole page blink and still doesn't refresh the feed. It seems to refresh every 12 to 24 hours.
<!-- this is for the rss feed -->
<script type="text/javascript" >
$(document).ready(function () {
feedsettings = {
FeedUrl: 'http://myrss.com/',
MaxCount: 100,
ShowDesc: true,
ShowPubDate: false,
DescCharacterLimit: 100,
iterate: true
}
$('#divRss').FeedEk(feedsettings);
setInterval(function(){
$('#divRss').FeedEk(feedsettings);
},7000);
});
</script>
<style>
.rssDiv{float:right; padding-left:35px;}
ul{width:500px !important}
</style>
<!-- end feed stuffs -->
Any help guidance assistance or direction is immensely appreciated. I have to make this self sustaining with little to no extra installations. I've also posted this on code review but I think that may have been the wrong place to post this initially.

How to set my HTML Table progressively with Javascript/AJAX and Java Servlet?

Hy everyone! I've got a problem developping a little webapp.
The goal is to search for a specific word in files from a stating folder on the server.
To do that, I've implemented a recursive algorithm using java.io.File and a BufferReader.
When I get the results, I had them in a table using a script in my jsp file :
// Posting founded files in a table.
var files = response.getElementsByTagName("file");
// -> Creating the results table.
var table = "<table width=\"100%\">\n";
for (var i = 0, c = files.length; i < c; i++) {
// -> Building the number of apparence in each file.
var nb = files[i].getAttribute("nb");
var nbSentence = "";
if (nb == 1) { nbSentence = nb + " time in this file."; }
else { nbSentence = nb + " times in this file."; }
// Building and filling the table.
if (i % 2 == 0) { table += "<tr class=\"pair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
else { table += "<tr class=\"impair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
}
table += "</table>\n";
// -> To end the procedure, we had the table to the right div.
document.getElementById("files").innerHTML = table;
My problem is that with this code, all of the results are printed in one tim in the target table. I would like to see the results comming one by one, everytime a file is found in the algorithm.
I've tried to change the readystate to "3" in the onreadystatestage function :
xhr.onreadystatechange = function() {
if (xhr.readyState >= 3 && (xhr.status == 200 || xhr.status == 0)) {
callback(xhr.responseXML);
document.getElementById("loader").style.display = "none";
document.getElementById("btn").value = "Search";
} else if (xhr.readyState < 3) {
document.getElementById("loader").style.display = "inline";
document.getElementById("btn").value = "Cancel";
}
};
But it doesn't change anything.
Does somebody have an idea? How can I send every founded file one by one ? Do I have t do it in the servlet class ?
The for instruction in the servlet class :
// If the input word name isn't empty, the algorithm is launched.
if (null != wordToSearch && !"".equals(wordToSearch))
{
lstFiles.clear();
searching(new File(contextPath), wordToSearch);
int n = lstFiles.size();
// Priting a message that indicate how many files have been found with the word to search.
emptyFieldMessage = n + " files has been found containing the word '" + wordToSearch + "'!";
output.append("<message>").append(emptyFieldMessage).append("</message>\n");
output.append("<lstFiles>\n");
// Then, files list with :
// - File path in "name" parameter,
// - Number of apparence of the word in "nb" parameter,
// - Formatted path as the value.
for(int i = 0; i < n; i++)
{
output.append("<file name=\"" + lstFiles.get(i) + "\" nb=\"" + lstNbApparence.get(i) + "\" >").append(lstFilesPath.get(i)).append("</file>\n");
}
output.append("</lstFiles>\n");
}
To be more complet, the whole script code :
<script>
// Creating xhr variable.
var xhr = null;
// Creating the "Search" button function.
function request(callback) {
// "Cancel" button case.
if (xhr && xhr.readyState != 0)
{
xhr.abort();
}
// "Search" button case.
else
{
// Calling the good function from external file.
xhr = getXMLHttpRequest();
// Callback and loading icon management.
xhr.onreadystatechange = function() {
if (xhr.readyState >= 3 && (xhr.status == 200 || xhr.status == 0)) {
callback(xhr.responseXML);
document.getElementById("loader").style.display = "none";
document.getElementById("btn").value = "Search";
} else if (xhr.readyState < 3) {
document.getElementById("loader").style.display = "inline";
document.getElementById("btn").value = "Cancel";
}
};
// Calling the Servlet in charge of the recursion algorithm.
var input = encodeURIComponent(document.getElementById("wordName").value);
xhr.open("GET", "/webApp_Search_Merge/ActionServlet?wordName=" + input, true);
xhr.send(null);
}
}
// Creating the reponse function.
function readData(response) {
if (null != response)
{
// Posting the message include in the XML file sending back by the Servlet.
var message = response.getElementsByTagName("message");
document.getElementById("message").innerHTML = message[0].firstChild.nodeValue;
// Posting founded files in a table.
var files = response.getElementsByTagName("file");
// -> Creating the results table.
var table = "<table width=\"100%\">\n";
for (var i = 0, c = files.length; i < c; i++) {
// -> Building the number of apparence in each file.
var nb = files[i].getAttribute("nb");
var nbSentence = "";
if (nb == 1) { nbSentence = nb + " time in this file."; }
else { nbSentence = nb + " times in this file."; }
// Building and filling the table.
if (i % 2 == 0) { table += "<tr class=\"pair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
else { table += "<tr class=\"impair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
}
table += "</table>\n";
// -> To end the procedure, we had the table to the right div.
document.getElementById("files").innerHTML = table;
}
}
Thanks by advance for your help, Thomas.
I tried to set up a working demo, but with no results. I was also searching why I can't find the way to "sleep" a function and re-execute after 1000 milliseconds or whatever you want. Already found an answer to that, but I think it's not really what did you expected:
A sleep function will kill the browser and possibly the machine.
Javascript is single threaded, so the browser will block while this
executes, and the loop itself will just take up a lot of CPU. I’ve
heard of some libraries that actually do sleep correctly in an
asynchronous manner, but I can’t remember the name right now.
This is a very bad idea. JavaScript is single threaded so while that
for loop is running nothing else can execute (js timers, browser
events, even the UI in most browsers). Try to sleep for 5 or more
seconds and the browser will even warn the user that a script is
running slowly.
Just use setTimeout.
Also speaks about a sleep function into Native Javascript. It seems that it's like a framework or something like that. You can download it and try it at your own. I can't say anything about this because I've never tested, it's just what I found on internet.
I'm sorry to give you bad news.

IE not loading XML content until I open Developer tools?

I have a page that loads product information from an XML file using a jQuery AJAX get request. This works well in FF and Chrome however the content doesn't load in IE. It will however load the data after opening the developer window and refreshing the page! Does anyone know why?
Here is my jQuery AJAX request:
//Load the xml file
$.ajax({
type: "GET",
url: "xml/" + cat + ".xml",
dataType: ($.browser.msie) ? "text" : "xml",
success: function(data) {
alert('xml successfully loaded');
var xml;
if (typeof data == "string") {
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = false;
xml.loadXML(data);
} else {
xml = data;
}
//Get total number of products in the category
$(xml).find('dataroot').each(function() {
var pTemp = $(this).attr('count');
catName = $(this).attr('catTitle');
console.log(catName);
pTotal = Number(pTemp);
});
//Fill the correct entries onto the page
while (count<=pTotal) {
$(xml).find('product').each(function() {
if (count>lCounter && count<hCounter) {
var pName = $(this).find('ProductName').text();
var pImage = $(this).find('Photo').text();
var pCode = $(this).find('ProductCode').text();
var pDesc = $(this).find('WebDescription').text();
if (cat.substring(0,2)=='cs') {
var pPrice = $(this).find('PartyShackPrice').text();
} else { var pPrice = $(this).find('RRP').text(); }
var pSize = $(this).find('size').text();
var pLink = '<a href="item.html?'+cat+'-'+pCode+'">';
var pHTML = '<div id="'+pCode+'" class="box">';
pHTML += pLink + '<img src="images/SMALL_IMAGE/' + pImage + '" width="70" height"100" /></a>';
pHTML += '<div class="boxText">';
pHTML += pLink + '<div class="boxTitle">'+pName+'</div></a>';
pHTML += '<div class="boxDesc">'+pDesc+'</div>';
if (pSize !== 'Not Applicable') { pHTML += '<div class="boxSize">'+pSize+'</div>'; }
pHTML += '<div class="boxPrice">£'+pPrice+'</div>';
pHTML += pLink + '<div class="boxBuy"></div></a>';
pHTML += '</div></div>';
$("#products").append(pHTML);
}
count +=1;
});
}
//Work out the total number of pages the product list is split up into
if (pTotal%50==0) { pageTotal = pTotal/50; }
else { pageTotal = Math.floor(pTotal/50) + 1; }
console.log('pageTotal - ' + pageTotal);
//Show path of the current page
getPath(cat, catName, 0);
//Depending on page number show previous and next buttons and display product counter
if (pageTotal==1) { //page 1 and only one page
$("#prev").css("visibility", "hidden");
$("#next").css("visibility", "hidden");
$("#counter").append('1 - ' + pTotal + ' of ' + pTotal);
} else if ((pageNum==1) && (pageTotal!=1)) { //page 1 and multiple pages
$("#prev").css("visibility", "hidden");
$("#next").append('Next >>');
$("#counter").append('1 - 50 of ' + pTotal);
} else if ((pageNum==pageTotal) && (pageTotal!=1)) { //last page when theres more than 1 page
$("#next").css("visibility", "hidden");
$("#prev").append('<< Previous');
$("#counter").append((((pageNum-1)*50)+1) + ' - ' + pTotal + ' of ' + pTotal);
} else { // a middle page
$("#next").append('Next >>');
$("#prev").append('<< Previous');
$("#counter").append((((pageNum-1)*50)+1) + ' - ' + (pageNum * 50) + ' of ' + pTotal);
}
//Display page number
$("#currentPage").append(' ' + pageNum + ' of ' + pageTotal);
},
error: function() { alert('failure'); }
});
});
Also IE should call either the success alert or the error alert however it does neither until opening the developer window and refreshing the page.
Thanks
I knew what the problem was just by reading the title of your question on the SO main page. And reading the code in the question confirms it. The problem you have is the line console.log(catName);
IE (and some other browsers) don't initialise the console object until the developer window is opened.
Prior to this, trying to use console will return undefined, and will cause your script to stop running.
The first lesson here is not to leave debugging code in your program after you're done with it. Calls to the console should only be there while you're testing the program; when you've finished with them, take them out.
The second lesson is that if you do need to have console calls in your code, you should wrap them in code that checks if console exists before it tries to use it. There are a number of ways to do this, from a simple if(console) {console.log(...);} all the way through to writing your own debugging class. How you do it is up to you, but it is generally a good idea to write all console code this way, even when you're just doing a bit of debugging, to avoid the kind of issue you're having here.
Hope that helps.
Let jQuery do what it does best. Replace all of this:
dataType: ($.browser.msie) ? "text" : "xml",
success: function(data) {
alert('xml successfully loaded');
var xml;
if (typeof data == "string") {
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = false;
xml.loadXML(data);
} else {
xml = data;
}
...
With this:
dataType: "xml",
success: function(xml) {
alert('xml successfully loaded');
...

retrieving the twitter search feeds dynamically using ajax

Long back I used JSON and was successful to get the hash tag feeds from twitter and facebook. But presently I am just able to get the feeds but its not being updated constantly that means it not been update dynamically. I guess I need to ajaxify it, but I am not able to do that since I am not aware of ajax. Here is the code which I have used to get the twitter search feeds.
$(document).ready(function()
{
$("#Enter").click(function(event){
var searchTerm = $("#search").val() ;
var baseUrl = "http://search.twitter.com/search.json?q=%23";
$.getJSON(baseUrl + searchTerm + "&rpp=1500&callback=?", function(data)
{
$("#tweets").empty();
if(data.results.length < 1)
$('#tweets').html("No results JOINEVENTUS");
$.each(data.results, function()
{
$('<div align="justify"></div>')
.hide()
.append('<hr> <img src="' + this.profile_image_url + '" width="40px" /> ')
.append('<span><a href="http://www.twitter.com/'
+ this.from_user + '">' + this.from_user
+ '</a> ' + makeLink(this.text) + '</span>')
.appendTo('#tweets')
.fadeIn(800);
});
});
});
});
function makeLink(text)
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
return text.replace(exp,"<a href='$1'>$1</a>");
}
The code below should help you. What I've done is moved the code which fetches the tweets into a function. This function is then called every X seconds to update the box. When the user enters a new search term and clicks "Enter", it will reset the timer.
var fetchSeconds = 30; //Number of seconds between each update
var timeout; //The variable which holds the timeout
$(document).ready(function() {
$("#Enter").click(function(event){
//Clear old timeout
clearTimeout(timeout);
//Fetch initial tweets
fetchTweets();
});
});
function fetchTweets() {
//Setup to fetch every X seconds
timeout = setTimeout('fetchTweets()',(fetchSeconds * 1000));
var searchTerm = $("#search").val();
var baseUrl = "http://search.twitter.com/search.json?q=%23";
$.getJSON(baseUrl + searchTerm + "&rpp=1500&callback=?", function(data) {
$("#tweets").empty();
if (data.results.length < 1) {
$('#tweets').html("No results JOINEVENTUS");
}
$.each(data.results, function() {
$('<div align="justify"></div>').hide()
.append('<hr> <img src="' + this.profile_image_url + '" width="40px" /> ')
.append('<span>' + this.from_user + ' ' + makeLink(this.text) + '</span>')
.appendTo('#tweets')
.fadeIn(800);
});
});
}
function makeLink(text) {
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
return text.replace(exp,"<a href='$1'>$1</a>");
}
Hope this helps

Categories