NodeJS / jQuery - Poll notifications API - javascript

I have the following JSON data in an API:
[
{
notification: "'James' has created a new user. This requires
approval",
read: null
}
]
I have the following jQuery:
$.ajax({
dataType: "json",
url: "/api/notifications",
success: function(data) {
counterText = 0;
$.each(data, function(index, value) {
if(value.read == 0 || value.read == null)
{
var theCounter = parseInt($('.counter').text());
counterText += theCounter += 1;
}
});
$('.counter').text(counterText);
}
});
The problem is that this only works when someone refreshes the browser. I am using Socket.io in order to do real-time notifications, however, instead of each notification coming in, I just ideally need to update this code each time a socket comes in. For example, an event called "Ping"
socket.on("test-channel:App\\Events\\Ping", function(message) {
$.toast({
heading: 'Information',
text: message.data.message,
icon: 'info',
loader: false, // Change it to false to disable loader
loaderBg: '#9EC600' // To change the background
});
});
There are, however, a lot of events so I don't really want to have to update on each on. Ideally, I would like instant polling on this file so that notifications can updated immediately without the need of refreshing the browser.

To paraphrase, it sounds like you'd like to add a polling mechanism to your AJAX approach. (Sockets can have advantages such as reduced latency, but they can be slightly more complex, so I understand why you may not want to try them at this time.) All your current AJAX code lacks is really just a mechanism to make continual requests on an interval. You can do that with:
var polling = true;
var period = 60 * 1000; // every 60 seconds
var interval = polling && setInterval(function() {
if (polling) {
$.ajax({
... // existing ajax call here
});
} else {
if (interval) {
clearInterval(interval);
}
}
}, period);
// Later, if you want to stop polling, you can:
polling = false;
// ...or even just:
if (interval) {
clearInterval(interval);
}

Related

How to avoid multiple AJAX calls after setTimeout

I have a text field in which I respond to typing by checking the database for the number of matches, but I don't want to pummel the database with too many queries for no reason if the user types several characters quickly.
Searching the web, the advice seems to be to wrap it all in setTimeout(), but I apparently don't understand how to use it properly. Here is my code at the moment:
$(".qs-text").keyup(function() {
if ($(this).val().length > 2) {
setTimeout(function() {
$.get("ajax_request.php?req=Quicksearch&qs=" + $(".qs-text").val(), function(data) {
$('.qs-hits').text(data);
});
}, 500);
} else {
$('.qs-hits').text('-');
}
});
It does wait 500ms, and at the end of the timeout period, it does use the final state of the field in the request - good.
However then it sends multiple identical requests (one for every character I typed) instead of just one. That defeats the purpose of having the timeout in the first place. I can almost see why the code would do that, since the keyup event fires every time, but I have no idea how to solve it. There are other questions whose titles sound like what I'm asking, but every one I've read is different enough that I can't quite apply any of them to my case.
You need cancel timeout when create a new.
var timeout = null;
$(".qs-text").keyup(function() {
if(timeout != null) clearTimeout(timeout);
if ($(this).val().length > 2) {
timeout = setTimeout(function() { $.get("ajax_request.php?req=Quicksearch&qs="+$(".qs-text").val(), function(data) {
$('.qs-hits').text(data);
}); },500);
} else {
$('.qs-hits').text('-');
}
});
We usually store the timeout in variable and then clear it conditionally when call a new one. However for large web application, I suggest using web sockets for such subsequent calls for real-time experience
var timer;
$(".qs-text").keyup(function() {
if ($(this).val().length > 2) {
clearTimeout(timer);
timer = setTimeout(function() {
$.get("ajax_request.php?req=Quicksearch&qs=" + $(".qs-text").val(), function(data) {
$('.qs-hits').text(data);
});
}, 500);
} else {
$('.qs-hits').text('-');
}
});
I would recommend using something like lodash for debouncing, so you can do something like this
$(".qs-text").keyup(function() {
_.debounce(()=> {
$.get("ajax_request.php?req=Quicksearch&qs="+$(".qs-text").val(), function(data) {
$('.qs-hits').text(data);
})
}, 500)
});
for more info, https://lodash.com/docs/4.17.15#debounce

Fire an event when an NFC card is presented

I am attempting to build a webapp on a Chromebook, I need it to read RFID card serial numbers with an ACR122U NFC. I am using chrome-nfc.
I am reading cards happily, but I do not know how to fire an event when a card is presented.
Are there any events in chrome-nfc I can use to know when a card has been presented to the reader?
EDIT: I have been trying to use chrome.nfc.wait_for_tag, but it does not behave as I would expect.
// With a card on the reader
chrome.nfc.wait_for_tag(device, 10000, function(tag_type, tag_id){
var CSN = new Uint32Array(tag_id)[0];
console.log ( "CSN: " + CSN );
});
[DEBUG] acr122_set_timeout(round up to 1275 secs)
DEBUG: InListPassiveTarget SENS_REQ(ATQA)=0x4, SEL_RES(SAK)=0x8
DEBUG: tag_id: B6CA9B6B
DEBUG: found Mifare Classic 1K (106k type A)
[DEBUG] nfc.wait_for_passive_target: mifare_classic with ID: B6CA9B6B
CSN: 1805372086
// with no card on the reader
chrome.nfc.wait_for_tag(device, 10000, function(tag_type, tag_id){
var CSN = new Uint32Array(tag_id)[0];
console.log ( "CSN: " + CSN );
});
[DEBUG] acr122_set_timeout(round up to 1275 secs)
DEBUG: found 0 target, tg=144
Both return the results as above immediately, it does not seem to matter what number I use for a timeout...
If I call the function with no card on the reader, and then immediately put the card on the reader after function call, I get no output in the console.
I'm not familiar with chrome-nfc, but taking a shot in the dark by reverse engineering the source, it looks like you would want to use the wait_for_tag method, like:
chrome.nfc.wait_for_tag(device, 3000, function(tag_type, tag_id) {
// Do your magic here.
});
...Where device is your reader, 3000 is the maximum time to wait (in ms), and replacing // Do your magic here. with your desired logic. If it times out, both tag_type and tag_id will be null.
If you wanted to wait indefinitely, you could just recursively call a function with the above code. Example:
function waitAllDay(device) {
chrome.nfc.wait_for_tag(device, 1000, function(tag_type, tag_id) {
if(tag_type !== null && tag_id !== null)
{
// Do your magic here.
}
waitAllDay(device);
});
}
That's assuming you want it to continue waiting even after a tag has been presented. Wrap the waitAllDay(device); in an else if you want it to stop once a tag is read.
UPDATE: It seems the wait_for_tag method does not work as intended, so I'm proposing a second solution. I'm leaving the existing solution in place in case the method is fixed by the developers of chrome-nfc.
Another thing to try is to use chrome.nfc.read, passing in a timeout option, inside a window.setInterval.
var timer = window.setInterval(function () {
chrome.nfc.read(device, { timeout: 1000 }, function(type, ndef) {
if(!!type && !!ndef) {
// Do your magic here.
// Uncomment the next line if you want it to stop once found.
// window.clearInterval(timer);
}
});
}, 1000);
Be sure and call window.clearInterval(timer) whenever you want it to stop watching for tags.
While I do not consider this a proper solution; here is a workaround I am using for the time being.
function listen_for_tag(callback, listen_timeout){
var poll_delay = 400; //ms
var listen_loop = null;
if(!listen_timeout){
listen_timeout = 99999999;
}
function check_for_tag(){
if(listen_timeout < 0) {
clearInterval(listen_loop);
console.log("we didnt find a tag. finished");
}
chrome.nfc.wait_for_tag(dev_manager.devs[0].clients[0], 10, function(tag_type, tag_id){
console.log ( "FOUND A TAG!!" );
clearInterval(listen_loop);
// handle the callback (call it now)
var C = callback;
if (C) {
callback = null;
window.setTimeout(function() {
C(tag_type, tag_id);
}, 0);
}
});
listen_timeout -= poll_delay;
}
listen_loop = setInterval(check_for_tag, poll_delay);
}

Strophe.js client connecting to server, disconnect/timeout

I have a little JavaScript XMPP client, written with Strophe, that connects to a server hosted on hosted.im. I think hosted.im uses ejabberd on their backend.
I establish the connection using
Strophe.Connection(myBoshService), and am able to send chat messages back and forth. However, after a certain time, it seems, there is an automatic disconnect if there is no activity.
Now, my question is, what would be a good way to keep the session active, so that it does not disconnect. Disconnect time seems to be very short, about 60 seconds or so.
Should I send some kind of activity back and forth to keep it open? Or, which seems simpler to me, should I somehow change the timout of the session. If so, where can I change this? Is this a server-setting, irregardless of the Strophe.Connection object, or can I set the timeout when initializing Strophe.Connection?
Thanks for any and all help.
Best regards,
Chris
Edit: Here is the code I use for connecting:
I manage the connection through a global variable Hello (yes, name is awkward, I took it from an example):
var Hello = {
connection: null,
start_time: null,
partner: {
jid: null,
name: null
},
log: function (msg) {
$('#log').append("<p>" + msg + "</p>");
},
send_ping: function (to) {
var ping = $iq({
to: to,
type: "get",
id: "ping1"}).c("ping", {xmlns: "urn:xmpp:ping"});
Hello.log("Sending ping to " + to + ".");
console.log("Sending ping to " + to + ".");
Hello.start_time = (new Date()).getTime();
Hello.connection.send(ping);
},
handle_pong: function (iq) {
var elapsed = (new Date()).getTime() - Hello.start_time;
Hello.log("Received pong from server in " + elapsed + "ms.");
console.log('Received pong from server in " + elapsed + "ms.');
$('#login').hide();
$('#chat').show();
//window.location = "chat.html";
//Hello.connection.disconnect();
return true;
},
//"<active xmlns="http://jabber.org/protocol/chatstates"/><body xmlns="http://jabber.org/protocol/httpbind">tuiuyi</body>"
displayIncomingText: function (text) {
var body = $(text).find("xml > body");
if (body.length === 0)
{
body = $(text).find('body');
if (body.length > 0)
{
body = body.text();
$('#chattext').append("<p>"+ body + "</p>");
}
else
{
body = null;
}
}
return true;
},
readRoster: function (iq) {
$(iq).find('item').each(function () {
var jid = $(this).attr('jid');
var name = $(this).attr('name') || jid;
Hello.partner.name = name;
Hello.partner.jid = jid;
});
return true;
}
};
The main relevant objects here are Hello.connect and Hello.partner, which stores the jid of the only person on the accounts roster, as this is a one to one chat.
Then, in $(document).ready, I bind two buttons to connect and send messages respectively:
$(document).ready(function () {
$('#chat').hide();
$('#chatSend').bind('click', function () {
Hello.connection.send(
$msg(
{to : Hello.partner.jid, type : 'chat'}
).c('body').t($('#chattextinput').val())
);
$('#chattext').append("<p align='right'>" + $('#chattextinput').val() + "</p>");
});
$('#SignIn').bind('click', function () {
$(document).trigger('connect', {
jid: $('#eMail').val(), password: $('#password_f').val()
}
);
});
});
Clicking the sign-in button triggers the event "connect":
$(document).bind('connect', function (ev, data) {
console.log('connect fired');
var conn = new Strophe.Connection("http://bosh.metajack.im:5280/xmpp-httpbind");
conn.connect(data.jid, data.password, function (status) {
console.log('callback being done');
if (status === Strophe.Status.CONNECTED) {
alert('connected!');
$(document).trigger('connected');
alert('Connected successfully');
} else if (status === Strophe.Status.DISCONNECTED) {
$(document).trigger('disconnected');
}
else
{
Hello.log("error");
console.log('error');
}
});
Hello.connection = conn;
});
This creates the Strophe.Connection and stores it in Hello.connection. Also, it sets the callback function of the connection object. This code is taken straight from an example in a Strophe.js book. Anyway, the callback checks the status of the connection, and if status === Strophe.Status.DISCONNECTED, triggers "disconnected", which only does this:
$(document).bind('disconnected', function () {
Hello.log("Connection terminated.");
console.log('Connection terminated.');
// remove dead connection object
Hello.connection = null;
});
Anyway, what is happening is that, for some reason, in the callback set with conn.connect, after a short time, the status evaluates to Strophe.Status.DISCONNECTED, and I am not sure why, unless somewhere, either in the server or in the connection object, there is a timeout specified which seems to be ca. 60 seconds.
As to a log of the stanzas going back and forth, I guess I would need to quickly write a handler to see all incoming stanzas, or is it possible to see a log of all stanzas between the client and server in ejabberd?
For the sake of other people who come upon this and have a similar problem, the solution in this case was that the servers at hosted.im send a ping request every 60 seconds to check if the client is still online.
This ping request looks like this:
<iq from="testserver.p1.im" to="chris#testserver.p1.im/23064809721410433741569348" id="164323654" type="get"> <ping xmlns="urn:xmpp:ping"></ping> </iq>
What is needed, of course, is to form a response, which will look something like this:
<iq from="chris#testerver.p1.im" to="testserver.p1.im" id="164323654" type="result" xmlns="jabber:client"><ping xmlns="urn:xmpp:ping"/></iq>
Note the "to"-attribute. I omitted it at the beginning as I was under the assumption a message sent with no to-attribute is automatically assumed to be a client->server message. Not in this case however. Not sure if this is the case in general, or whether it is an oddity of servers at hosted.im.
Thanks to everyone for their comments and suggestions!
Best regards,
Chris

how to design an elegant js polling routine?

I have a requirement where I need to poll the database via ajax from js to check for a status. If the status is "active" then the polling should stop and an alert should popup "case is now active". The js should check the db every 2 seconds until the db status returns "active." Can you provide an elegant js routine for this? Here's some general js to show what I want to do:
function ReportAsActivePoll()
{
for(var i=0; i<10; i++)
{
setTimeout(StatusIsActive,(i*2000));
if(statusIsActive)
{
ReportAsActive();
break;
}
}
}
var statusIsActive = false;
function StatusIsActive(case)
{
statusIsActive = GetStatusFromDB(case) == "active";
}
function ReportAsActive()
{
alert("case is now active")
}
A few notes:
I know the code above is not correct. It's just for illustrative purposes.
The code above will call StatusIsActive 10 times. I would like the calls to stop/break/discontinue after status is active. However, I think polling requires to queue up all the calls ahead of time so I'm not sure how to achieve this.
Use setInterval() and clearInterval() for simplicity. Like so:
<script type="text/javascript">
function checkStatus(theCase) {
var intervalId = window.setInterval(function() {
if (getStatusFromDb(theCase) == 'active') {
clearInterval(intervalId)
reportAsActive()
}
}, 2000)
}
function reportAsActive()
{
alert("case is now active")
}
var tmpCounter = 0
function getStatusFromDb(theCase)
{
if (tmpCounter++ == 4) return "active"
}
checkStatus('case 123')
</script>
You should also consider making functions start with a lowercase letter, because that is the normal JS convention. By choosing another style, you risk having case-sensitive errors that are annoying to track down.
You need to use setInterval instead of your setTimeout and when you received a valid response you have to remove this interval with clearInterval.
So you need to do something like this
var intervalID = window.setInterval(function(){
var resFromYourDB = ...; // get your result via ajax
if (resFromYourDB['active']){
window.clearInterval(intervalID);
// do you alert
}
}, 2000)
This way it will be polling your server till it will get active as a response and not a predefined amount of time as with setTimeout. Also when it will get this response it will properely stops.

getJSON requests looping through an array of parameters with delay between each call

Can anyone help me understand why the following jQuery/Javascript code, rather than running at a rhythmic 1-per-second-ish beat rate, instead has this cascading avalanche of ajax calls (slow to many-per-second)?
var i = 0, l = data.length;
function geocode() {
$.getJSON(
'https://maps.googleapis.com/maps/api/geocode/json',
{
key: "xxxxx",
sensor: false,
address: data[i][3],
region: 'gb'
},
function(d, textStatus, jqXHR) {
if(d["status"] == "OK") {
console.log(data[i][3]);
console.log(d["results"][0]["geometry"]["location"]);
i++;
if(i < l) { window.setInterval(geocode, 1000); }
}
}
);
}
geocode();
In my head this flows thus:
Call geocode the first time
Ajax request is made
On success (which is an arbitrary amount of time later) I read the results
Increment the index
If we've not yet expended the array, set up another call to geocode to start in 1 second
For reference: "data" is a nested array of UK postcodes which I'm trying to retrieve coordinates for using Google's geocoding API.
You keep setting a new interval and never cancel the previous one. You should either cancel the interval using clearInterval() or use a one off setTimeout.
If you use an interval then when you set the interval save the value:
var intervalId;
....
intervalId = setInterval(...);
then
clearInterval(intervalId);
when you need a new interval.
OR use setTimeout() and reissue as required.

Categories