Appended Elements Using .on Method Unable To Be Removed - javascript

jQuery is deciding to be dumb or I'm simply missing something, but removing appended elements does not work for me using the following code:
$('#add-show').click(function() {
if ( $('#fav-search').val() == '' ) {
// do nothing
}
else {
$('.fav-results').append('<code><span class="icon-remove"></span>' + $('#fav-search').val() + '</code>');
}
});
$('.fav-results code').on('click', 'a', function() {
$(this).parent().remove();
});
And the HTML for anyone who is interested:
<div class="input-append">
<input class="span2" id="fav-search" type="text">
<button class="btn" type="button" id="add-show"><span class="icon-plus"></span></button>
</div>
<div class="pull-right fav-results">
<?php foreach($shows as $show): ?>
<code><span class="icon-remove"></span><?php echo $show['showname'] ?></code>
<?php endforeach ?>
</div>
Existing titles pulled from my database table are able to be removed but no appended elements can be.
I originally was using a .click handler but I read that it only works for elements existing in the DOM at the time of page load. After reading previous questions of the same nature I changed to using .on but it's still acting the same.

For your click event to apply to dynamically created elements, you should delegate it to the ancestor <div> instead of the <code> elements:
$(".fav-results").on("click", "code a", function() {
$(this).parent().remove();
});

You are using remove() instead of detach() which is removing the event handlers on all of the code elements before they are executed.

Related

Add listener to dynamically added HTML within closure?

I have a list of locations in google maps that a user can click. When they click, I generate a template that displays the information for that place. Right now, I have a container div that I call .replaceWith() on with the newly generated template.
When a user tries to click a button in that template, I want a place-specific action to take place (e.g. pin the place). To do this, I need the place ID saved somewhere so that the listener code knows what to do. I was hoping to use a closure to create the listener on the fly so that I could "enclose" the ID of the place that the viewer is getting details for:
function selectPlace(place_id) {
// Swap out the old template
$("#listing-placeholder").replaceWith(listing_info_template(place));
// Create a listener to handle clicks while remembering the place_id
(function(){
$('.save_button').click(function(){
alert("Clicked handler for " + place_id);
});
})();
}
This doesn't seem to work at all; my listener never fires. It seems like this is related to the fact that .save_button is inside of the template (dynamically added). Not sure why this is.
I am hesitant to use .on() because then I would have to put the ID somewhere in the template, which feels really hacky to me. I know that backbonejs somehow binds events to dynamically inserted templates so that any relevant context is still available to events -- that's effectively what I'm looking to mimic here.
So, any suggestions on how I can add a listener to a dynamically created element in such a way that the listener receives key information about the "object" that element is conceptually representing, without bloating the HTML with extra metadata (I've seen people make the id's like "save_button-" and then split on the dash, but that seems extremely hacky?)?
Thanks!
I've used a variable with a broad scope to hold selected Id in the quick and dirty example below.
var selectedId; //Holds seleced ID
function selectPlace(place_id) {
// Swap out the old template
//$("#listing-placeholder").replaceWith(listing_info_template(place));
$("#listing-placeholder").replaceWith($("#section" + place_id));
//Sotre the ID here
selectedId = place_id;
}
$(document).ready(function() {
$("#cbId").change(function() {
selectPlace($(this).val())
});
//Set up event listener. Change #target as appropriate for you
$("#target").on("click", ".save_button", function() {
alert(selectedId);
});
});
#sections {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
<label>Select a section
<select id="cbId">
<option></option>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
</label>
</div>
<div id="target">
<div id="listing-placeholder">
I'm the place holder
</div>
</div>
<div id="sections">
<!--No Event Listeners Will be bound directly untill template is replaced -->
<div id="section1">
<h2>I'm section 1</h2>
<input type="button" value="Save Button" class="save_button">
</div>
<div id="section2">
<h2>I'm section 2</h2>
<input type="button" value="Save Button" class="save_button">
</div>
<div id="section3">
<h2>I'm section 3</h2>
<input type="button" value="Save Button" class="save_button">
</div>
</div>
I will just try to correct your actual approach by passing the parameter to your closure, but you may find a better approach.
In your case you need to pass the place_id as a parameter to the closure too, this is how should be your code:
function selectPlace(place_id) {
// Swap out the old template
$("#listing-placeholder").replaceWith(listing_info_template(place));
// Create a listener to handle clicks while remembering the place_id
(function(id){
$('.save_button').click(function(){
alert("Clicked handler for " + id);
});
})(place_id);
}
I changed the variable name so you can get the difference between the two parameters.
You actually have to use .on, it's the way jQuery matches all dynamically added elements. But you don't need to do anything "hacky", you just have to bind the listener to a parent element
`$(parent).on('click', '.save_button', {});
function selectPlace(place_id) {
// Swap out the old template
$("#listing-placeholder").replaceWith(listing_info_template(place));
// Create a listener to handle clicks while remembering the place_id
$(document).on('click', '.save_button').click(function(){
alert("Clicked handler for " + place_id);
});
}

Removed DOM element still appears on the page [duplicate]

This question already has answers here:
How to remove an HTML element using Javascript?
(11 answers)
Closed 8 years ago.
I'm trying to add/remove a DOM element (id ="result") dynamically. The addition seems to work fine but after removal the element still appears on the page.
What's happening here? What am I doing wrong?
Here is my code:
<!DOCTYPE html>
<html>
<body>
<script>
function clearResult() {
if (document.getElementById("result") != null){
alert("remove #result");
$("#result").remove();
if (document.getElementById("result") != null) {
alert("#result still exists");
}
}
alert("Exiting clearResult");
}
function search() {
clearResult();
if (document.getElementById("result") == null) {
alert("add #result");
$('<table id="result"><tr>I am a table</tr></table>').appendTo('#ex');
}
}
</script>
<div>
<button id="search" onclick="search()" value="Send">Search</button>
</div>
<div id="ex">
#*Add result table here dynamically*#
</div>
</body>
</html>
Your HTML is invalid. Content within a table needs to be in td tags. Without those, your code is being rendered as:
I am a table
<table id="result"><tr></tr></table>
You can see that then removing the #result element appears to do nothing, because the text does not disappear. If you change your code to include the td elements, it works fine:
$('<table id="result"><tr><td>I am a table</td></tr></table>').appendTo('#ex');
Example fiddle
Note that you can also massively simplify your code. You don't need to check for the existance of an element before removing it in jQuery. Also, you should use jQuerys event handlers, instead of outdated on attributes. Try this:
<div>
<button id="search" value="Send">Search</button>
</div>
<div id="ex"></div>
$('#search').click(function() {
$('#ex').empty().append('<table id="result"><tr><td>I am a table</td></tr></table>');
});
Updated fiddle
I use empty() here on the #ex element to save a selector, it has the same behaviour as remove(), except is performed on the children of an element, not the element itself.

jQuery on not working for dynamically added elements [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 9 years ago.
I want to use .on on dynamically created elements... Although its not working, and yes I am using a selector :)
$(".metadata").on("click", "i.icon-remove", function () {
console.log("what");
$(this).parent(".metadata").slideUp(function () { $(this).remove(); });
});
This works perfectly for existing content, but not for anything thats dynamically created. Both initial and dynamic content use the exact same creation method so I know their signatures are the same, any ideas?
Here is my HTML as it stands, the first item is present in the HTML, the second is dynamically created
<div class="metadata">
<input type="text" value="" style="width: 200px;">
<i class="icon-remove"></i>
</div>
<div class="metadata" style="">
<input type="text" maxlength="100" style="width: 200px;">
<i class="icon-remove"></i>
</div>
Try this
$(document).on("click", ".metadata i.icon-remove", function () {
console.log("what");
$(this).parent(".metadata").slideUp(function () { $(this).remove(); });
});
As an addendum to Pranav's answer, avoid if at all possible doing delegated events off of $(document) - that results in all events that happen anywhere in the page being inspected for matches to your selector.
Far better would be to use a more targeted selection that exists on the page from the start. Something like
$('#otherDivThatsThere').on("click", "i.icon-remove", function () {
console.log("what");
$(this).parent(".metadata").slideUp(function () { $(this).remove(); });
});
Where, again, #otherDivThatsThere is already in your dom at the moment that line of code is run.

How do I get the value of this textarea jquery

I am trying to get the value of the textarea (class="caption_textarea") when clicked on the link with class "save_caption".
The value of the textarea is changed with ajax and I am not including that here and therefore it is not always empty.
I have following HTML code:
<div class="caption_text" style="display:none;">
<div class="small_icons">
<img src="<?php echo base_url('public/images/tick.png'); ?>"/>
<img src="<?php echo base_url('public/images/delete.png'); ?>"/>
</div>
<textarea id="<?php echo $image_name_without_path[0]; ?>" class="caption_textarea" cols="32" rows="2" name="caption_text"></textarea>
</div>
I tried jquery's next, closest and find methods but I am unable to retrieve the value of the closest textfield's value to the a element clicked. Jquery code below:
jQuery(document).ready(function($) {
$('.save_caption').live("click", function() {
alert($(this).closest('textarea').find('.caption_textarea').val());
});
});
jQuery(document).ready(function($) {
$('.save_caption').live("click", function() {
alert($(this).closest('.caption_text').find('.caption_textarea').val());
});
});
JS FIDDLE
You can find the cpmmon parent caption_text using .closest() then find the textarea inside it using .find()
jQuery(document).ready(function($) {
$('.save_caption').live("click", function() {
alert($(this).closest('.caption_text').find('.caption_textarea').val());
});
});
closest() looks for the closes ancestor. You might want to try next() or nextAll()
jQuery(document).ready(function($) {
$('.save_caption').live("click", function() {
alert($(this).next('textarea.caption_textarea').val());
});
})
or something similar should work fine.
Change the selector a bit. First take parent of .save_caption then look for its siblings having .caption_textarea class. Your code is a bit modified below -
jQuery(document).ready(function($) {
$('.save_caption').live("click", function() {
alert($(this).parent().siblings('.caption_textarea').val());
});
});
Hope it will work.
Why are you using closest? I'm possibly missing some detail of your code.
Either way, wouldn't the solution be:
alert($('.mytextarea').val());
Or:
alert($('.mytextarea').html());
If your problem is that the class isn't unique to that text area (I would use an id but that's up to you), try:
alert($(this).next().val());
You can use 'textarea.mytextarea' to keep it strictly to textareas or .next('textarea').
Corrections and editions are welcome.
ps: make sure "this" is giving you the correct element.

JQuery .on only firing once on dynamically generated elements

So I have the following problem. I am trying to add a two events to a table of checkboxes.
Here's an example of the html.
<body>
<div id='container'> //static element, everything beyond this element is dynamic
<div id='pane_x'>
<div id='bottom_x'>
<div id='bottom_left_x'>
<div id='results_x'>
<div id='list_x'>
<div id='table_1'>
<table>
<tbody>
<tr>
<td>
<input type='checkbox' name='blah' id='blah_obj.id_x' class='blahblah'>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
I am trying to select the checkboxes only hopefully by using a prefix selector [id^='blah_']. I am able to get the code working for the first pane ie: pane_0, but it doesn't fire on pane_1 or beyond.
jquery(document).on("change", "[id^='blah_" + obj.id + "']", function() {
//code here
});
There may be nesting errors as I just made an approximate estimate of the html. The weird thing is I can see them by using a daisy chained .children() statement, but I can't select the input elements.
Since the comments don't support the same code blocks as this section I'll just add it here:
jquery(document).on("change", ".checked", function() {
var ids = jquery(this).attr("id").split("_");
if (ids[0] === "blah")
//do code
}
});
edited the id for clarity. The id structure is "blah_" obj.id "_" individual iterator. So 3 checkboxes on pane 0 would look like this:
blah_0_0
blah_0_1
blah_0_2
there are 2 other sets of checkbox lists on this page that I do not want to target with these functions, that is why i'm using the prefix selector.
The point of using startsWith selector is not to try to complete the whole value as you are doing with obj.id if obj.id is even defined.
Following would find all input with ID's starting with 'blah_' either existing or in the future.
jQuery(document).on("change", "input[id^='blah_']", function() {
//code here
});
Using the class as selector makes even more sense if they all share a common class
jQuery(document).on("change", "input.blahblah", function() {
//code here
});
Also note you have typo in jquery should be jQuery unless you have defined it otherwise in your own code
Important note ID's may not be repeated in a page, in case you have been repeating the same checkbox ID. They must be unique by definition
here another sample :
$("body").on({
click:function(){
// where $(this) is the current item changed
}
}, "input.blahblah");
​

Categories

Resources