Handling jQuery click events on divs produced in a foreach loop - php

I have an HTML div:
<div id='text_icon_<?php $i++; ?>' class="text_icon">Some Text</div>
that I print inside a foreach loop. I am using ajax to handle the click() event on it and change its text to Done!, so I have an output like:
<div class="text">Done!</div>
If I run the loop 4 times and I click on one of the divs (i.e. the one with class text_icon) then only first one is working while the rest of the divs are not working.

Update:
Your update indicates the below is not the problem, the IDs are unique.
Without your jQuery code it's hard to help you debug, so here's an example of how it can be done:
HTML:
<div id='text_icon1' class='text_icon'>Div #1</div>
<div id='text_icon2' class='text_icon'>Div #2</div>
<div id='text_icon3' class='text_icon'>Div #3</div>
<div id='text_icon4' class='text_icon'>Div #4</div>
JavaScript code using jQuery:
$("div.text_icon").click(function() {
// Within the `click` handler, `this` points to the
// DOM element. If you're kicking off some ajax something,
// you'll probably be doing something like this:
// Grab `this` to a variable we can access from the
// `success` closure
var theDiv = this;
// Do our call
$.ajax({
url: "your_url_here",
success: function() {
// It worked, udate the div
$(theDiv).text("Done!");
}
});
});
Live copy
Original answer:
If you're really using "DIV id='text_icon' class="text_icon..../DIV", e.g.:
<DIV id='text_icon' class="text_icon">....</DIV>
...then the problem is that the id is not unique. ID values must be unique on the page (reference). That would seem to fit with the symptom you describe, with "only the first one" working. Most browsers, when given invalid HTML with multiple IDs, will use the ID on the first element in document order and ignore the remaining ones.
If you don't need the div to have an ID at all, you can just remove it. Otherwise, just ensure the ID is unique, e.g.:
<DIV id='text_icon1' class="text_icon">....</DIV>
<DIV id='text_icon2' class="text_icon">....</DIV>
<DIV id='text_icon3' class="text_icon">....</DIV>
<DIV id='text_icon4' class="text_icon">....</DIV>

As far as I can tell, you are giving your divs the same ID. Targetting multiple elements with the same ID is impossible, the IDs need to be unique.
Try this:
$i = 1;
foreach ($array as $al) {
echo "<div id='text_icon_$i'>blablabla</div>";
$i++;
}
Of course, you'll need to modify your jQuery code too to include a potentially unlimited number of such IDs (I don't know whether performance will be good this way, but I remember doing it once for a comments list on a blog).
Another way would be to use a common class rather than unique IDs :).

Apart from the arguments about unique IDs, could it also be that the click handlers need to be hooked up again after the ajax call? If so, it'd be better to use .live rather than .click.
$("div.text_icon").live("click",
function(event) {
var icon = $(this);
}
}

Related

Using a toggle with jQuery and PHP in a while loop doesn't work correctly

I have some problems with the jQuery toggler. I'm using a while loop in PHP and I'm showing database parameters in the page. The problem is that I'm using a "Details" parameter which is the largest one, and I want it to be displayed as none, and then click a button to make the data appears(toggle), and when I'm doing it, only works for even loops of the query, I mean, the first one doesn't work, but the second works perfectly... Here's my code:
<?php
$query = "SELECT * FROM datable where user = '".$userSESSION."'";
if ($result = mysqli_query($db, $query)) {
while ($row = mysqli_fetch_array($result)) {
?>
And then I've got the toggler where I get my data:
<script >
$('.cuenta_detalles_div').click(function(){
$('.cuenta_detalles_p').toggle();
});
</script>
<div >
<button class="cuenta_detalles_div">Detalles: <i class="fa fa-chevron-down"></i></button>
</div>
<div class="cuenta_detalles_p"><?php echo $row['detalles'];?></div>
};
}
?>
Tried typical toggle like
<script >
$('.cuenta_detalles_div').click(function(){
$('.cuenta_detalles_p').toggle();
});
</script>
and other similar, but only works for the first row, or even rows but not in all.
Bit hard to tell from how you've provided the code, but it looks like this $('.cuenta_detalles_div').click( is inside the php while loop and before the HTML it applies to.
This means
when it runs on the first row, the .cuenta_detalles_div doesn't exist so does nothing.
when it runs on the 2nd row (even row) it actually applies to the first row.
3rd row it applies to the 1st and 2nd row, but the 1st row already has an event handler to toggle, to toggles twice (so appears not to work at all).
Put your event handlers away from the HTML they apply to and wrap them in inside document ready, so there's only 1 event handler.
$(function() {
$('.cuenta_detalles_div').click( ...
This will fix the 1st issue, however it will then apply the click to all of the matching divs, so you need to use this inside the click:
$(function() {
$('.cuenta_detalles_div').click(function() {
$(this).closest("div").next().toggle();
});
});
(assuming you don't change your HTML structure)

Toggle generated table and images with jQuery

I tried to make a function which would accept a number when called, and hide any loop generated elements on page with the ID of #sub + the number provided.
<script>
function toggleryhma($id) {
$("#sub"+$id).toggle();
$("#ryhmanum"+$id).toggle();
}
</script>
The element I'd need to click to call the function is...
<span class=ryhmaspan onclick="$(toggleryhma('<?php echo $ryhmanum;?>');">
For some reason this doesn't seem to do anything. I basically have lots of images with the ID's "#sub1", "#sub2", "#sub3", etc...
Same with the #ryhmanum. I want to use those ID's to only toggle the items under the span I'm clicking.
The problem is in your onclick. Your onclick should be like below.
onclick="toggleryhma('<?php echo $ryhmanum;?>')"

How to make drag and drop using dragula js dynamic

I am trying to create a section using dragula js just like this:
http://bevacqua.github.io/dragula/
What I want is, the drag and drop should be dynamic. So that on each drag and drop the position of each element should be saved. How can I do that?
I know it can be done with php and ajax. But no idea on how the position should be manipulated
This question can be broken down into 2 different problems.
How do I keep track of the order of elements?
From what I can tell, dragula does not have a concept of tracking positioning of elements. You will have to devise a way to identify the parent container and the draggable items element. (div in the example). If you need to create the parent containers dynamically, you will need to track their order too. If you have a predefined layout, then all you need to do is track elements order and what parent they belong too. (for example, left or right, if we use the dragula example).
Create an id for each draggable element. You will have something like this.
<div id="left">
<div id="element1">Some text</div>
<div id="element2">Some other text</div>
</div>
When an element is dropped you will need to capture the element that was dropped and it's order to the parent container. To do this, you can use the jQuery index function to find the new index relative to the parent container. You will then need to reorder the list as you have it saved on the server side.
draggableElements.on('drop',function(el)
{
var parentElId = $(el).parent().attr('id');
var droppedElIndex = $(el).index();
var droppedElId = $(el).attr('id');
$.ajax({
url: "itemDropped.php",
type: 'GET',
data: { parentIdParam: parentElId,
droppedIndexParam: droppedElIndex,
droppedIdParam: droppedElId }
}).done(function() {
//do something else
});
});
How do I save the ordering of the elements?
This depends on your requirements. If you are saving the heirarchy to a database you will need to save the parent container ID for each element, the order or position it is in and the elements ID.
To rerender the page with the elements in the same order they were dropped in you would simply loop over all the elements in each container and render them in the order they are saved.
Review this [http://codepen.io/rachelslurs/pen/EjKmLG]
Also other example mostly similar with your dragula js example
sample code for to check and customize

How to show/hide one dynamic element (div) at a time with jQuery

This is my first attempt at jQuery and I'm using a basic tutorial I found here: http://papermashup.com/simple-jquery-showhide-div/#
This is my current code and how the jQuery works: http://jsfiddle.net/mZQsu/
As you can see, when you click the '+/-' it opens all 4 of the tables/DIVs.
How can I modify this code to open just the relevant secondary table/div according to the original table?
(Please note the secondary tables are generated dynamically from PHP and SQL data)
Thanks.
P.S all my code is here http://jsfiddle.net/mZQsu/ instead of clogging up this question page :)
DEMO fiddle
$('.toggler').click(function() { // had to differentiate the main togglers with a new class
var ind = $(this).parents('tr').index()-1; // could change
$(".slidingDiv").eq(ind).slideToggle();
});
$('.show_hide').click(function() { // this are the 'togglers' inside the big menus
$(this).parents(".slidingDiv").slideToggle();
});
The best solution would be if you tag each of your div's with an id. E.g.
<div class="slidingDiv" id="ip_127_0_0_1">
and then modify the equivalent links to do
$("#ip_127_0_0_1").slideToggle();
so just the associated div gets expanded.
See my updated fiddle: http://jsfiddle.net/mZQsu/1/
You can use the index of the row, and toggle only the matching row of the other table using jQuery index and eq
See the relivant docs here:
jQuery index
jQuery eq
This should work:
$('.show_hide').click(function() {
$(this).parents(".slidingDiv").slideToggle();
});
Since the slidingDiv class is a direct parent of the show_hide link, I could have used "parent" rather than "parents". The latter provides more flexibility because it traverses all ancestors looking for the class.
Here is a modified code - http://jsfiddle.net/mZQsu/3/
I have added show-hide1, show-hide2, show-hide3, show-hide4.
And clicking on it opens respectively slidingDiv1, slidingDiv2, slidingDiv3, slidingDiv4.
When you are binding to an event: You can always grab that event target and reference it.
$('.show_hide').click(function(e) {
$(e.target).parent("div.slidingDiv").slideToggle();
});
.parent() is a good place to start, but .closest() also might work. That being said, this is the preferred way to go about it.
On a side note if you ever want to do the opposite you could use .not(e.target) and all the other elements except for the one your click will be called.
Since your html is PHP-generated, it should not be a problem to include unique IDs for both +- links and sliding divs, for example:
a href="#" class="show_hide" id="show_hide2"
And
div class="slidingDiv" id="slidingDiv2"
Then in your click function you get the index of the div that you want to open:
$(.show_hide).click(function(){
var $str = $(this).attr('id');
var $index = $str.charAt( $str.length-1 );
});
Now you can use index to open the div:
var divName = "#slidingDiv" + $index;
$(divName).slideToggle();

PHP variable as part of a jQuery function doesn't work, but plain text does

I have the following jQuery code in my PHP file (edited Jan 19 2010 # 10:40 MST):
<?php
$count = 0;
foreach($attachments as $attachment) :
echo '<script type="text/javascript">
$(\'#a_'.$count.'\').click(function() {
$(\'#d_'.$count.'\').show(200);
});
// if "no" is clicked
$(\'#d_'.$count.' .no\').click(function() {
$(\'#d_'.$count.'\').hide(200);
});
// if "yes" is clicked
$(\'#d_'.$count.' .yes\').click(function() {
$(\'#d_'.$count.'\').hide(200);
// update database table -- this is why I need the script inside the for loop!
var jsonURL = \'http://path/to/update_db_script.php\';
$.getJSON(jsonURL, {\'post_id\' : '.$attachment->ID.'}, function(data) {
alert(\'Thank you. Your approval was received.\');
});
$(\'#a_'.$count.'\').replaceWith(\'<span>Approved</span>\');
});
</script>';
echo '<li>';
if($attachment->post_excerpt == 'approved') {
// Check the proof's status to see if it reads "approved"
echo '<span>Approved</span>';
} else { ?>
// If not yet approved, show options
<a class="approve" id="a_<?php echo $count; ?>" href="#">Click to Approve</a>
<div class="confirm-approval" id="d_<?php echo $count; ?>">
<p>Please confirm that you would like to approve this proof:</p>
<a class="yes" href="#">Yes, I approve</a>
<a class="no" href="#">No, not yet</a>
</div><?php
} ?>
</li>
<?php $count++;
endforeach; ?>
The page in question is available here. The "click to approve" links do not work (that's my problem).
When I view source, the PHP variables appear to have echoed properly inside the jQuery:
<script type="text/javascript">
$('#a_0').click(function() {
$('#d_0').show(200);
});
... etc ...
</script>
This looks correct, but nothing happens when I click any of the links. However, when I replace the PHP echo statements with plain numbers (0, 1, etc.) the click functions work as expected.
You may be asking: why on earth do you have this inside a for loop? The reason is that I need to retrieve the attachment->ID variable and pass it to an external PHP script. When someone clicks "approve" and confirms, the external script takes the attachment->ID and updates a database value to read "approved".
Why won't the click function fire when PHP is in place? Is there some kind of greater force at work here (e.g., hosting limitation), or am I missing a fundamental piece of how PHP and JavaScript interact?
Since you didn't post your HTML its a little hard to troubleshoot.
First, I am not sure why one is working and the other is not since the code it is outputting looks correct. Either way, I still would make some changes. Move your a_0,a_1, etc and d_0,d_1, etc into the id attribute instead of a class:
<div>Click Me</div>
<div class="confirm_approval" id="d_0">Show Me</div>
<div>Click Me</div>
<div class="confirm_approval" id="d_1">Show Me</div>
Now, instead of outputting your code in a loop in PHP, place this jQuery code once on your page:
$(document).ready(function(){
$("a.approve[id^='a_']").click(function(e){
var id = this.id.replace('a_',''); // Get the id for this link
$('#d_' + id + '.confirm-approval').show(200);
e.preventDefault();
});
});
This code finds any a element with the approve class that has an id that starts with a_. When this is clicked, it grabs the number off the id a_0 = 0 and uses that id to find the confirm-approval element and show it.
Since the javascript is run on the client and has no way of knowing whether the script was generated using PHP or not, I think that particular part is a wild goose chase...
When I replace the PHP echo statements
with plain numbers (0, 1, etc.) the
click function works as expected.
Do this again and compare the actual output using view-source in a browser. I'll bet you find that there is a difference between the working and failing scripts, other than one of them being generated by PHP.
It seems that the problem is in jQuery selectors. Instead of dynamically binding click() events on multiple objects with an output of PHP code, use just one class selector and bind to objects with this class. And you can specify an id attribute to make them unique.
Something strange too is to have the script tag and the
$(document).ready(function()
in the loop. I don't know if this causes any problems, but it's sure not very efficient, one time is enough.

Categories