I have implemented a user-generated keyword list for a project I'm working on, using jQueryUI autocomplete to suggest existing keywords.
On selecting the autocomplete suggestion, the returned string is added to the html of a div, as a child div.
I would like to add a removal function whereby the user can remove the child div if erroneously entered.
I've tried multiple suggested answers from Stackoverflow and elsewhere, but can't seem to get it working.
I've created a fiddle containing the pertinent elements.
The most logical solution to me was:
$('.keyword-entry').click(function(e){
var id = $(this).closest('div').prop('id');
$('#'+id).remove();
}
Though it would appear this doesn't work.
Whilst a solution to the problem would be very much appreciated to save my dwindling supply of coffee from running out this evening, I would also appreciate a rundown as to why I'm going wrong.
Thanks in advance.
Event delegation.
It's basically that you're attempting to attach an event to an DOM element that doesn't exist in the DOM at the time of load. Rewrite the .click() handler too:
$(document).on('click', '.trashYes', function () {
$(this).remove();
});
Fiddle: http://jsfiddle.net/6bBU4/
What it's doing is that, it's attaching the .click() event to the document (The top most DOM element) will travel down to find any new .trashYes, thus successfully executing the .remove(). This doesn't have to be bound to the document but to any DOM element within the document as well at load.
No need to get the id and then try and find it again, just do this...
$('<div id="'+id+'" class="keyword-entry" style="z-index:0">'+ui.item.value+' <--I want to remove this</div>')
.appendTo($('#keyword-list'))
.click(function(e){
$(this).remove();
});
when adding the keyword entry
Related
Question:
I am trying to build a dynamic form using jQuery. There are a few standard html form inputs in a row in addition to a CSS stylized "hidden checkbox" toggle button. (Example)
The first row is statically coded, and there is a button to add more rows to the form for batch submissions. JQuery applied to the .on(click) event works perfectly with the static content, but newly appended form rows ignore the binding. Even jsfiddle's dynamic display doesn't appear to function, though it is possible my fiddle example has a bug that my working copy doesn't have. (Fiddle)
/* activeToggle is the selector for the container and descendants,
// .toggleHappy is the hidden input element within activeToggle */
$(activeToggle).on("click", ".toggleHappy", function(e) {
e.preventDefault();
$(this).val(($(this).val() == 0) ? 1 : 0);
console.log($(this).val());
});
I have researched and found the common mistake of using .click() instead of delegating using .on(click, selector, fn()) and am thus using the latter now.
What is frustrating is I have another .on(click) that IS working with the dynamic content. (the remove function) So, I was hoping another pair of eyes might help me find out what my mistake is. I know this is very similar to other questions on the basic subject, but I have read quite a number of those discussions first, and have applied many of them to get where I currently am.
Updates:
I tried what Madhavan suggested and it does in fact work, but as expected, only for the first-child. So dynamically added rows are not pointed to. Thanks for the fast look. I feel like it might be a selector/scope issue, but whats weird is that once the page is loaded, I can type this directly into console and it works?
//this works run from console, but doesn't fire from a real click?
$(".theContainer .data .switch .toggleHappy").first().click();
ANSWER I have been working on another project in the interim and it is starting to look like .on(event, selector, fn) is not working at all for dynamically added items. But, I had a breakthrough! The other project was slightly simplified, and I found the following:
//.theContainer is static
//.data .switch .toggleHappy is the dynamic chain created
//does not delegate and bind dynamically
$(".theContainer").on("click", ".data .switch .toggleHappy", function() {});
//DOES work!
$(".theContainer").on("click", ".toggleHappy", function() {});
It would appear that a selector like .path .to .element only works well on existing static content, while .element allows .on() to be bound and delegated properly for dynamically generated nodes. See the updated fiddle.
The part that confused me was that hopping into the console and referencing dynamic elements with the full selector DID work on dynamic elements, but the events weren't delegated to them. Thanks again for the eyes that looked over this question, hope it helps someone else, because I still haven't found this on the web yet.
It appears that delegating jQuery events with .on() will only work on static content when the selector used within .on() is a list of consecutive elements. In my code, I had a single container which was static, I delegated an event to it referencing multiple elements between the container and the destination elements. It would work locally for any number of statically identified elements, but any dynamically added ones would ignore the bindings. It also would throw no errors, and it WOULD respond to lines of script executed within the console directly, using the same selector chaining as the function. I found the following:
//.theContainer is static
//.data .switch .toggleHappy is the dynamic chain created
//does not delegate and bind dynamically
$(".theContainer").on("click", ".data .switch .toggleHappy", function() {});
//DOES work!
$(".theContainer").on("click", ".toggleHappy", function() {});
It would appear that a selector like ".path .to .element" only works well on existing static content, while ".element" allows .on() to be bound and delegated properly for dynamically generated nodes. See the updated fiddle.
The part that confused me was that hopping into the console and referencing dynamic elements with the full selector DID work on dynamic elements, but the events weren't delegated to them. Thanks again for the eyes that looked over this question, hope it helps someone else, because I still haven't found this on the web yet.
$(activeToggle).on("click", function(e) {
e.preventDefault();
$(":first-child",this).val(($(":first-child",this).val() == 0) ? 1 : 0);
console.log($(":first-child",this).val());
});
I made a change like this and works fine. But I'm not sure why it is not triggering for '.toggleHappy' instead.
I’ve read many posts already on the $.each and newly added elements + event attachment. Many of the current Questions regarding this topic on StackOverflow don’t seem to work for me. $.on() is normally recommended since it allows us to append new elements and still maintain a single event listener + handler.
In my current code:
1.$(‘input[type="checkbox"]’).on(“change”, function(e){});
//I do a logical if-statement, if(this.checked) else
//With-in the if-statement I run $.each, however, once I have appended new element in this context a new li to the ul, it stops working.
Out of the curiosity has anyone encountered something like this before, and if YES, how have you folks solved this?
Some StackOverflow posts I have already seen:
jQuery $(element).each function doesn't work on newly added elements
jquery: dynamically appending li items to ul then adding click, but click runs through each li
Event binding on dynamically created elements?
Currently what you are using is called a "direct" binding which will only attach to element that exist on the page at the time your code makes the event binding call.
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.
As you are creating elements.
You need to use Event Delegation. You have to use .on() using delegated-events approach.
General Syntax
$(document).on(event, selector, eventHandler);
Ideally you should replace document with closest static container.
Example
$(document).on('change', 'input[type="checkbox"]', function(){
//Your code
});
I'm semi-new to Javascript/jQuery so apologies in advanced if I'm missing something basic. I have a function that is triggered whenever a user types in an element with a specific class.
$('.relevantClass').keyup(function(){
//code...
});
Now this function may end up, depending on the situation, creating a good deal of new HTML including new instances of relevantClass through the .append() method.
var newHTML = <div class='relevantclass'>Content...</div>;
$('#wrapper').append(newHtml);
However, the jQuery selector does not seem to detect and execute the function when a user types in the newly created relevantClasses. I've checked the newly created Html and it has the correct class tags and old instances of the relevant class due work.
I'm guessing this has something to do with .append(); messing with the DOM and I need someway to "refresh" the selector and let it do its jQuery thing researching the DOM to find the new classes. Any thoughts on how to do this? Is there some jQuery method I can't find?
You have to use on() to attach events that work on dynamic content:
var $parent = $("selector"); //the element you're appending .relevantClass to
$parent.on("keyup",".relevantClass",function(){
//code...
});
Keep in mind that to work with dynamic content, you have to attach the event to relevantClass's closest parent that exists on page load.
Some people use body, but you should get used to using parent elements as close as you can get to the dynamic content. This is so that event delegation occurs on a smaller scale.
More info on on() here.
Also, I hope that newhtml variable is wrapped in quotes.
$('.relevantClass').on('keyup', function(){
//code...
});
Try something like
$('body').on('keyup', '.relevantClass', function() { ... }
The idea is that you use an existing root element and use your class selector as a filter. See the examples here.
Is it better to attach the on() event to the document or a closer parent?
Note: Initially this question had another aspect and a different topic. It became obsolete really quickly (typo in the source code)
The best key for performance using jQuery is to use an id as the initial identifier. For example:
$('#my_id').on('click', 'tag.my_class', function () {
...
});
This allows jQuery to go straight to the container, and then begin trawling from there.
if you bind the "on" event to the closest parent will produce exactly what are you looking for, click function will works fine even if it is appended to document, but in future if you append any elements with class "clickable" will also get binded. so its always good practice to append the "on" event to closest parent rather than whole document.
if you want more specific you can use
$("ul.media-grid").on('click', 'li.clickable', function () {
alert("works")
});
as it will get the ul with the class "media-grid" and appends the event to the li's with class "clickable"
I got following problem: I generate a div with "jQuery-Load" links. Theese links inside the div should reload the same div with different parameters. I found a working solution, which generates theese links, which are clickable and... ...trigger the chosen event once. So clicking the same link inside the generated div, after it has been regenerated, doesnt work anymore. Tried a lot of things...
It looks like that now:
click
<div id="aaa0"> I'm the div - level1! </div>
div gets filled - beautyful.
It now contains this: (actually its generated what is why wrote [time] wich is time(); generated in php. as a changing parameter
[...] Link inside Updated Div [...]
when i click the link inside the div it works. when i click it again, it wont...
I want to generate a nice 'click deeper inside the data'-thing, which would be amazing getting this thing work and is the reason why everything must be as best as possible inside the "onclick" event :|
Sorry btw. for the a bit confusing post-style, its a confusing topic, and im not native speaking :)
Thanks for any help or hint in advance,
Harry
Maybe you're missing the concepts between bind and live. In bind, jQuery scans the document and attach a function direct to the element. In live, jQuery attach the function to the document, along with the event and the element as parameters. Once a event bubbles, jQuery check the event and the element, and if it match, then a function executes.
After the first run, the dom has changed, and its gonna work using live.
something like that should work:
click
<div id="aaa0"> I'm the div - level1! </div>
<script>
$('a').live('click', function (e) {
e.preventDefault();
var id = this.id;
$(this).next('div').load('getdetails.php?fNumber=36&env=fun&id=' + id);
});
</script>
basically, what is done is a generic rule, which gives all tags the same behavior. (load next div content). ".live()" is used so that loaded tags work (check the jquery documentation for .live(), or event delegation in general).
I'm not certain about the preventDefault stuff. You might want to use somehting else than tag for the link.
click
made the day :) I don't know exactly why, but maybe its possible preventDefault made the bind and live thing for me. Its working fine, so ...
thanks for the hints! :D