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.
Related
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.
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.
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.
i need close the user session with ajax, when this close the nav or tab of my app. For this i'm using the event beforeunload, the issue is when i reload the page with F5(cmr+r, ctrl+r) with this the nav open the warning diag and i don't need this.
$(window).bind('beforeunload',function (e) {
var message = 'Are you sure you want to leave?';
return message;
}
$(window).bind('unload', function () {
var dataStatus = $('button[name="status"]').attr('data-status');
if (dataStatus == 'online') {
var req = $.ajax({
url: 'mi-url',
type: 'POST',
async : true,
data: {data: JSON.stringify({user_id: <?php echo $user->getId() ?>})},
dataType: "JSON"
});
}
});
Waiting for replys, thanks.
You can't differentiate close tab and tab unload/reload. Instead your old approach, you can set interval 5 minutes or some meaningful time period, and send a notification to the server about session.
I have an AJAX function to check for new messages and then prepend the new messages to the #message. But, my problem is that this function triggers every 20 seconds, but whenever you click the Refresh button that instantly triggers the function, it messes up. Here is my functions for the AJAX:
function ajaxMail() {
var message_id = $('.line:first').attr('id');
jQuery.ajax({ //new mail
type: 'get',
dataType: 'text',
url: "/employee/message/check_mail.php",
data: {
latest_id: message_id,
t: Math.random()
},
success: function(data, textStatus) {
$('#messages_inner').prepend(data);
}
});
}
function updateTitles() {
//if(titleChange !== false) {
$.get('update.php?type=title', function(data) {
document.title = data;
});
//}
$.get('update.php?type=header', function(data) {
$('#heading').html(data);
});
$.get('update.php?type=total', function(data) {
$('#total').html('Total messages: ' + data);
});
setTimeout("updateTitles();ajaxMail();", 20000);
}
updateTitles();
And for the Refresh button this is what I use:
$(document).ready(function() {
$('#refresh').click(function() {
ajaxMail();
updateTitles();
});
});
Sometimes, the same exact message gets prepended to the message div because of the button or something. (but when I refresh of course there aren't 2 of the same message anymore) This is one time when the same message was prepended multiple times:
First, I pressed the Refresh button and it prepended the new message. But then about 5 seconds later the funciton triggered again and for some reason prepended the same message again. Also as you can see the Inbox count says 2 because really there is only 2 ("Test" and "Test12345"), but for some reason the "Test12345" got prepended 2 times.
Does anyone know why it is doing this? I can also provide the code for check_mail.php if you need to see it.
I'd recommend trying cache:false too, I've had browsers caching an ajax request even through I was sending a random string along.
Also, consider clearing the timeout before you set it again, as each time the refresh button is pressed it starts another timeout.