Instead of reloading old data from a PHP file that I parse with JavaScript using JSON, I want to ONLY load new data. My project is a little multiplayer environment and my goal is to have all users see either other move in realtime.
Here is my code:
JavaScript:
function getUsers() {
$.get("database/getData.php", function(data) {
// data returned from server;
for(var i = 0; i < data.response.length; i++) {
// users obtained from the array... parse them now
var user = data.response[i].split(" ");
// user info
var id = user[0];
var username = user[1];
var xx = user[2];
var yy = user[3];
userCount = data.response.length;
$(".online").html(userCount + " users online right now.")
// position the users
moveCharacter(username, xx, yy);
}
}, "json");
}
var infoGetter = setInterval(getUsers, 2000); // we may need to improve this... type of realtime
And here is my PHP:
<?
$database = sqlite_open("thenew.db", 0999, $error);
if(!$database) die($error);
$query = "SELECT * FROM users";
$results = sqlite_query($database, $query);
if(!$results) die("Canot execute query");
$data = array();
while($row = sqlite_fetch_array($results)) {
$data[] = $row['uid'] . " " . $row['username'] . " " . $row['xPos'] . " " . $row['yPos'];
}
echo json_encode(array("response"=>$data));
sqlite_close($database);
?>
How can I make it so ONLY new data from the PHP file is parsed by the JavaScript instead of all data?
Thanks!
I would suggest you to modify the select query. Instead of having it as select * from users, add some where condition like where userId > somenumber. Now send the last userId which we processed in the last request along with next request which you make from client side. This will make sure that you will always gets new response.
Indeed, with your current setup, every call to "getUsers" will replay the entire state of the game up to the last move made, and not necessarily finish in the correct state. In order to get the behavior you want, you will need to add a timestamp or serial id to the "users" table and then order your results in order to get the most recent moves. You will need to do this for each user separately, so you will also need to provide a mechanism to retrieve and iterate through all users...
Thus your javascript becomes something like...
function getUsers() {
$.get("database/getAllUsers.php", function(data) {
$.each(data, function(i,uid) {
$.get("database/getData.php?uid=".uid, function(data) {
...
and your php query becomes...
$query = "SELECT * FROM users WHERE uid=$_GET['uid'] ORDER BY timestamp DESC LIMIT 1
Related
I am trying to pull the latest entry of a mysql table through ajax and display it as html content inside a div. I have ajax and php functioning correctly, the only problem I have is that I want to query for new entries and stack the results at a time interval within a loop and I've run into two problems: getting the data to behave like a normal javascript string, and getting the loop to only return unique entries.
update.php file
$con=mysqli_connect("mydbhost.com","username","password","database_name");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$result = mysqli_query($con,"SELECT * FROM conversations");
$j = 0;
while($row = mysqli_fetch_array($result))
{
$carray[j] = $row['comment'];
$j++;
}
$comment = (array_pop($carray));
echo $comment;
echo "<br>";
mysqli_close($con);
JQuery Ajax request loop:
$(document).ready(function(e){
var comment;
function commentLoop() {
comment = $('#testdiv').load('update.php');
$('#testdiv').append(comment);
setTimeout(commentLoop, 6000);
}
commentLoop();
$(document).focus();
});
The problem is by doing SELECT * FROM conversations you keep requesting whole table -- although you only take the last one.
Your code need to remember which comment has been loaded, and only get any comment newer than that.
For example, assuming your primary key is incremental, do SELECT * FROM conversations WHERE convid > ?. Replace ? with latest comment that has been loaded. If you're loading for the first time, just do SELECT * FROM conversations
You could pass the last comment id displayed using request parameter into update.php. Also I recomment returning the data in JSON format so you can return a collection of comment and id and parse it easily
This will count the comments in the table and select the last entered comment then pass them to ajax as json data only if the received count is lower than the count of the comments in the table:
PHP:
if(isset($_GET['data']))
{
$con = new mysqli('host', 'user', 'password', 'database');
$init_count = $_GET['data'];
$stmt1 = "SELECT COUNT(*) AS count FROM conversations";
$stmt2 = "SELECT comment FROM conversations ORDER BY date_column DESC LIMIT 1";
$total = $con->prepare($stmt1);
$total->execute();
$total->bind_result($count);
$total->fetch();
$total->close();
if( ($init_count != '') && ($init_count < $count) )
{
$lastComment = $con->prepare($stmt2);
$lastComment->execute();
$result = $lastComment->get_result();
$row = $result->fetch_assoc();
$lastComment->close();
$data = array(
'comment' => $row['comment'],
'count' => $count
);
}
elseif($init_count == '')
{
$data = array(
'comment' => '',
'count' => $count
);
}
$pdo->close();
echo json_encode($data);
}
HTML:
<input type="hidden" id="count" value="" />
JQUERY:
$(document).ready(function(e){
function getComment(){
var count = $('#test').val();
$.ajax({
type: 'get',
url: 'update.php?data=' + count,
dataType: 'json',
success: function(data)
{
$('#count').val(data.count);
if(data.comment) != $('#testdiv').html(data.comment);
}
});
}
getComment();
setInterval(getComment, 6000);
});
SELECT * FROM conversations order by insert_date desc limit 10
insert_date the date time comment is inserted, i hope you will have a field for storing that if not add it now
I have followed help located in this topic: Using infinite scroll w/ a MySQL Database
And have gotten close to getting this working properly. I have a page that is displayed in blocks using jquery masonry, in which the blocks are populated by data from a mysql database. When I scroll to the end of the page I successfully get the loading.gif image but immediately after the image it says "No more posts to show." which is what it should say if that were true. I am only calling in 5 posts initially out of about 10-15, so the rest of the posts should load when I reach the bottom of the page but I get the message that is supposed to come up when there really aren't any more posts.
Here is my javascript:
var loading = false;
$(window).scroll(function(){
if($(window).scrollTop() == $(document).height() - $(window).height()) {
var h = $('.blockContainer').height();
var st = $(window).scrollTop();
var trigger = h - 250;
if((st >= 0.2*h) && (!loading) && (h > 500)){
loading = true;
$('div#ajaxLoader').html('<img src="images/loading.gif" name="HireStarts Loading" title="HireStarts Loading" />');
$('div#ajaxLoader').show();
$.ajax({
url: "blocks.php?lastid=" + $(".masonryBlock:last").attr("id"),
success: function(html){
if(html){
$(".blockContainer").append(html);
$('div#ajaxLoader').hide();
}else{
$('div#ajaxLoader').html('<center><b>No more posts to show.</b></center>');
}
}
});
}
}
});
Here is the php on the page the blocks are actually on. This page initially posts 5 items from the database. The javascript grabs the last posted id and sends that via ajax to the blocks.php script, which then uses the last posted id to grab the rest of the items from the database.
$allPosts = $link->query("/*qc=on*/SELECT * FROM all_posts ORDER BY post_id DESC LIMIT 5");
while($allRows = mysqli_fetch_assoc($allPosts)) {
$postID = $link->real_escape_string(intval($allRows['post_id']));
$isBlog = $link->real_escape_string(intval($allRows['blog']));
$isJob = $link->real_escape_string(intval($allRows['job']));
$isVid = $link->real_escape_string(intval($allRows['video']));
$itemID = $link->real_escape_string(intval($allRows['item_id']));
if($isBlog === '1') {
$query = "SELECT * FROM blogs WHERE blog_id = '".$itemID."' ORDER BY blog_id DESC";
$result = $link->query($query);
while($blogRow = mysqli_fetch_assoc($result)) {
$blogID = $link->real_escape_string($blogRow['blog_id']);
$blogTitle = $link->real_escape_string(html_entity_decode($blogRow['blog_title']));
$blogDate = $blogRow['pub_date'];
$blogPhoto = $link->real_escape_string($blogRow['image']);
$blogAuthor = $link->real_escape_string($blowRow['author']);
$blogContent = $link->real_escape_string($blogRow['content']);
//clean up the text
$blogTitle = stripslashes($blogTitle);
$blogContent = html_entity_decode(stripslashes(truncate($blogContent, 150)));
echo "<div class='masonryBlock' id='".$postID."'>";
echo "<a href='post.php?id=".$blogID."'>";
echo "<div class='imgholder'><img src='uploads/blogs/photos/".$blogPhoto."'></div>";
echo "<strong>".$blogTitle."</strong>";
echo "<p>".$blogContent."</p>";
echo "</a>";
echo "</div>";
}
}
Here is the php from the blocks.php script that the AJAX calls:
//if there is a query in the URL
if(isset($_GET['lastid'])) {
//get the starting ID from the URL
$startID = $link->real_escape_string(intval($_GET['lastid']));
//make the query, querying 25 fields per run
$result = $link->query("SELECT * FROM all_posts ORDER BY post_id DESC LIMIT '".$startID."', 25");
$html = '';
//put the table rows into variables
while($allRows = mysqli_fetch_assoc($result)) {
$postID = $link->real_escape_string(intval($allRows['post_id']));
$isBlog = $link->real_escape_string(intval($allRows['blog']));
$isJob = $link->real_escape_string(intval($allRows['job']));
$isVid = $link->real_escape_string(intval($allRows['video']));
$itemID = $link->real_escape_string(intval($allRows['item_id']));
//if the entry is a blog
if($isBlog === '1') {
$query = "SELECT * FROM blogs WHERE blog_id = '".$itemID."' ORDER BY blog_id DESC";
$result = $link->query($query);
while($blogRow = mysqli_fetch_assoc($result)) {
$blogID = $link->real_escape_string($blogRow['blog_id']);
$blogTitle = $link->real_escape_string(html_entity_decode($blogRow['blog_title']));
$blogDate = $blogRow['pub_date'];
$blogPhoto = $link->real_escape_string($blogRow['image']);
$blogAuthor = $link->real_escape_string($blowRow['author']);
$blogContent = $link->real_escape_string($blogRow['content']);
$blogTitle = stripslashes($blogTitle);
$blogContent = html_entity_decode(stripslashes(truncate($blogContent, 150)));
$html .="<div class='masonryBlock' id='".$postID."'>
<a href='post.php?id=".$blogID."'>
<div class='imgholder'><img src='uploads/blogs/photos/".$blogPhoto."'></div>
<strong>".$blogTitle."</strong>
<p>".$blogContent."</p>
</a></div>";
}
}
echo $html;
}
I have tried using the jquery infinite-scroll plugin, but it seemed much more difficult to do it that way. I don't know what the issue is here. I have added alerts and did testing and the javascript script is fully processing, so it must be with blocks.php right?
EDIT: I have made a temporary fix to this issue by changing the sql query to SELECT * FROM all_posts WHERE post_id < '".$startID."' ORDER BY post_id DESC LIMIT 15
The blocks are now loading via ajax, however they are only loading one block at a time. The ajax is sending a request for every single block and they are fading in one after another, is it possible to make them all fade in at once with jquery masonry?
I seen your code in another answer, and I would recommend using the LIMIT functionality in MySql instead of offsetting the values. Example:
SELECT * FROM all_posts ORDER BY post_id DESC LIMIT '".(((int)$page)*5)."',5
This will just take a page number in the AJAX request and get the offset automatically. It's one consistent query, and works independent of the last results on the page. Send something like page=1 or page=2 in your jQuery code. This can be done a couple different ways.
First, count the number of elements constructed on the page and divide by the number on the page. This will yield a page number.
Second, you can use jQuery and bind the current page number to the body:
$(body).data('page', 1)
Increment it by one each page load.
Doing this is really the better way to go, because it uses one query for all of the operations, and doesn't require a whole lot of information about the data already on the page.
Only thing to note is that this logic requires the first page request to be 0, not 1. This is because 1*5 will evaluate to 5, skipping the first 5 rows. If its 0, it will evaluate to 0*5 and skip the first 0 rows (since 0*5 is 0).
Let me know any questions you have!
Have you tried doing any debugging?
If you are not already using, I would recommend getting the firebug plugin.
Does the ajax call return empty? If it does, try echoing the sql and verify that is the correct statement and that all the variables contain the expected information. A lot of things could fail considering there's a lot of communication happening between client, server and db.
In response to your comment, you are adding the html in this piece of code:
if(html){
$(".blockContainer").append(html);
$('div#ajaxLoader').hide();
}
I would do a console.log(html) and console.log($(".blockContainer").length) before the if statement.
Basically, this is what I am doing:
I have a flash/ajax file uploader where users can select x amount of photos and upload them and then they are inserted into a MYSQL database by an external php script.
After they are inserted in the database, I would like to display them on the page and allow the users to edit the tags, caption, etc.
However, I cannot figure out how to "Live update" the page to display the correct data
Take this for example:
showFields() is ran once he upload is complete;
function showFields() {
var jsvar = '<?php echo getIDs(); ?>';
document.getElementById('picndata').innerHTML += jsvar;
}
which will work if I have getIDs just return a static value such as "test"
but if i were to have it do this:
function getIDs() {
$SQL = "SELECT * FROM `slides` ORDER BY `sid` DESC";
$results = mysql_query($SQL);
$row = mysql_fetch_assoc($results);
$slide = $row['sid'];
$SQL = "SELECT * FROM `slides` WHERE `sid` = $slide";
$results = mysql_query($SQL);
$str;
while ($row = mysql_fetch_array($results)) {
$str .= $row['size'] . "\r\n";
}
return $str;
}
(sloppy I know)
, then it will not work because the PHP is ran first and so it does not find any results because the images were not uploaded yet!
Any ideas?
This line:
$str .= $row['size'] . "\r\n";
will result in your JavaScript having an unterminated string literal.
Change:
var jsvar = '<?php echo getIDs(); ?>';
To:
var jsvar = '<?php echo str_replace("\r\n", "\\\r\n", trim(getIDs()) ?>';
This will place slashes in the appropriate places so the JavaScript is valid. Alternatively, instead of adding a backslash, you could replace the newlines entirely with a space or a comma or whatever works best for your code.
Use ajax and timestamp your images.
I personally have a 'refresh' function that get's called on a timed basis via setTimeout().
On initial load of current images, determine the newest image timestamp.
In you ajax, query for images with timestamp > previous 'newest' timestamp. Update the page if you get any results, and reset your new 'newest' var.
If you have some return from your upload function that you can use to trigger your ajax as well, that would eliminate any delay in seeing the new images.
I'd also suggest storing that timestamp in session variables so you are not relying on user input for your query.
Also handles concurrency where other users could be uploading to the same area.
I have a 3 step chained-select sequence, game -> battle -> winning side , which pulls all data from a MySQL database.
After some wandering on the internet, I found a compact jQuery script that performs wonderfully. However, I am at a loss as to how to allow for existing data: <option selected="selected"></option> using this script.
chained select javascript:
<script>
var ajax = new Array();
function getScenNumList(sel)
{
var game = sel.options[sel.selectedIndex].value;
document.getElementById('scenarioNumber').options.length = 0; // Empty scenario number select box
if(game.length>0){
var index = ajax.length;
ajax[index] = new sack();
ajax[index].requestFile = 'js/getPlayData.php?gameName='+game; // Specifying which file to get
ajax[index].onCompletion = function(){ createScenarioNumbers(index) }; // Specify function that will be executed after file has been found
ajax[index].runAJAX(); // Execute AJAX function
}
}
function createScenarioNumbers(index)
{
var obj = document.getElementById('scenarioNumber');
eval(ajax[index].response); // Executing the response from Ajax as Javascript code
}
function getNations(sel)
{
var scenNum = sel.options[sel.selectedIndex].value;
document.getElementById('victor').options.length = 0; // Empty nation select box
if(scenNum.length>0){
var index = ajax.length;
ajax[index] = new sack();
ajax[index].requestFile = 'js/getPlayData.php?scenID='+scenNum; // Specifying which file to get
ajax[index].onCompletion = function(){ createNations(index) }; // Specify function that will be executed after file has been found
ajax[index].runAJAX(); // Execute AJAX function
}
}
function createNations(index)
{
var obj = document.getElementById('victor');
eval(ajax[index].response); // Executing the response from Ajax as Javascript code
}
</script>
excerpt from the PHP database retrieval script (getPlayData.php):
$gameName = mysql_real_escape_string($_GET['gameName']);
$q = "SELECT a, b, c FROM table WHERE game='$gameName' ORDER BY num ASC";
$r = mysql_query($q);
echo "obj.options[obj.options.length] = new Option('#','');\n";
while ($row = mysql_fetch_row($r)) {
$string = mysql_real_escape_string(($row[0].' - '.$row[1])); // needed so quotes ' " don't break the javascript
echo "obj.options[obj.options.length] = new Option('$string','$row[2]');\n";
}
echoing the obj.options is the stock method this script was using. It seems ugly to me, but I don't know any javascript so I didn't want to fiddle with it.
The HTML is simple enough, just a table with a few empty <select> objects with IDs matching those in the javascript and onchange="getXXX(this)" calls.
My question is this: Everything works great for new records, but I'm at a loss as to how I can alter this to support marking one option from each select as selected, assuming I have that data in hand (ex: a user is editing an existing record) ?
Many thanks!
You can see this tutorial for creating an option that is selected as default. http://www.javascriptkit.com/javatutors/selectcontent.shtml One parameter in the option constructor dictate that whether the option is selected or not.
In the PHP file you will edit as follow:
$gameName = mysql_real_escape_string($_GET['gameName']);
$q = "SELECT a, b, c FROM table WHERE game='$gameName' ORDER BY num ASC";
$r = mysql_query($q);
echo "obj.options[obj.options.length] = new Option('#','');\n";
while ($row = mysql_fetch_row($r)) {
$string = mysql_real_escape_string(($row[0].' - '.$row[1])); // needed so quotes ' " don't break the javascript
if ($string ......)
echo "obj.options[obj.options.length] = new Option('$string','$row[2]', false, true);\n";
else
......
}
Using Javascript I need to get some rows from a DB table, and then loop through each row and use different fields from each row.
For example, if I get the rows like this:
var coordinatesArray = '<?php
global $wpdb;
echo $wpdb->get_var("SELECT * FROM users_coordinates WHERE lat>20 and lat<40 and long>-10 and long<40);
?>';
How should I write the following code:
// for each row do: {
// alert the id field
// alert the lat field
// alert the long field
// }
JSON is the way to put the output in, that ensures that the result will be valid JavaScript and protects you from arbitrary code execution in JS.
var coordinatesArray = <?php
global $wpdb;
// replace * by id, lat and long since you don't need other fields
$sql = "SELECT id, lat, long FROM users_coordinates WHERE lat>20 and lat<40 and long>-10 and long<40";
$rows = $wpdb->get_results($sql);
// if the function fails (?), make valid JS syntax
if (is_array($rows)) {
echo json_encode($rows);
} else {
echo '[]';
}
?>;
for (var i=0; i<coordinatesArray; i++) {
alert(coordinatesArray[i].id);
alert(coordinatesArray[i].lat);
alert(coordinatesArray[i]["long"]);
}
The other way would be creating a JS object with the id field as key of the JS object:
var coordinatesMap = <?php
global $wpdb;
// replace * by id, lat and long since you don't need other fields
$sql = "SELECT id, lat, long FROM users_coordinates WHERE lat>20 and lat<40 and long>-10 and long<40";
// note: OBJECT_K, the result will be an associative array with the first field of a
// row as key
$rows = $wpdb->get_results($sql, OBJECT_K);
// if the function fails (?), make valid JS syntax
if (is_array($rows)) {
echo json_encode($rows);
} else {
echo '{}';
}
?>;
for (var id in coordinatesMap) {
if (coordinatesMap.hasOwnProperty(id)) {
alert(id);
alert(coordinatesMap[id].lat);
alert(coordinatesMap[id]["long"]);
}
}
Please replace alert by something else, it's not really user-friendly. Remember that PHP != JavaScript and you cannot use PHP functions in JavaScript and vice versa. If you're not sure how the output would look like, use the View source option of a page.
References:
http://codex.wordpress.org/Class_Reference/wpdb#SELECT_Generic_Results
You may have a better time writing your own custom PHP script to fetch these values (rather than depending on WP), loop through them, and build a json object that you return to the javascript.
First, $wpdb->get_var can only get one value. http://codex.wordpress.org/Class_Reference/wpdb#SELECT_a_Variable
Use $wpdb->get_results instead
http://codex.wordpress.org/Class_Reference/wpdb#SELECT_Generic_Results
var coordinatesArray = '<?php
global $wpdb;
echo $wpdb->get_results("SELECT * FROM users_coordinates WHERE lat>20 and lat<40 and long>-10 and long<40);
?>';
for(coord in coordinatesArray) {
alert(coordinatesArray[coord].id);
alert(coordinatesArray[coord].lat);
alert(coordinatesArray[coord].long);
}
I haven't tested, but it should be something like that.