Jquery .on click event - removing the bound element - javascript

I have the following code:
$("#content h1").on("click", function(){
var f = $(this);
var clicked_id = f.data("id");
var children = _.filter(data, function(key){
var id = key.id.split("-")
id.pop()
id = id.join("-")
return clicked_id == id;
});
if (children.length != 0) {
$("#content").html("");
_.each(children, function(obj){
$("#content").append("<h1 data-id='"+ obj.id +"'>"+ obj.txt +"</h1>")
});
}
});
So basicly Im binding a .on "click" event to h1. On the click I clean the element containing the H1 then I add a new H1 element. Now the click does not register anymore. How should I actually be doing this so I can keep clicking?

Use on like so (event delegation):
$("#content").on("click", "h1", function() {
Now, each time you click #content, it'll check for an h1 and run the event. Your previous code only bound the handler to the h1 at runtime.

Maybe you could bind this way?
$(document).on("click", "#content h1", function(){
...
});

Related

Is there any way to make the onClick global or DRY?

$("input").on("keypress",function(e){
if(e.which===13){
$("ul").last().append("<li>"+$(this).val()+"</li>");
}
$("li").on("click",function(){
$(this).toggleClass("striked");
});
$("li").on("mouseenter",function(){
$(this).css("color","green");
});
});
$("li").on("click",function(){
$(this).toggleClass("striked");
});
$("li").on("mouseenter",function(){
$(this).css("color","green");
});
$("#slide").on("click",function(){
$("input").slideToggle();
});
Here, I have used the onClick event on<li> to apply the striked class two times just to make it work for both dynamic and non-dynamic elements on the page. But the code is replicated and seems long. Is there any way to shorten so that I can write it once and it gets activated for both types of elements?
Use event delegation instead, on the ul, so you only have to set up listeners once, rather than setting up multiple listeners for every element on load and on each .append. Also, save the ul and the input jQuery-wrapped elements in a variable once rather than selecting them and wrapping them with jQuery each time they're used:
const $ul = $("ul");
const $input = $("input");
$input.on("keypress", function(e) {
if (e.which === 13) {
$ul.last().append("<li>" + $(this).val() + "</li>");
}
});
$ul.on("click", 'li', function() {
$(this).toggleClass("striked");
});
$ul.on("mouseenter", 'li', function() {
$(this).css("color", "green");
});
$("#slide").on("click", function() {
$input.slideToggle();
});
A rather generic approach would be to capture the click event and check if it is from ul
document.body.onclick = function(e){
e = e || event;
var from = findParent('ul',e.target || e.srcElement);
if (from){
/* it's a link, actions here */
}
}
//find first parent with tagName [tagname]
function findParent(tagname,el){
while (el){
if ((el.nodeName || el.tagName).toLowerCase()===tagname.toLowerCase()){
return el;
}
el = el.parentNode;
}
return null;
}
now you can change the tagName passed to the findParent function and do accordingly
Read Here
You can try using the jquery all selector $('*'). For more information on this see
https://api.jquery.com/all-selector/.
Or you can add a specific class to every element you want to have an onClick action.

Javascript - Create Dynamic Element then Do Something on Element's Click

How can I call a click event listener on a dynamically created element rendered in the DOM?
I have some scripts that dynamically create elements in the DOM, one of them being a button/a. I would like that button/a to do something once the user clicks it. Right now nothing happens but if I add a setTimeout on the things to happen upon a click, then it kind of works - only let's me do the something on the first element's click (button/a). However I can't rely on a setTimeout to make this chunk of code work.
Here is more or less what I have without the setTimeout method:
// This triggers the whole process
var mainBtn = document.querySelector('.mainBtn');
mainBtn.addEventListener('click', function(e){
e.preventDefault();
mainFunc();
});
// This creates and renders dynamic content in DOM
function mainFunc(){
var out = document.querySelector('.outputWrapper');
var mainArr = ['something ', 'another ', 'else ', 'last one.'];
var div = document.createElement("div");
var btn = document.createElement("a");
var btnText = document.createTextNode("Click Me");
btn.appendChild(btnText);
btn.className = "clickMeBtn";
for(a of probArr){
div.append(a);
div.append(btn);
}
out.append(div);
}
// This is what should happen on button/a click
var clickedBtn = document.querySelector('.clickMeBtn');
if( clickedBtn != null ){
clickedBtn.addEventListener('click', function(e){
e.preventDefault();
console.log('click');
});
}
Here's with the setTimeout method:
// This triggers the whole process
var mainBtn = document.querySelector('.mainBtn');
mainBtn.addEventListener('click', function(e){
e.preventDefault();
mainFunc();
});
// This creates and renders dynamic content in DOM
function mainFunc(){
var out = document.querySelector('.outputWrapper');
var mainArr = ['something ', 'another ', 'else ', 'last one.'];
var div = document.createElement("div");
var btn = document.createElement("a");
var btnText = document.createTextNode("Click Me");
btn.appendChild(btnText);
btn.className = "clickMeBtn";
for(a of probArr){
div.append(a);
div.append(btn);
}
out.append(div);
}
// This is what should happen on button/a click
setTimeout(function(){
var clickedBtn = document.querySelector('.clickMeBtn');
if( clickedBtn != null ){
clickedBtn.addEventListener('click', function(e){
e.preventDefault();
console.log('click');
});
}
}, 10000);
Again this kind of works...it let's me click only on the first instance of the clickedBtn variable.
Any suggestions on how to make this idea work?
Thanks a lot!!
document.querySelector('.clickMeBtn'); returns the first found element, or null.
Attach click event handler when you create the anchor element:
var btn = document.createElement("a");
btn.addEventListener('click', function(e){
e.preventDefault();
console.log('click');
});
I am not 100% sure of what is your question. But the problem I can see is that you cannot bind listeners to elements that are not yet created in the DOM.
So I can see 3 options here:
1- You build a wrapper on top of document.createElement() and a wrapper on top of addEventListener to bind the events to the elements after they are created. For example you build a map of event listeners to begin with, with the 'element selector' as Key and function to call as Value. Then you do a lookup of the listener once the element has been created and you bind it to it with addEventListener.
2- You use JQuery on() method like this:
// define the click handler for all buttons
$( document ).on( "click", "button", function() {
alert( "Button Clicked!" )
});
/* ... some time later ... */
// dynamically add another button to the page
$( "html" ).append( "<button>Click Alert!</button>" );
Source: this JQuery script is from [here][1]
(EDIT) 3- you just bind it after creation, as suggested. Although I thought you wanted to do more advanced stuff, like dynamically add elements asynchronously from the listeners.

Attaching Right Click Event on Dynamically Created Elements

Below is the code that dynamically creates an element and attach an onclick event.
var div = document.createElement('div');
div.onclick = function(e){
console.debug(e);
}
var parent = document.getElementsByClassName('myid_templates_editor_center_menu');
parent[0].appendChild(div);
How about attaching a right click event?
The answer to your question consists of two parts:
1) How to attach the right-click event?
Answer: use the contextmenu event.
2) How to attach an event to dynamically created elements?
Answer: the idea is to attach the event to the parent element that will contain your newly created element. The event will propagate along the DOM until it reaches your parent element.
Working Example:
//get parent elements
var elements = getElementsByClassName('myid_templates_editor_center_menu');
//attach to the first found parent element
elements[0].addEventlistener('contextmenu', function(e) {
console.log("right clicked!");
})
Add
div.oncontextmenu = function(e){
e.preventDefault();
console.debug(e);
}
instead onclick
You can use contextmenu event
window.onload = function() {
var div = document.createElement("div");
div.innerHTML = "right click";
div.oncontextmenu = function(e) {
console.debug(e.type, e);
}
document.body.appendChild(div);
}
Working Example
node.addEventListener('contextmenu', function(ev) {
ev.preventDefault();
alert('success! - Right Click');
return false;
}, false);
Codepen :
http://codepen.io/mastersmind/pen/WogoVB
var div = document.createElement('div');
div.oncontextmenu = function(e){
console.debug(e);
}
var parent = document.getElementsByClassName('myid_templates_editor_center_menu');
parent[0].appendChild(div);

Stop element from disappearing when clicked

I'm writing a simple jQuery plugin that will dynamically place a div under a text box whenever it has focus. I've been able to get the position just about right in all the browsers.
I have to attach two event handlers as well on the focus and blur events of the textbox. And it works okay, but the problem is that the div that has been placed under the textbox closes even when we click on it. Now it makes sense why it would so happen, it's because the textbox loses focus, but is there a way I can stop it from happening?
I tried attaching this to the blur event handler -
if($(mainElem).is(":focus")) return;
where mainElem is the div that is shown below the textbox.
Here is a jsFiddle to illustrate the problem.
You are not going to be able to use the blur event if you want to place "clickable" elements in the div that shows. One way to solve this is to bind your event listener to a more global element like the document and then filter out the targets.
Here is a code sample:
$(document).on('click', function (e) {
var targetEl = e.target,
parent = $(e.target).parents()[0];
if (relElem[0] === targetEl || self[0] === targetEl || self[0] === parent) {
$(mainElem).show();
} else {
$(mainElem).hide();
}
});
Here is an update to your fiddle: http://jsfiddle.net/9YHKW/6/
This is a fiddle that I threw together for a project a while back: http://jsfiddle.net/MYcZx/4/
While it is not based off of your fiddle (and I do apologize) I believe that the functionality is much the same as what you're looking for. My example does not include input fields, but rather spans that hold the values. And while I'm not managing focus/blur, you could add a tabIndex attribute to the spans and then add a trigger on focus that would open the menu.
var $sub = $('.subscription');
$sub
.on('click', '.remove', function() {
$(this).parent().remove();
})
.on('click', 'li', function(e) {
var $this = $(this),
$parent = $this.parent(),
$options = $parent.children('li'),
$value = $parent.siblings('.value'),
isMulti = $parent.hasClass('multi'),
values = [];
if(!isMulti) {
$options.removeClass('active');
}
$this.toggleClass('active');
$options.filter('.active').each(function() {
values.push($(this).text());
});
$value.text(values.join(', ') || 'select');
$value[(values.length ? 'add' : 'remove') + 'Class']('set');
});
var $clone = $sub.clone(true);
$('.new')
.on('click', function() {
$(this).before($clone.clone(true));
});

trying to append content to DOM element

I'm trying to add a div to a row of content with the click of a button. My code works for the first row but not for any other row. Please help. This is the function for the button:
$(".addMMbtn").each(function() {
$(this).bind("click",
function() {
var thisRow = $(this).closest(".txtContentRow");
var thisTxt = thisRow.find(".txtContent");
var cellStr = '<div class = "mmCell prep"></div>';
$(cellStr).appendTo(thisTxt);
}
);
});
You can see a fiddle of the problem here: http://jsfiddle.net/z7uuJ/
$(".addMMbtn") will only find the elements present on the page and your code will only attach click event handler on them. Since you are adding the elements dynamically you should either use delegate or on (if you are using jQuery 1.7+) for click event to work on them too. Try this
Using delegate
$('#default').delegate('.addMMbtn', 'click', function() {
$('<div class = "mmCell prep"></div>')
.appendTo($(this).closest(".txtContentRow").find(".txtContent"));
});
Using on
$('#default').on('click', '.addMMbtn', function() {
$('<div class = "mmCell prep"></div>')
.appendTo($(this).closest(".txtContentRow").find(".txtContent"));
});
Demo
Instead of assigning click event directly on the button you need to use on():
$(document).on("click", ".addMMbtn",
function() {
var thisRow = $(this).closest(".txtContentRow");
var thisTxt = thisRow.find(".txtContent");
var cellStr = '<div class = "mmCell prep"></div>';
$(cellStr).appendTo(thisTxt);
}
);
In this case event handler will be subscribed to all newly added elements.
Code: http://jsfiddle.net/z7uuJ/5/
You don't need to loop through the elements to bind the handler:
$(".addMMbtn").live('click', function() {
var thisRow = $(this).closest(".txtContentRow");
var thisTxt = thisRow.find(".txtContent");
var cellStr = '<div class = "mmCell prep"></div>';
$(cellStr).appendTo(thisTxt);
});

Categories