loading an ajax call within a forEach loop - php

i have a feed page which loads posts (known as 'shouts' in my code) from a database based on who the user is following ('scouting' in my code). The basic information is displayed correctly. However, in each post i would like to load a separate file using ajax which will control the likes of the post. Below is my PHP for the feed page:
$findShouts = $pdo->prepare('SELECT * FROM feed WHERE name IN (SELECT scouting FROM scout WHERE scouted =? OR scouting =?) ORDER BY timestamp DESC');
//execute query and variables
$findShouts->execute([$username, $username]);
if ($findShouts->rowCount() > 0)
{
//get the shouts for each scout
while($row = $findShouts->fetch(PDO::FETCH_ASSOC)){
$shoutID[] = $row['id'];
$shoutUsername[] = $row["username"];
$shoutName[] = $row["name"];
$shoutText[] = $row["text"];
$shoutTimestamp[] = $row["timestamp"];
}
$shoutCount = count($shoutUsername);
for($indexShout=0; $indexShout < $shoutCount; $indexShout++) {
print'
<div class=feedNewShout>
<div class=shoutInformation>
<div class=shoutName>
<p>'. $shoutName[$indexShout] .'</p>
</div>
<div class=shoutTimestamp>
<p>'. timeElapsed("$shoutTimestamp[$indexShout]", 2) .'</p>
</div>
<div class=shoutText>
<p>'. $shoutText[$indexShout] .'</p>
</div>
<input type="hidden" name="feedID" class="feedID" value="'. $shoutID[$indexShout] .'">
<div class=likesAjax>
</div>
</div>
</div>';
}
unset($shoutID);
unset($shoutUsername);
unset($shoutName);
unset($shoutText);
unset($shoutTimestamp);
}
In each post the div class=likesAjax performs an ajax call which sends the hidden $feedID to feedlikes.php.
feedLikes.js
$(document).ready(function()
{
var feedID = $(".feedID").val();
$.ajax({
url: "feedLikes.php",
cache: false,
type: "POST",
data: {feedID: feedID},
dataType: "html",
success: function(html){
$(".likesAjax").empty();
$(".likesAjax").append(html);
}
});
});
feedLikes.php
if (isset($_POST['feedID']))
{
$feedID = ($_POST['feedID']);
echo "$feedID";
}
the problem i have is that i can see the ajax goes through every post and echos the feedID, however, every time a new call is made, all the feedID's change to the same thing. I know this is because my success call in my ajax updates every likesAjax class to the same thing. So whatever the feedID is of the last post, will be displayed for all of them.
My question is, how can i load feedLikes.php so that every post is shown with its own $feedID?
Note, feedLikes.php will eventually do something with the ID, the echo is just for test purposes.

Without changing your codes' logic, in PHP you can add an attribute to each ".likesAjax" box called data-id:
<div class="likesAjax" data-id="'.$shoutID[$indexShout] .'">
Now in jQuery in your ajax success function you can update your selector to look for this attribute as well in order to update the correct ".likesAjax" element:
$(".likesAjax[data-id='"+ feedID +"']").append(html);
To put these all together you would need to loop through your .likesAjax elements. To make your code a little cleaner you should make a function with the feedID as a parameter that will be executed for every step of the loop. This will look like the following:
$(".likesAjax").each(function() {
var feedID = $(this).attr("data-id");
loadFeedLikes(feedID);
});
function loadFeedLikes(feedID) {
$.ajax({
url: "feedLikes.php",
cache: false,
type: "POST",
data: {feedID: feedID},
dataType: "html",
success: function(html){
$(".likesAjax[data-id='"+ feedID +"']").html(html);
}
});
}
If you want to make this lighter you can create a new feedLikes.php that takes all the feedLikes you have and pushes them in an array. This array should contain the content you need and the feedId. Then you would only need one ajax call and with a for loop you could loop through the results and update all the $(".likesAjax") elements at once. This way you will have only one query to your db and only one ajax call to fetch your data.

Related

Ajax in while loop

I'm building push notifications for my messaging system and have a weird bug.
I'm using an ajax to get recent messages. In my PHP script I have a while loop where I go through my results. So each <li> is a 'recent message'.
In my mind it would be simple. I put an ajax function in the <li> and as it iterates through the while loop it will send the values received from the iteration. Below is my PHP script.
$output .= "
<li>
<img src='$profilephoto' class='rm_pp' alt=''>
<div class='imNotification'>
<script>
function getIMNotification() {
$.ajax({
url: 'getIMNotification.php',
method: 'POST',
data:{user2:'$id'},
success:function(data) {
$('.imNotification').html(data);
}
});
}
getIMNotification();
</script>
</div>
</li>
";
For example, in my getIMNotification.php if i just echo the user2 value sent from my AJAX, it will echo the same value for each result. But, since it's in the while loop, shouldn't it receive new values each iteration?
Is it because of the function being called? The one value being echoed is the last id in the loop. Any logic as to why it's doing that?
You shouldn't redefine the function in the loop. You should define the function once, and have it take the ID as a parameter. Then you can call it separately for each LI.
You also need to put the result in the specific DIV for that message. .imNotification selects all the DIVs with that class. You can use $id in the ID of the DIV to target each one.
The function doesn't need to come from AJAX, you can just put this in the original HTML:
function getIMNotification(id, target) {
$.ajax({
url: 'getIMNotification.php',
method: 'POST',
data: {
user2: id
},
success: function(data) {
$('#' + target).html(data);
}
});
}
Then the PHP would be:
$output .= "
<li>
<img src='$profilephoto' class='rm_pp' alt=''>
<div class='imNotification' id='imNotification-$id'>
<script>
getIMNotification('$id', 'imNotification-$id');
</script>
</div>
</li>
";

Ajax success function location.reload for individual php file

I have a feed page on my website (very similar to facebook) that enables me to like and comment on posts. I'm using ajax to update the posts, however, after a like, rather than each individual post reloading, the whole feed does (not the whole page itself, it just returns to the top of the feed).
I believe this is because each post is using a file named feedLikes.php that are all being reloaded rather than just that one specific post. I'm not sure how to only make that one post reload. below is my code.
From feed.php below, you can see i am searching for all the posts within the database. Each one of these posts is given a feedID like so:
$findShouts = $pdo->prepare('SELECT * FROM feed WHERE name IN (SELECT scoutingUsername FROM scout WHERE scoutedUsername =? OR scoutingUsername =?) ORDER BY timestamp DESC');
//execute query and variables
$findShouts->execute([$username, $username]);
if ($findShouts->rowCount() > 0)
{
//get the shouts for each scout
while($row = $findShouts->fetch(PDO::FETCH_ASSOC)){
$shoutID[] = $row['id'];
$shoutUsername[] = $row["username"];
$shoutName[] = $row["name"];
$shoutText[] = $row["text"];
$shoutTimestamp[] = $row["timestamp"];
}
$shoutCount = count($shoutUsername);
for($indexShout=0; $indexShout < $shoutCount; $indexShout++) {
print'
<div class=feedNewShout>
<div class=shoutInformation>
<div class=shoutName>
<p>'. $shoutName[$indexShout] .'</p>
</div>
<div class=shoutTimestamp>
<p>'. timeElapsed("$shoutTimestamp[$indexShout]", 2) .'</p>
</div>
<div class=shoutText>
<p>'. $shoutText[$indexShout] .'</p>
</div>
<input type="hidden" name="feedID" class="feedID" value="'. $shoutID[$indexShout] .'">
<div class=likesAndComments>
<div class=likesAjax data-id="'.$shoutID[$indexShout] .'">
</div>
<div class=commentsAjax data-id="'.$shoutID[$indexShout] .'">
</div>
<div class=deleteShoutAjax data-id="'.$shoutID[$indexShout] .'">
</div>
</div>
</div>
</div>';
}
unset($shoutID);
unset($shoutUsername);
unset($shoutName);
unset($shoutText);
unset($shoutTimestamp);
}
From this i use a jquery Ajax call in feedLikesAjax.js to find each individual feedID needed:
$(document).ready(function()
{
$(".likesAjax").each(function() {
var feedID = $(this).attr("data-id");
$.ajax({
url: "feedLikes.php",
cache: false,
type: "POST",
data: {feedID: feedID},
dataType: "html",
success: function(html){
$(".likesAjax[data-id='"+ feedID +"']").empty();
$(".likesAjax[data-id='"+ feedID +"']").append(html);
}
});
});
});
I use this information and pass it to feedLikes.php:
if (isset($_POST['feedID']))
{
$feedID = ($_POST['feedID']);
$findHasUserLiked = $pdo->prepare('SELECT username FROM feedLikes WHERE feedID =? and username=?');
//execute query and variables
$findHasUserLiked->execute([$feedID, $username]);
if ($findHasUserLiked->rowCount() > 0)
{
$hasUserLiked = $findHasUserLiked->fetchColumn();
echo<<<_END
<form action="feedLikes.php" id="unlikePostForm$feedID" method="post">
<button type="submit" class="unLikeButton"></button>
<input type="hidden" name="feedIDForUnlike" class="feedIDForUnlike$feedID" value="$feedID">
</form>
_END;
?>
<script type="text/javascript">
$(document).ready(function()
{
$('#unlikePostForm<?php echo $feedID ?>').on('submit', function (e) {
e.preventDefault();
var feedIDUnlike = $(".feedIDForUnlike<?php echo $feedID ?>").val();
$.ajax({
url: "feedLikesClicked.php",
cache: false,
type: "POST",
data: {feedIDUnlike: feedIDUnlike},
dataType: "html",
success: function(html){
location.reload();
}
});
});
});
</script>
<?php
}
else
{
echo<<<_END
<form action="feedLikes.php" id="likePostForm$feedID" method="post">
<button type="submit" class="likeButton"></button>
<input type="hidden" name="feedIDForLike" class="feedIDForLike$feedID" value="$feedID">
</form>
_END;
?>
<script type="text/javascript">
$(document).ready(function()
{
$('#likePostForm<?php echo $feedID ?>').on('submit', function (e) {
e.preventDefault();
var feedIDLike = $(".feedIDForLike<?php echo $feedID ?>").val();
$.ajax({
url: "feedLikesClicked.php",
cache: false,
type: "POST",
data: {feedIDLike: feedIDLike},
dataType: "html",
success: function(html){
location.reload();
}
});
});
});
</script>
<?php
}
$likesNumber = $pdo->prepare('SELECT count(*) FROM feedLikes WHERE feedID =?');
//execute query and variables
$likesNumber->execute([$feedID]);
$numberOfLikes = $likesNumber->fetchColumn();
print'
<div class=numberOfLikes data-id="'.$feedID .'">
<p>'. $numberOfLikes .'</p>
</div>';
}
?>
Like i said it all works perfectly apart from the reloading. Now i know the location.reload that is used on success is actually reloading every feedLikes.php for every post. But i'm really stuck on how to just reload the current feedLikes.php post that is needed for that specific post. I thought this would be really simple, and it maybe, but i cant find it anywhere.
Really grateful for any help. Thank you
There are lots of ways to do this. To achieve what you are actually asking you need to modify your jQuery success function to target only the div element for the post you are interested in. Either by adding a unique ID to the HTML, or using a selector based on the class and data-id attributes to identify that specific post.
Then yout PHP needs to only return the HTML which you want to modify and you have your jQuery success function insert that into the div for the relevant post.
Having said that, for what you are trying to do is there really any need to reload the post? You could have your PHP script just return the new number of likes and whether or not current user has liked the post and then update those values in your success call.
You could optimise your code a lot, the feedLikesAjax.js script is calling feedLikes.php once the page is loaded, creating a new ajax request for each post. You could combine the code from feedLikes.php into feed.php and have the server output the page with all the data immediately, and get rid of feedLikesAjax.js altogether. You could replace the likes and unlikes forms with a single button for each post and right now you are setting an event handler for each form individually, if you give them all a common class you can just use a single event handler.
EDIT
To answer your comment:
You don't need another query in your while statement. You can expand your first query using a left join to have it also include data from the feedLikes table in the returned results or you can use another subquery to your original query to add another column to your returned results. Something along the lines of this should give you a userLiked row with a value of 1 or 0 for liked/not liked. You might have to edit it a bit to get it working for you, I'm not an SQL guru by any means.
SELECT *, (SELECT COUNT(L.username) FROM feedLikes L WHERE L.feedID = F.id AND L.username = F.username) AS userLiked
FROM feed F
WHERE name IN (SELECT scoutingUsername FROM scout WHERE scoutedUsername =? OR scoutingUsername =?)
ORDER BY timestamp DESC

AJAX change comment on table row click

I'm currently developing a web app that demonstrates how to "sign" different words in ASL. There's a list of terms on the left, and a video and comment section on the right.
See screenshot here: http://i917.photobucket.com/albums/ad19/brycematheson/Screen%20Shot%202015-06-16%20at%2010.05.36%20PM.png
I'm struggling to get the comments to change using AJAX whenever a new term is clicked. Currently, the comments stay the same as new terms are selected. How would I go about using AJAX to change the comment section to update when a new term is selected?
My comment section looks like so. Updating the $id_post=3 section in PHP will change the comment to match the comments with that ID in the database, so that's not an issue, I just need it to do it on the fly.
Here is my comment code in my index.php page:
<?php
// Connect to the database
require_once('models/db-settings.php');
$id_post = '$_POST['rowID']; //the post or the page id
?>
<div class="cmt-container">
<?php
$sql = mysqli_query($mysqli, "SELECT * FROM comments WHERE id_post = '$id_post' ORDER BY id ASC") or die(mysqli_error($mysqli));
while($affcom = mysqli_fetch_array($sql,MYSQLI_ASSOC)) {
$id = $affcom['id'];
$name = $affcom['name'];
$email = $affcom['email'];
$comment = $affcom['comment'];
$date = $affcom['date'];
// Get gravatar Image
// https://fr.gravatar.com/site/implement/images/php/
$default = "mm";
$size = 35;
$grav_url = "http://www.gravatar.com/avatar/".md5(strtolower(trim($email)))."?d=".$default."&s=".$size;
?>
<div class="cmt-cnt">
<img src="<?php echo $grav_url; ?>" />
<div class="thecom">
<h5><?php echo ucfirst($name); ?></h5><span data-utime="1371248446" class="com-dt"><?php echo $date; ?></span>
<br/>
<p>
<?php echo $comment; ?>
</p>
<div style="float:right;"><span class="action">X</span></div>
</div>
</div><!-- end "cmt-cnt" -->
<?php } ?>
<div class="new-com-bt">
<span>Write a comment ...</span>
</div>
<div class="new-com-cnt">
<textarea class="the-new-com"></textarea>
<div class="bt-add-com">Post comment</div>
<div class="bt-cancel-com">Cancel</div>
</div>
<div class="clearfix"></div>
</div>
And my Javascript:
$('#matrix tr').click(function (event) {
var rowID = ($(this).attr('id')); //trying to alert id of the clicked row
$(function(){
e.preventDefault();
$.ajax({
type: 'POST',
url: 'index.php',
data: rowID,
success: function(msg) {
}
});
});
});
What am I doing wrong? Am I missing something?
Thanks in advance.
You aren't actually doing anything with the page once it's returned to you
success: function(msg) {
}
When the ajax completes successfully the code inside this function will execute, whatever was returned by the page will be inside the msg param.
success: function(msg) {
$('#comments-container').html(msg);
}
This will entirely replace the contents of the element(s) that have id="comments-container" with whatever the ajax request returned.
You might properly read the jQuery AJAX documentation page and study some of the examples. http://api.jquery.com/jquery.ajax/
Once you've fixed that you'll run into a problem where it still won't change, this is because you're not sending properly formatted POST data.
data: rowID,
In order to access the POST data like you are trying to (with $_POST[key]) the POST data also needs to be in key-value pairs.
data: "rowID=" + rowID,
Read the comments on the PHP manual page for the $_POST superglobal for a better understanding of this. http://php.net/manual/en/reserved.variables.post.php
EDIT: Oh and if you're planning on releasing this website to the public you might want to look at SQL Injection and how to harden your websites against it. As it stands this would be pretty easily broken into and your database compromised.

need to target 'delete' button to elements pouring out of a while loop in PHP

I have the following loop, which creates a list from a database:
for ($i=0;$i<count($tutor_subj);$i++){
$query_tutors = "SELECT level, subject FROM level, subject WHERE level.id = '$tutor_lvl[$i]' AND subject.id = '$tutor_subj[$i]'";
$result_t = mysqli_query($db_conx, $query_tutors);
while($m = mysqli_fetch_array($result_t)){
echo $m['level']." ".$m['subject']." ".$tutor_top[$i]."<div style='float:right; padding-right:5px;'><a href='#'><img src='images/remove_btn.png' onclick='removeSubj'></a></div></br>";
}
}
?>
As you can see I'm adding a 'remove' button in the html after each entry, and I want to use this button to allow the users to delete that particular row of data from the database if they choose.
My question is how can I link the row from this while loop to the button being generated at the end of each line (so that the appropriate entry is deleted in the DB)?
PS - I havent written the javascript/jquery function removeSubj yet because I'm stuck, hence am not including that
Add an unique identifier to onclick='removeSubj' so that when it is called, you can determine what you would want to delete. You could use something like onclick='removeSubj("unique_identifier")'. Replace that unique_identifier with something that is always unique for every row in your database (for example an id-field).
You can then use this value in your javascript function, and finally in your server-side script, to delete the correct row.
Let me give you and example to buttress #sumurai8s' point because i had the same issue before i read his answer.
assuming this is the item you intend to loop (i.e you have dynamically generated this from your php/database loop)
<div class="media-body media-right">
<span onclick="delete(<?php echo $fromDb['id']; ?>);" class="icon icon-trash-o icon-3x text-blood pull-lg-right"></span>
</div>
This is what your java script should be
//delete
function delete(I) {
// delete methodology
var id_to_be_deleted = I;
var formData = new FormData();
formData.append("id_to_be_deleted", id_to_be_deleted);
$.ajax({
type: "POST",
url: "/delete.php",
contentType: false,
processData: false,
//contentType: "application/json; charset=utf-8",
dataType: "json",
data : formData,
success: function()
{
alert('successs');
}
});
}
And delete.php should be
<?php
if ($_POST['id_to_be_deleted']) {
$delete = $_POST['id_to_be_deleted'];
//do db delete query here i.e DELETE FROM table_name WHERE id='$id_to_be_deleted'
...
}
if you don't do it this way you might be experiencing your DELETE ACTION being fired twice.
Don't thank me, thank #sumurai8 for waking me up from my slumber ;)
Happy coding.

Send data in Ajax response

hey I am trying to populate one select dropdown on the basis of another one using ajax. I have one select populated with portfolios and the 2nd one is empty. when I select an option from the 1st select box. I call an ajax function in which I send the selected portfolio id, In the ajax method I find the groups for the selected id, how can I populate the 2nd select with the groups I found. My code is
The form which contains two selects
<form name="portfolios" action="{{ path('v2_pm_portfolio_switch') }}" method="post" >
<select id="portfolios" name="portfolio" style="width: 200px; height:25px;">
<option selected="selected" value="default">Select Portfolio</option>
{% for portfolio in portfolios %}
<option get-groups="{{ path('v2_pm_patents_getgroups') }}" value={{ portfolio.id }}>{{ portfolio.portfolioName }}</option>
{% endfor %}
</select><br/><br/>
<select id="portfolio-groups" name="portfolio-groups" style="width: 200px; height:25px;">
<option selected="selected" value="default">Select Portfolio Group</option>
</select><br/>
</form>
The JS
<script>
$(document).ready(function(){
$('#portfolios').change(function() {
var id = $("#portfolios").val();
var url = $('option:selected', this).attr("get-groups");
var data = {PID:id};
$.ajax({
type: "POST",
data: data,
url:url,
cache: false,
success: function(data) {
//want to populate the 2nd select box here
}
});
});
});
</script>
Controller method where I find the groups for the selected portfolio
public function getgroupsAction(Request $request){
if ($request->isXmlHttpRequest()) {
$id = $request->get("PID");
$em = $this->getDoctrine()->getEntityManager();
$portfolio_groups = $em->getRepository('MunichInnovationGroupPatentBundle:PmPatentgroups')
->getpatentgroups($id);
return $portfolio_groups;
}
}
Any idea how can i send the portfolio groups and populate the 2nd select
thanks in advance
Use getJson instead of ajax();
Json (JavaScript Object Notation) , is the most easiest way to send structured data between php and javascript.
I Assuming here that the controller respond directly to the ajax query and that $portfolio_groups is an associative array with "id" and "name" as keys or an object with this same properties.
In your PHP controller send json data:
public function getgroupsAction(Request $request){
if ($request->isXmlHttpRequest()) {
$id = $request->get("PID");
$em = $this->getDoctrine()->getEntityManager();
$portfolio_groups = $em->getRepository('MunichInnovationGroupPatentBundle:PmPatentgroups')
->getpatentgroups($id);
echo json_encode($portfolio_groups);
}
}
Then use getJson to retrieve data and iterate over it :
$.getJSON(url, data, function(result) {
var options = $("#portfolio-groups");
$.each(result, function(item) {
options.append($("<option />").val(item.id).text(item.name));
});
});
Have a look to the getjson documentation for more detail about it
Check out this XML tutorial (someone out there is going to flame me for linking to w3schools) it's a good start.
AJAX requests are, in VERY broad terms, calls which make a browser open a window that only it can see (not the user). A request is made to the server, the server returns a page, the script that made the request can view that page. This means that anything which can be expressed in text can be transmitted via AJAX, including XML (for which the X in AJAX stands for).
How is this helpful? Consider, if you are trying to populate a drop down list, you need to return a list of items to populate it with. You COULD make an ajax call to a page http://www.mysite.com/mypage.php?d=select1 (if you are unfamiliar with GET and POST requests, or are a little in the dark regarding the more utilitarian aspects of AJAX, another full tutorial is available here) and have it return a list of items as follows:
item1
item2
item3
...
And scan the text for line breaks. While this certainly would work for most cases, it's not ideal, and certainly won't be useful in all other cases where AJAX may be used. Instead consider formatting the return in your PHP (.NET, ASP, whatever) in XML:
<drop>
<item>item1</item>
<item>item2</item>
<item>item3</item>
</drop>
And use Javascripts built in parser (outlined here) to grab the data.
What I would do is to use the $.load() function.
To do this, your getgroupsAction should return the options html.
The JS:
<script>
$(document).ready(function(){
$('#portfolios').change(function() {
var id = $("#portfolios").val();
var url = $('option:selected', this).attr("get-groups");
var data = {PID:id};
// Perhaps you want your select to show "Loading" while loading the data?
$('#portfolio-groups').html('<option selected="selected" value="default">Loading...</option>');
$('#portfolio-groups').load(url, data);
});
});
</script>
I don't know how $portfolio_groups stores the data, but let's say you'd do something like this in your response:
<?php foreach($portfolio_groups as $p) : ?>
<option value="<?php echo $p->value ?>"><?php echo $p->name ?></option>
<?php endforeach ?>
This way, the select will be filled with the options outputted by getgroupsAction.
The easiest way would be to return json string from your controller and then process it in the 'success' call of the $.ajax.
Lets assume, that your $portfolio_groups variable is an array:
$portfolio_groups = array('1'=>'Portfolio 1', '2' => 'Portfolio 2');
then you can return it from controller as json string like this:
echo json_encode($portfolio_groups);
Then in your jQuery ajax call you can catch this string in the response (the 'success' setting of the $.ajax). Don't forget to add setting dataType: 'json'
Roughly, your $.ajax call will look like this:
$.ajax({
type: "POST",
data: data,
url:url,
cache: false,
dataType: 'json', // don't forget to add this setting
success: function(data) {
$.each(data, function(id, title){
var node = $('<option>').attr('value', id).html(title);
// this will simply add options to the existing list of options
// you might need to clear this list before adding new options
$('#portfolio-groups').append(node);
});
}
});
Of course, you will also need to add the checks if the data is not empty, etc.
Supposing that the function getgroupsAction stays in a flat php controller ( not inside a class ) you should tell the server to execute the function
so at the end of file being called by ajax you should barely call the function first ( probably you did it! )
For your patents group result set, you can generate the select by php or by javascript
In first case you should do this:
//php
$options = getgroupsAction($_REQUEST);
$return = "<select name =\"name\" id=\"id\"><option value=\"\"></option>";
foreach( $options as $option){
$return.= "<option value=\"$option\">$option</option>";
}
$return .= "</select>";
echo $return;
Then in Javascript:
// javascript
var data = {PID:id};
$.ajax({
type: "POST",
data: data,
url:url,
cache: false,
success: function(data) {
//inside data you have the select html code so just:
$('#divWhereToappend').append(data);
},
error: function(data) {
//ALWAYS print the error string when it returns error for a more easily debug
alert(data.responseText);
}
});

Categories