Dynamically update table rows with SocketIO - javascript

My intent: Build makeshift queue-ing system backed by socketIO. I am dynamically populating my table. Each row has a unique identifier. I thought it was as simple as once a user clicks a button on a given row, to send a socket emit event to the server and then have the server send an emit event back to the client side and whosoever was listening for that particular event, it would remove that row for them.
What actually Occurs: The socket workflow works, however it will ONLY remove the button on the person's browser who selected it. It does not send the emit event to EVERYONE in the room. The way I have designed it, is that anyone who visits that page joins a room called, "queue_room". My idea behind this was so that anyone in this room, would all receive the same updates in realtime. You will also see that I am testing with trying to remove row_0, which represents a particular row, but still it does not work as intended..
My overarching goal is build out a realtime queue-ing system, but this is not working out well in my favor.
My ask: Can someone please help me resolve this issue and/or is there another suggested direction that you all recommend? Also, I am using MONGODB, as my backend database if that is at all helpful. Thanks!!
CLIENT SIDE TABLE(JADE):
div(class= "the_results", style = "text-align: center;")
table.table.table-striped.table-dark
thead
tr
th(scope='col')
th(scope='col') Name
th(scope='col') Email
tbody
- var n = 0
- var x = 0
for item in json
tr(id = 'row_#{x++}')
td
button.btn.btn-primary.request_button_attributes(class = 'sendRequest', id='#{n++}' type = 'submit', value = '#{item.room}') Send Request
td #{item.name}
td #{item.email}
script(src="/socket.io/socket.io.js")
script.
function removeRow() {
$('#row_0').hide()
}
var socket = io.connect('http://localhost:6969');
socket.emit('subscribe', {
room: "queue_room",
name: '#{user.name}'
})
$(document).ready(function() {
$('.sendRequest').each(function() {
$(this).click(function() {
//$(".the_results").hide();
var roomNumber = $(this).attr('value');
var val = $(this).attr('id').toString();
var URL = 'http://localhost:6969/results/';
var obj = {
room: roomNumber
};
socket.emit('dequeue', {
room: "queue_room",
id: val
})
socket.on('dequeue', function(data) {
removeRow()
})
$.ajax({
url: URL,
type: "POST",
data: JSON.stringify(obj),
contentType: "application/json",
success: function() {
console.log('The AJAX is working as intended')
},
error: function() {
console.log("CMON! nabbit, ya gotta issue with ur ajax request")
}
});
});
});
});
SERVER SIDE SOCKET FUNCTIONALITY:
socket.on('dequeue', function(data) {
console.log("broadcast to " + data.room)
io.sockets.in("queue_room").emit('dequeue', {
room: data.room,
id: data.id
})

I only listened for the socket event when the button was clicked. Inatead place the listen event outside the button click such that anyone who visits the page is able to see updates on the page.

Related

How to check message status "message seen " in chat using jQuery

I have a chat app created using PHP, mySQL and jQuery. It's working fine for me. But now I want to add the "message seen" feature whenever the receiver sees the message. Or It can be a "tick" like feature as done in WhatsApp. The problem is that I don't know how to achieve this.
Here's the script which only works up to sending and receiving messages between users. What I have to do to implement this?
$ = jQuery;
var currentID = null;
var chatTimer = null;
var oldhtml = "";
function fetch_data() {
$.ajax({
url: "select.php",
method: "POST",
success: function(data) {
$('#live_data').html(data);
}
});
}
function fetch_chat() {
$.ajax({
url: "fetch_chat.php",
method: "POST",
data: {
id: currentID
},
dataType: "text",
success: function(data) {
$("#chatbox").show();
$('#messages').html(data);
$("div.area").show();
if (oldhtml !== data) {
$('#messages').scrollTop($('#messages')[0].scrollHeight);
}
oldhtml = data;
}
});
}
$(document).ready(function() {
fetch_data();
setInterval(function() {
fetch_chat();
}, 500);
$(document).on('click', '.first_name', function() {
currentID = $(this).data("id1");
fetch_chat();
});
$("#sub").click(function() {
var text = $("#text").val();
$.post('insert_chat.php', {
id: currentID,
msg: text
}, function(data) {
$("#messages").append(data);
$("#text").val('');
});
});
});
you need a flag in your messages table,
when receiver fetches some messages, the status of these messages should be set to "seen", or if you want you can do this with ajax call after that the receiver opens the chat box or any event happened (like receiver clicks on chat box).
in chat boxes you must set id for every message, and every time you retrieve messages or check for new messages, you also must check "unseen" messages and send status of messages beside the message, and with your javascript,you must change class of these messages to "unseen" and other messages to "seen"
I assume for a message to be "seen" it has to be visible from the chat html node($("#messages") in your case), meaning for some reason it can be hidden(e.g: another chat html node "active" in case there are several and only one can be active at a time, or maybe browser tab out of focus, or even the very message is out of the scroll view of the chat html node ...).
So, why not just add events listeners to it, listening whether its gets the "active" state or to the browser tab focus... When conditions met, just do an ajax query that will change the status(received, read(in this case) ...) of the message in the database by its id(assuming each message has a unique id set on it). Of course there should be a timer retreiving messages status, by then, in the sender side, you select read messages by their id and manage to get them "tick"ed as will, and even do something else.

Email subscription redirect issue with w3-include-html

I am testing using the w3-include-html library in order to avoid hard coding certain code blocks that are used frequently such as the menu bar, footer, contact form, etc. on a website I am working on. At first I encountered an error with the mobile menu bar that I found a solution for HERE. I was able to change the on click event listener that I was using for $('body').on('click','.navbar-toggle',function() { as instructed by the solution.
The remaining problem is that at first the email subscribe field was able to avoid redirecting a blank page that would say "You have subscribed successfully." and simply show a green check mark. After using w3-include-js it now redirects to this blank page with the text. While looking through some of the js functions I found this code:
$('.ajax-form').on('submit', function(event) {
event.preventDefault();
});
$('.form-required').each(function() {
var form = this;
var formname = this.id;
var $form = $(form);
if($form.data('ajaxInProcess')) {
return;
};
$form.data('ajaxInProcess', true);
$.ajax({
url: form.action,
type: form.method,
data: $(form).serialize(),
success: function(response) {
var responseObject = {};
if (typeof response === 'string') {
responseObject = JSON.parse(response);
} else {
responseObject = response;
}
var statusText = responseObject.status;
if (formname == 'subscribe') {
$('#subscribe-button').removeClass('successful');
} else if (formname == 'subscribe2') {
$('#subscribe-button2').removeClass('successful');
}
I believe that this is the code that needs to be edited in order to get the email subscribe working again with w3-include-html. I am hoping someone here is able to help me in applying the solution above to this code that I have included. Any help here is greatly appreciated.
You need to delegate the submit event as well
$('body').on('submit','.ajax-form',function(event) {
event.preventDefault();
});

Jquery- jtable with back batton press

Jtable pagination is not working if I am pressing back button.
I have some 4 option in menu. First option is home and last is report. When I am clicking on report, getting a list which I am displaying by using jtable. After clicking page 1,2,3,4,10,20 new page come. But after pressing back button previous should display. For that I modified some code of jtable api.
/* Performs an AJAX call to reload data of the table.
*************************************************************************/
_reloadTable: function (completeCallback) {
var self = this;
//Disable table since it's busy
self._showBusy(self.options.messages.loadingMessage, self.options.loadingAnimationDelay);
//Generate URL (with query string parameters) to load records
var loadUrl = self._createRecordLoadUrl();
//Load data from server
self._onLoadingRecords();
self._ajax({
type:'GET',
url: loadUrl,
cache : false,
data: self._lastPostData,
success: function (data) {
var historyData = self._lastPostData;
historyData.url=loadUrl;
history.pushState(stringifyObject(self),'List',window.location.href);
location.hash = loadUrl;
self._hideBusy();
//Show the error message if server returns error
if (data.Result != 'OK') {
self._showError(data.Message);
return;
}
//Re-generate table rows
self._removeAllRows('reloading');
self._addRecordsToTable(data.Records);
self._onRecordsLoaded(data);
//Call complete callback
if (completeCallback) {
completeCallback();
}
},
error: function () {
self._hideBusy();
self._showError(self.options.messages.serverCommunicationError);
}
});
},
And added one more method
window.onhashchange = function() {
//console.log(JSON.stringify(eval("(" + history.state + ")"));
if(history.state!=null){
var self = JSON.parse(history.state);
alert(self._createRecordLoadUrl());
alert(self.state._lastPostData);
self._reloadTable(completeCallback);
}
}
I am not able to call these method because self is not jtable object.
Please provide better solution.

Add/change session variable only on click on an element

On my web i have a button. On click on it i want to add a var called key in clients $_SESSION array.. I`m doing it with AJAX like so:
$('button').click(function() {
$.get('engine.php', {key: 1}, function(data) {
console.log('You grabbed the key..');
});
});
In engine.php i`m doing this:
if(!empty($_GET['key'])) {
session_start();
$_SESSION['key'] = true;
}
But it is not good for security reasons.. Every user can type in console a get request and get this var.. How should i do it so the user can get this var only by clicking on a button ?

Creating ajax request loop within an 'each' function

This topic is covered in a few other questions, but I had some difficulty applying the suggested approaches into this use case. I have a checkbox list, where a user can select n sub-sites to publish their post to. since this list could grow to be 100+, I need an efficient way to perform an expensive task on each one. It's okay if it takes awhile, as long as Im providing visual feedback, so I planned to apply an "in progress" style to each checkbox item as its working, then move to the next item int he list once it is successfully published. Also note: I'm working in the WordPress wp_ajax_ hook but the PHP side of things is working well, this is focused on the JS solution.
This code is working right now (console.logs left in for debug), but I've seen multiple warnings against using async: true. How can I achieve a waterfall AJAX loop in a more efficient way?
//Starts when user clicks a button
$("a#as_network_syndicate").click( function(e) {
e.preventDefault(); //stop the button from loading the page
//Get the checklist values that are checked (option value = site_id)
$('.as-network-list').first().find('input[type="checkbox"]').each(function(){
if($(this).is(':checked')){
blog_id = $(this).val();
console.log(blog_id+' started');
$(this).parent().addClass('synd-in-progress'); //add visual feedback of 'in-progress'
var process = as_process_syndication_to_blog(blog_id);
console.log('finished'+blog_id);
$(this).parent().removeClass('synd-in-progress');
}
});
});
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
var result = as_syndicate_to_blog(data);
console.log('end 2nd func');
return true;
}
function as_syndicate_to_blog(data){
$.ajax({
type : "post",
dataType : "json",
async: false,
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id},
success: function(response) {
if(response.type == "success") {
console.log(response);
return response;
} else {
}
},
error: {
}
});
}
Indeed, doing synchronous AJAX request is bad because it will block the browser during the whole AJAX call. This means that the user cannot interact with your page during this time. In your case, if you're doing like 30 AJAX calls which take say 0.5 seconds, the browser will be blocked during 15 whole seconds, that's a lot.
In any case, you could do something following this pattern:
// some huge list
var allOptions = [];
function doIntensiveWork (option, callback) {
// do what ever you want
// then call 'callback' when work is done
callback();
}
function processNextOption () {
if (allOptions.length === 0)
{
// list is empty, so you're done
return;
}
// get the next item
var option = allOptions.shift();
// process this item, and call "processNextOption" when done
doIntensiveWork(option, processNextOption);
// if "doIntensiveWork" is asynchronous (using AJAX for example)
// the code above might be OK.
// but if "doIntensiveWork" is synchronous,
// you should let the browser breath a bit, like this:
doIntensiveWork(option, function () {
setTimeout(processNextOption, 0);
});
}
processNextOption();
Notice: as said by Karl-André Gagnon, you should avoid doing many AJAX requests using this technique. Try combining them if you can, it will be better and faster.
If you can't pass the whole block to the server to be processed in bulk, you could use a jQuery queue. This is using your sample code as a base:
var $container = $('.as-network-list').first();
$container.find('input[type="checkbox"]:checked').each(function(){
var $input = $(this);
$container.queue('publish', function(next) {
var blog_id = $input.val(),
$parent = $input.parent();
console.log(blog_id+' started');
$parent.addClass('synd-in-progress'); //add visual feedback of 'in-progress'
as_process_syndication_to_blog(blog_id).done(function(response) {
console.log(response);
console.log('finished'+blog_id);
$parent.removeClass('synd-in-progress');
next();
});
});
});
$container.dequeue('publish');
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
return as_syndicate_to_blog(data).done(function(){ console.log('end 2nd func'); });
}
function as_syndicate_to_blog(data){
return $.ajax({
type : "post",
dataType : "json",
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id}
});
}
I don't have a test environment for this so you may need to tweak it for your use case.

Categories