Jquery .remove() only acts on second click - javascript

I'm building out a notifications feature with bootstrap popover. A notification should be removed after a user clicks on it, which is intuitive. However, it takes two clicks to make it work -- the first time, nothing seems to happen. The click listener is firing both times as discovered through alert().
I've simplified my problem to its most basic reproducible form in this fiddle js:
https://jsfiddle.net/ksun78/758n1azu/36/
$('body').on("click", ".popover-body .notif-popup-container", function() {
$("#" + $(this).attr("id")).remove();
})
Placing code above because it won't let me submit without code snippet, though the fiddle js should have all you need.
Can someone explain what the issue might be and how to fix it? Thanks!

I think the problem is that the popover library clones your elements so there are two elements with the same Ids. You can modify your code like this so it will work but better to avoid same Ids
$('body').on("click", ".popover-body .notif-popup-container", function() {
$(`[id="${$(this).attr("id")}"]`).remove();
})

If you simply want to delete that div you can use following code:
$(document).on("click", ".notif-popup-container", function() {
$(this).remove();
});

It turns out that behind the scenes, popover will make a copy of the elements and display them. This means that using ONLY the ID to remove the elements won't work, because it will first remove the display:none element on the page, then the copy of that shown in the popover. Thanks to #Gabriel for pointing that out.
The solution here was just to not use the id attribute of the element as it was unnecessary. A simple $(this).remove() will do the trick.
As for the issue of duplicate id's: I was originally intending on storing the notification id inside a "data-id" attribute. However, retrieving "data-id" using jquery was returning undefined, so I opted for the "id" attribute instead. Maybe #Gabriel can provide some insight into the issue of "data-id" being undefined, as it seems like a popover related issue as well.

Related

Assigning JQuery On Click Function in For Loop

I have a function that dynamically creates div elements based upon whatever input is given, and lets them choose certain items by clicking on each div. I have it so that if the div is clicked, a function (named checkToggle) is called that makes it looks like it is selected and adjusts some related variables. There is a checkbox in the div element that is toggled by this function (hence its name). Long story short, I had to jump through some hoops to get it to work, most of which I don't even remember. Please don't ask me about that.
The point of this question is this. I initially used the following JavaScript code to run the function when the checkbox was clicked. It was assigned by the main function, which created these div elements using a for loop.
document.getElementById(`${itemID}-checkbox`).onclick = function() {
checkToggle(`${itemID}-checkbox`);
};
This works, but I wanted to try to convert all of my onClick functions to JQuery. Here is the JQuery alternative I created.
$(`${itemID}-checkbox`).on(`click`, function() {
checkToggle(`${itemID}-checkbox`);
});
While the code itself seems to be fine, it does not work. It seems as if JQuery functions cannot be created like this in a for loop or something. It is applied after the element is created and put in its place, so I don't think it has anything to do with the element not being ready. I am also having the same issue with 2 other similar cases. Any idea as of why this isn't working?
Let me know if more information is needed and if so, what kind of information is needed.
You need to update the selector to Target HTML id using the # character. Simply prepend the character to the query:
$(`#${itemID}-checkbox`).on(`click`, function() { checkToggle(`${itemID}-checkbox`); });
It would also apply to DOM methods querySelector or querySelectorAll as well.
Hopefully that helps!

jQuery Waypoints add class when element is scrolled into view

I'm using the Waypoints plugin to check if an element is scrolled into view. I have multiple divs with class item as the user scrolls down the page, I want to add a class "viewed" to each.
$(".item").waypoint(function(){
$(this).addClass("viewed");
console.log("yey");
});
The console.log works, but the .addClass doesn't. Does the plugin not support $(this)?
I finally got it working.
$(".item").waypoint(function(){
$(this[0,'element']).addClass("viewed");
});
The this wasn't pointed at the element, so I needed to target it.
You have to be careful when calling these callback functions, and what this really means. In this instance, its probably referring to your function.
Doesn't the event trigger pass the target in the function as an argument? Try using that. If you want to know what your nested this really is, console.log it.
$(".item").waypoint(function(thing){
$(thing).addClass("viewed");
console.log("yey");
});
The checked answer caused loads of errors in newer version of this plugin.
This is what works for me:
$(".item").waypoint(function() {
$(this.element).addClass("viewed");
});

Jquery remove function follow up

I submitted this question last week:
chrome not working with jquery remove
and was able to resolve it (stupidity on my part really), however my example was very simple. Currently I'm trying to use .remove to eliminate a complete div from a page before sending an array of inputs to an ajax function. However, I am not able to get .remove to work at all.
Here's my latest try:
http://jsfiddle.net/CJ2r9/2/
I get function not defined on the jsfiddle on multiple browsers. On my application I get absolutely no errors, but nothing works either.
I'm relatively new to javascript scopes, so if the problem is scope-wise then please let me know how I'm screwing up.
I have also tried using the .on jquery function, but it's a bit more confusing considering my div ids are dynamically loaded from the server (jstl, spring MVC, etc). If that's a solution please let me know how I can get on the right track.
Thank you!
The two problems in your jsFiddle are:
Scope: removeElem is not in global scope, since you left the default configuration option to execute the code on DOM ready. You can change it to "no wrap" to make the funciton global.
The elements you want to remove don't exist. The div elements have IDs like "removeXXXp" and in your event handlers you pass "removeXXXs".
Here is an other, simpler solution (in my opinion) for element removal. Given your markup:
<div class="scheduleSet" id="remove315p">
<!-- ... -->
Remove
</div>
You can use .on like so:
$('.schduleSet a.optionHide').on('click', function() {
// traverses up the DOM tree and finds the enclosing .schduleSet element
$(this).closest('.scheduleSet').remove();
});
You don't even need IDs at all.
I made a simple fiddle, the inline onclick doesn't see the function defined in javascript so I get a ReferenceError: myRemove is not defined.
By adding the listener in js, .remove() works fine.
Sorry I don't know what causes the difference in behavior though.
Test it out: http://jsfiddle.net/xTv5M/1/
// HTML5
<div id="removeme">foo bar</div>
<button onclick="myRemove('removeme')">Go</button><br>
<div id="removeMe2">foo bar</div>
<button id="go2">Go Again</button>
// js
function myRemove(name){
$('#'+name).remove()
};
$('#go2').click(function(){ myRemove('removeMe2') });
I see that you are already using jquery. Why dont you do it this way:
<div id="foo">This needs to be removed</div>
Remove
function removeElem(element){
$('#'+element).remove();
}
$(function(){
$("#remove").click(function(){
removeElem($(this).data('remove'));
});
})
Fiddle here: http://jsfiddle.net/vLgpk/
They way this works is, using data-remove (can be anything like data-xyz btw), binds the remove link with the div. You can then read this binding later when remove is clicked.
If you are new to jQuery, and wondering what data-remove is, its just custom attribute that you can add to you code which can be later retrieved using the data() call on the element. Many great frameworks like Bootstrap use this approach.
Advantage of using this approach in my opinion is you can have the remove links anywhere in your UI and they don't need to be related structurally to your divs by siting inside them.

jquery onclick is not working

I am dynamically creating a link, and I am trying to add a click function to it. The links are being added, but the click function is not working. I dont see anything in the console, nor do I get an alert.
var section = $('<section></section>').append('<a class="link" href="#"></a>');
section.find('a.link').attr('title', post.data.permalink)
.text(post.data.title)
.click(function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
items.push(section[0].outerHTML);
$('#posts').empty().append(items.join(''));
One of the most common mistakes with jQuery. When dynamically adding elements, normal jQuery event handlers don't work, so you need to use .live() to be able to bind events to dynamic elements. This should work:
var section = $('<section></section>').append('<a class="link" href="#"></a>');
section.find('a.link').attr('title', post.data.permalink)
.text(post.data.title)
.live("click", function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
items.push(section[0].outerHTML);
$('#posts').empty().append(items.join(''));
Notice the use of .live("click", function() { ... }); there? That should solve your problem.
That looks okay. You may try using each() to iterate over that collection. I'm not sure if you can bind even handlers to a jQuery collection like that.
section.find('a.link').each(function(){
$(this).attr('title', post.data.permalink)
.text(post.data.title)
.click(function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
});
If running this in IE be sure that developer-tools (F12 )are present , otherwise console will be undefined and the call of console.log() will force an error and stops the function from executing.
What else: outerHTML is IE-only, you'll better forget it and never use it.
You don't need to manually join the HTML.
You're binding the event to an element, then taking the HTML of that element and just concatenting it into a string, which is then in turn inserted into the DOM as new elements when you append to #posts.
items is not defined here, but I'm going to go out on a limb and assume it's an array of generated <section>s and etc?
If that's the case, I might be missing something you're trying to do here, but it seems you could just eliminate the whole concatention of HTML and simply append the items array, which would preserve the bound click event.
// Push the element, don't stringify it.
items.push(section);
// Then simply append the "items" elements.
$('#posts').empty().append(items);
Sure, live would probably solve the problem as well, but you certainly can bind events to generated elements then insert them into the DOM. What you cannot do is bind an event to an element then print out it's HTML and insert that into the DOM. Any binding you made with the original element is lost.

JQuery event selector

Say i have 10 small images that i want to use as tooltips.
Im assinging them all the same class, '.helper'
Im selecting helper, then calling
mouseenter(function() { $(".helper").stop(false,true).fadeIn(); })
I then want a div to popup, containing some text. This works fine if there's only one tooltip on the page, but as soon as there is more than one, whenever i hover over one, they all appear at the same time.
Have i got something fundamentally wrong?
Comments appreciated.
Thx
Use this as the selector inside instead of the .helper selector again:
$('.helper').mouseenter(function() {
// "this" now refers to the image that is being hovered...
$(this).stop(false, true).fadeIn();
});
If you're wondering what the problem was, it was that when you called
$(".helper")
within your function, you were getting all the elements with class helper, in stead of just the single element you wanted.

Categories