I am trying to create a simple AJAX/PHP chat application to enable communication between registered users on a website. The problem with it is storing the chat history. I thought of storing all the chat messages in a single database (with columns like user1, user2, message, time), and then at every AJAX request, search the database for a matching message between the users, but I think this might be extremely inefficient. Is it a good idea to implement it this way, and what are some good ways of handling this?
Since a chat room has to constantly get updates, I wanted to minimize the requests to a minimum, so I just labeled each message with the database id. Since every user can see all the messages for that room, the request is just sending the id to the server to see if there were any new posts. If there were, it returns the new posts and updates the page.
Here's the JavaScript that I use:
var csrf = $("input[name='csrf_test_name']").val();
load_messages();
load_users();
$("#submitbutton").click(function(){
var message = $("#content").val();
$.post(base_url + "index.php/chat/ajax_post", {
text: message,
csrf_test_name: csrf
});
$("#content").attr("value", "");
return false;
});
function load_messages(){
var last = $('#messagewindow p:last').attr('id');
$.ajax({
url: base_url + "index.php/chat/ajax_retrieve",
type: "POST",
data: {
last: last,
csrf_test_name: csrf
},
cache: false,
success: function(html){
if(html.substr(1, 1) == 'p'){
var oldscrollHeight = $("#messagewindow").prop("scrollHeight") - 20;
var id;
var tag;
var user;
var uid;
//remove messages that exceed the max - determined on the server side
$('#messagewindow p:lt(' + $(html).siblings().size() + ')').remove();
//add messages, emoticons and classes based on whether its the user or someone else
$(html).find('b').each(function(){
if ($(this).html() == user_name + ':'){
$('#messagewindow').append($(this).parent().emoticons(base_url + 'images/emoticons').attr('class', 'self'));
} else {
$('#messagewindow').append($(this).parent().emoticons(base_url + 'images/emoticons').attr('class', 'others'));
}
});
//scroll screen
var newscrollHeight = $("#messagewindow").prop("scrollHeight") - 20;
if(newscrollHeight > oldscrollHeight){
$("#messagewindow").animate({ scrollTop: newscrollHeight }, 'normal');
}
$(html).find('span').each(function(){
id = $(this).attr('id');
uid = 'u' + id.substr(1);
if (id.substr(0, 1) == 'e' && $('#userwindow p[id="' + uid + '"]').size() < 1){
user = $(this).prev().html();
tag = "<p id='" + uid + "'>" + user.substr(0, user.length - 1) + "</p>";
$('#userwindow').append(tag);
} else if(id.substr(0, 1) == 'x') {
$('#userwindow p[id="u' + id.substr(1) + '"]').remove();
}
});
}
}
});
}
function load_users(){
$.ajax({
url: base_url + "index.php/chat/ajax_users",
cache: false,
success: function(html){
if(html.substr(1, 1) == 'p'){
$("#userwindow").html(html);
}
}
});
}
setInterval(load_messages, 2000);
setInterval(load_users, 240000);
What would be wrong with your method?
Use the proper MySQL indexes on your table (I would say on the two columns user1, user2 and on timestamp or unique ID for the order) and the performance will be good enough.
You can add the curent timestamp to the AJAX request to retreive only message that you didn't loaded the call before.
Related
I have a weak server
When clients repeatedly request ajax service, the server stops working
Frequent demand ajax
My server is weakening
I want to make only one request. Upon completion he will be able to make another request
function checkItemd(item_id){
$("#checkBtn"+item_id).html("Processing..(Wait)").removeClass("btn-success").addClass("btn-primary");
alert("One tool checked at a time - Click OK");
var payload_string = $("#payload_form").serialize();
$.ajax({
type:"POST",
url:"ajax-item-check",
data:payload_string + "&itemId=" + item_id,
dataType:"json",
success:function(result){
if (result.result=="success"){
if (result.works=="success"){
var checkBtnMessage = result.response ? result.response : "'Sent to ' Email ";
$("#checkBtn"+item_id).html(checkBtnMessage).removeClass("btn-primary").addClass("btn-success");
}else{
$("#checkBtn"+item_id).html("Error").removeClass("btn-primary").addClass("btn-danger");
setTimeout('removeRow('+item_id+');',1000);
}
}else{
$("#checkBtn"+item_id).html("Not available to sellers").removeClass("btn-primary").addClass("btn-warning");
}
}
});
return false;
If you want to stop the user making multiple parallel requests, you can just set a flag which causes the function code not to be executable if the request is already in progress.
e.g. look at the requestInProgress flag in this example:
var requestInProgress = false;
function checkItemd(item_id) {
if (requestInProgress == true) return false;
$("#checkBtn"+item_id).html("Processing..(Wait)").removeClass("btn-success").addClass("btn-primary");
alert("One tool checked at a time - Click OK");
var payload_string = $("#payload_form").serialize();
requestInProgress = true;
$.ajax({
type:"POST",
url:"ajax-item-check",
data:payload_string + "&itemId=" + item_id,
dataType:"json",
success:function(result){
requestInProgress = false;
if (result.result=="success") {
if (result.works=="success") {
var checkBtnMessage = result.response ? result.response : "'Sent to ' Email ";
$("#checkBtn"+item_id).html(checkBtnMessage).removeClass("btn-primary").addClass("btn-success");
}else{
$("#checkBtn"+item_id).html("Error").removeClass("btn-primary").addClass("btn-danger");
setTimeout('removeRow('+item_id+');',1000);
}
}else{
$("#checkBtn"+item_id).html("Not available to sellers").removeClass("btn-primary").addClass("btn-warning");
}
}
});
}
N.B. you might want to add an "error" callback so you can set the flag false again in the event of any kind of unexpected problem with the request. Otherwise the user would have to refresh the page before they could make the request again.
Turning off asynchronous requests in jQuery fixed the issue.
I have the following Javascript & AJAX request (using jQuery) in my page:
"use strict";
var hsArea, counter, hotspots, count;
counter = 4;
count = 0;
hotspots = {};
function fetchHotspotList() {
$.getJSON ('/alpha/engine/hotspots/gethotspot.php', {'type' : 'list'}, function(json) {
hotspots = json;
});
}
function displayHotspot(type, id, number) {
$.ajax({
url: '/alpha/engine/hotspots/gethotspot.php',
dataType: 'json',
data: {'type' : type, 'id' : id},
success: function(json) {
console.log(json);
var hotspot, extract;
extract = json.content;
extract = extract.replace(/<(?:.|\n)*?>/gm, '');
extract = extract.substring(0, 97);
extract = extract + "...";
json.content = extract;
hotspot = document.createElement("div");
hsArea.append(hotspot);
hotspot.setAttribute('class','hotspot');
hotspot.setAttribute('id','hotspot' + number);
$(hotspot).css('position', 'absolute');
$(hotspot).css('top', number * 100 + 100);
$(hotspot).css('left', number * 100 + 110);
hotspot.innerHTML = "<h1>"+ json.title + "</h1><p>" + json.content + "</p>";
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus, errorThrown);
}
});
}
function listHotspots() {
for(count = 0; count < counter; count++) {
(function(count) {
displayHotspot('scribble',hotspots[count], count);
count = count + 1;
})(count);
}
}
function loadHotspots() {
fetchHotspotList();
listHotspots();
}
$(document).ready(function() {
hsArea = $("#hotspotArea");
fetchHotspotList();
listHotspots();
});
(Sorry the formatting is a bit off!) - Now, the $(document).ready() function assigns the hsArea variable as it should, however, a combination of fetchHotspotList() and listHotspots() returns:
Uncaught TypeError: Cannot call method 'replace' of null
However, if in the Google Chrome Javascript console, I run:
loadHotspots();
it fetches the data from the AJAX request and displays it properly on the page. At first I thought the problem was that I Wasn't using the $(document).ready() handler, but adding it hasn't fixed it. Neither has using an onload handler inside of the body tag.
Any help would be greatly appreciated.
Regards,
Ben.
It's probably due to the fact that your listHotSpots function is called before fetchHotSpots returns (since it's an async call).
You're better off chaining the execution of listHotSpots to the completion of fetchHotSpots, like so:
function fetchHotspotList() {
$.getJSON ('/alpha/engine/hotspots/gethotspot.php', {'type' : 'list'}, function(json) {
hotspots = json;
listHotSpots();
});
}
You may be better off modifying listHotSpots to take the json data returned from your AJAX call. Hope this helps!
I have a chat application and in this application, i want to show online users in a chatroom. I have a database that records online users and it keeps changing whenever a new user comes. Whenever a users leaves, it is deleted from the database. Database consists of two columns: username and room. Database side works fine.
onlinelar.php:
<?php
$data = array();
$current = $_GET['current'];
$room = $_GET['room'];
$getRoomUsers = mysql_query("SELECT * FROM `chat_users_rooms` WHERE `room` = '".$room."'");
if(mysql_num_rows($getRoomUsers) != $current)
{
$data['numOfUsers'] = mysql_num_rows($getRoomUsers);
}
else
{
$data['numOfUsers'] = $current;
}
echo json_encode($data);
?>
online.js:
var numOfUsers = 0;
var room;
function chat(room2)
{
room = room2;
}
$.ajaxSetup({
cache: false
});
function getuserlist() {
$.ajax({
type: "GET",
url: "onlinelar.php",
data: {
'room': room,
'current' : numOfUsers
},
dataType: "json",
cache: false,
success: function(data) {
if (numOfUsers != data.numOfUsers) {
numOfUsers = data.numOfUsers;
$('#bu').html($("<strong id='bu'>"+ numOfUsers + "</strong>"));
}
setTimeout(getuserlist(),1);
},
});
}
And finally, the initializer of it in index.html:
----something
<script type="text/javascript">
var chat = new Chat(<?php echo $room;?>);
chat.getuserlist();
</script>
<strong id="bu">
<?php
echo $numOfUsers;
?>
</strong>
------something
In here, i want to check database situation(rows of the certain room), and change the number of chatters in that room simultaneously. 'current' is for number of users and 'room' is for the name of the room.But there is no change even though the num of rows of database is changing. Which part i am missing?
Note: I have added online.js in index.php
$('#bu').html($("<strong id='bu'>"+ numOfUsers + "</strong>"));
This line places a new element under your old one, what you want to do is replace the old one by calling
$('#bu').html(numOfUsers);
Also setTimeout() takes milliseconds so 1 is a really low value, you might want to start with 1000 and work from there.
Edit:
And setTimeout() takes a function as a param so you want to call:
setTimeout(getuserlist, 1000);
A user enters an address on this form, then click on verify address, and i run this:
$('#verify').click(function () {
var address = $('input[name=address]');
var city = $('input[name=city]');
var state = $('input[name=state]');
var zip = $('input[name=zip]');
var country = $('select[name=country]');
//organize the data for the call
var data = 'address=' + address.val() + '&city=' + city.val() + '&state=' + state.val() + '&zip=' + zip.val() + '&country=' + country.val();
//start the ajax
$.ajax({
url: "process.php",
type: "GET",
data: data,
cache: false,
success: function (html) {
//alert (html);
if (html!='error') {
//show the pin long and lat form
$('.form2').fadeIn('slow');
} else alert('Error: Your location cannot be found');
}
});
//cancel the submit button default behaviours
return false;
});
process.php takes the data, and verifies that the address exists, then sends back the latitude and longitude as "longitude,latitude". How can I take that data and place it in a form field that shows up if the location is found (form fields in the form2 div). Thanks so much.
Replace this:
$('.form2').fadeIn('slow');
with this:
$('.form2').fadeIn('slow').find('input[name=latlon]').val(html);
where latlon is the name of the input field where you want to insert the latitude and longitude.
Well, I'm litte confused but, if I understand correctly, you can split response by "," separator and simply put each one in respective field. Like this:
if (html!='error') {
var response = html.split(',');
$('.form2').fadeIn('slow');
$('.form2 input.longitude').attr( 'value', response[0] );
$('.form2 input.latitude').attr( 'value', response[1] );
} else {
alert('Error: Your location cannot be found');
}
I have a page which uses jquery's ajax functions to send some messages.
There could be upwards of 50k messages to send.
This can take some time obviously.
What I am looking to do is show a progress bar with the messages being sent.
The backend is PHP.
How can I do this?
My solution:
Send through a unique identifier in the original ajax call.
This identifier is stored in a database(or a file named with the identifier etc), along with the completion percentage.
This is updated as the original script proceeds.
a function is setup called progress(ident)
The function makes an ajax call to a script that reads the percentage.
the progressbar is updated
If the returned percentage is not 100,
the function sets a timeout that calls itself after 1 second.
Check this if you use jQuery:
http://docs.jquery.com/UI/Progressbar
You can just supply the value of the bar on every AJAX success.
Otherwise, if you don't use JS Framework see this:
http://www.redips.net/javascript/ajax-progress-bar/
I don't have a way to test it, but it should go like this:
var current = 0;
var total = 0;
var total_emails = <?php $total_emails ;?>;
$.ajax({
...
success: function(data) {
current++; // Add one to the current number of processed emails
total = (current/total_emails)*100; // Get the percent of the processed emails
$("#progressbar").progressbar("value", total); // Add the new value to the progress bar
}
});
And make sure that you'll include jQuery along with jQueryUI, and then to add the #progressbar container somewhere on the page.
I may have some errors though ...
You will probably have to round the total, especially if you have a lot of emails.
You could have an animated gif load via .html() into the results area until your ajax function returns back the results. Just an idea.
Regarding the jquery ui progress bar, intermittently through your script you'll want to echo a numeric value representing the percent complete as an assigned javascript variable. For example...
// text example php script
if (isset($_GET['twentyfive-percent'])) {
sleep(2); // I used sleep() to simulate processing
echo '$("#progressbar").progressbar({ value: 25 });';
}
if (isset($_GET['fifty-percent'])) {
sleep(2);
echo '$("#progressbar").progressbar({ value: 50 });';
}
if (isset($_GET['seventyfive-percent'])) {
sleep(2);
echo '$("#progressbar").progressbar({ value: 75 });';
}
if (isset($_GET['onehundred-percent'])) {
sleep(2);
echo '$("#progressbar").progressbar({ value: 100 });';
}
And below is the function I used to get the progress bar to update its position. A little nuts, I know.
avail_elem = 0;
function progress_bar() {
progress_status = $('#progressbar').progressbar('value');
progress_status_avail = ['twentyfive-percent', 'fifty-percent', 'seventyfive-percent', 'onehundred-percent'];
if (progress_status != '100') {
$.ajax({
url: 'test.php?' + progress_status_avail[avail_elem],
success: function(msg) {
eval(msg);
avail_elem++;
progress_bar();
}
});
}
}
If I had to guess, I bet there is a better way... But this is the way it worked for me when I tested it.
Use this answered question
this is how i implemented it:
var progressTrigger;
var progressElem = $('span#progressCounter');
var resultsElem = $('span#results');
var recordCount = 0;
$.ajax({
type: "POST",
url: "Granules.asmx/Search",
data: "{wtk: '" + wkt + "', insideOnly: '" + properties.insideOnly + "', satellites: '" + satIds + "', startDate: '" + strDateFrom + "', endDate: '" + strDateTo + "'}",
contentType: "application/json; charset=utf-8",
dataType: "xml",
success: function (xml) {
Map.LoadKML(xml);
},
beforeSend: function (thisXHR) {
progressElem.html(" Waiting for response from server ...");
ResultsWindow.LoadingStart();
progressTrigger = setInterval(function () {
if (thisXHR.readyState > 2) {
var totalBytes = thisXHR.getResponseHeader('Content-length');
var dlBytes = thisXHR.responseText.length;
(totalBytes > 0) ? progressElem.html("Downloading: " + Math.round((dlBytes / totalBytes) * 100) + "%") : "Downloading: " + progressElem.html(Math.round(dlBytes / 1024) + "K");
}
}, 200);
},
complete: function () {
clearInterval(progressTrigger);
progressElem.html("");
resultsElem.html(recordCount);
ResultsWindow.LoadingEnd();
},
failure: function (msg) {
var message = new ControlPanel.Message("<p>There was an error on search.</p><p>" + msg + "</p>", ControlPanel.Message.Type.ERROR);
}
});