I'm creating a hyperlink element dynamically and set its attribute class so when it is clicked it will trigger a function.
Here is the code for dynamically creating the hyperlink element:
editLink = document.createElement("a");
editLink.setAttribute("class", "edit-button");
This is what should happen when the link was clicked:
$(document).ready(function(){
$('.edit-button').click(function(event){
event.preventDefault();
var docHeight = $(document).height();
var scrollTop = $(window).scrollTop();
$('.overlay').show().css({'top': scrollTop + 'px'});
});
});
But nothing happens when it is clicked. Thank you in advance :)
Not sure if you are appending the created element with body. I make this changes and it is working fine
var editLink = document.createElement("a");
editLink.setAttribute("class", "edit-button");
editLink.innerHTML = "Click"; // added text for testing
window.document.body.appendChild(editLink); // Appending to body
$(document).ready(function(){
$('.edit-button').click(function(event){
event.preventDefault();
alert('1')
var docHeight = $(document).height();
var scrollTop = $(window).scrollTop();
$('.overlay').show().css({'top': scrollTop + 'px'});
});
});
jsfiddle
try this
var editLink = document.createElement("a");
editLink.setAttribute("class", "edit-button");
editLink.innerHTML = 'click';
document.body.appendChild(editLink);
$(function() {
$('.edit-button').on('click',function(event){
alert('clicked');
event.preventDefault();
var docHeight = $(document).height();
var scrollTop = $(window).scrollTop();
$('.overlay').show().css({'top': scrollTop + 'px'});
});
});
https://jsfiddle.net/s718ay3g/1/
Event Delegation is the way to do it.
When you add event to .edit-button directly, at the time of loading the document, browser attaches that event listener to only the currently existing .edit-button elements. It doesn't get executed automatically for the newly created elements with the same class.
What you could do is put your event biding and listener code in a function and call it each time you add a new element to the DOM. But that's considered a bad practice.
Welcome, Event Delegation.
The idea is to attach the event to a parent/ancestor element which is not dynamic and trigger the event only when the event target is your specified element( matched with some sort of selector like class or ID).
In your case, the updated event binding code would look like this.
$(document.body).on("click", ".edit-button", function(){
//whatever you want to do in here.
});
and then, you can continue to add classes to newly created elements like you did...
var editLink = document.createElement("a");
editLink.setAttribute("class", "edit-button");
The event would still work.
This way you only attach the event once.
If your buttons/links are going to be contained in a container div or something similar, attach the event to that container instead of body.
$(".class-of-the-container").on("click", ".edit-button", function(){
//whatever you want to do in here.
});
Related
I have a function that is called every time a user goes through a new step to bind the click event to each new item that is added to the page, and it was working fine but now it's stopped and I cannot figure out why
Below is the function (or click here for full js):
function bindClickEvents() {
console.log('bindClickEvents');
$(".wall-dropdown .item").unbind('click').on('click', function() {
console.log('Item clicked');
if ($(this).hasClass('range')) {
$(".item.range").removeClass('active');
selectedRange = $(this).data('id');
$(this).addClass('active');
selectedStyle = null;
selectedColour = null;
}
if ($(this).hasClass('style')) {
$(".item.style").removeClass('active');
selectedStyle = $(this).data('id');
$(this).addClass('active');
selectedColour = null;
}
if ($(this).hasClass('colour')) {
$(".item.colour").removeClass('active');
selectedColour = $(this).data('id');
$(this).addClass('active');
}
runFilter();
});
}
Use off with on (not unbind)
$(".wall-dropdown .item").off('click').on('click', function() {
However I suggest you simply switch to delegated event handlers (attached to a non changing ancestor element):
e.g
$(document).on("click", ".wall-dropdown .item", function()
It works by listening for the specified event to bubble-up to the connected element, then it applies the jQuery selector. Then it applies the function to the matching items that caused the event.
This way the match of .wall-dropdown .item is only done at event time so the items can exists later than event registration time.
document is the best default of no other element is closer/convenient. Do not use body for delegated events as it has a bug (to do with styling) that can stop mouse events firing. Basically, if styling causes a computed body height of 0, it stops receiving bubbled mouse events. Also as document always exists, you do not need to wrap document-based delegated handlers inside a DOM ready :)
Why don't you bind event to body like
$('body').on('click','.wall-dropdown .item',function(){...some code...})
to prevent reinitialization of event?
this code automaticaly works with each new element .wall-dropdown .item
I have code that does this:
$('.attachment-medium').each(function(){
$(this).click(function(){
var gallWidth = $('.gallery').width();
$('.gall-output').toggle().css('width', gallWidth);
var url = $(this).attr('src').slice(0,-12) + '.jpg';
$('.gall-output-img').html('<img class="img-responsive" src="' + url + ' "/>');
var imgMeta = $(this).parent().next().html();
$('#gall-output-meta').html(imgMeta);
});
});
This generates a modal overlay and displays an img withing a div with class .gall-output. I've created a small <p class="gall-close">close</p> to hide() the .gall-output but it doesn't seem to be working with this code:
$('.gall-close').click(function() {
$('.gall-output').hide();
});
Is there a way of using this .gall-close to hide or toggle .gall-output?
Thanks for your help.
In case the .gall-close is added later and not in the dom when the page is loaded, you can attach the click-event using event-delegation:
$(document).on("click", ".gall-close", function(){
$('.gall-output').hide();
});
Instead of $(document) any static parent element can work as container element to delegate the event. In case this solves your issue, you can check https://api.jquery.com/on/#on-events-selector-data-handler, section "Direct and delegated events":
"Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on()."
I am slowly making my way from jQuery to vanilla JS, but I am struggling with wanting to write the following in JavaScript, would I have to setup a 'for' loop for each element? How would I target the child elements an an ID?
Here's what I would want to understand:
$('#id li').click(function(){
$(this).addClass('active');
});
I understand document getElementById to grab the '#id' but how would I achieve getting the child <li> elements? And how would I get the 'onclick' function to work for ANY list element clicked? Would I have to setup a 'for' loop for each element? Any help much appreciated!
Here is a JSFiddle that does what you want:
http://jsfiddle.net/digitalzebra/ZMXGC/10/
(function() {
var wrapper = document.getElementById("id");
var clickFunc = function(event) {
var target = event.originalTarget || event.target;
target.className = "active";
};
wrapper.addEventListener("click",clickFunc);
})();
A little bit of an explanation is in order...
First, I'm using a self executing function to fetch the wrapper div, using getElementById(). This is equivalent to using an id selector in jQuery: $('#id')
Next, I'm attaching a click handler to the element using the function addEventListener() and passing in an event type of click.
This binds the click handler function to the div element, the same as jQuery's click() would do. I'm using something called event bubbling, where a click event on any of the children of the wrapper will call the click handler attached to the wrapper.
Once the user clicks on the element, our function is called. originalTarget or target is the element that the user actually clicked in to, which in this case will always be an li. I'm then setting the class on that element to active.
Here is example for above question
http://jsfiddle.net/G3ADG/2/
(function() {
var id = document.getElementById("id");
var liele = id.getElementsByTagName("li");
for (var i = 0; i < liele.length; i++) {
liele[i].addEventListener("click", function () {
this.className = "active";
})
}
})();
Well I really liked Polaris878 solution as he is not using any loop inside it. In my solution first get HTML node information using document.getElementById this works similarly to $("#id"). than in next step I am fetching all tag type of "li" which are children of "id", than on this li tag array adding event listener to listen click functionality
className is one of attribute that allow to add class on that Node
I have tested above code in mozilla and chrome
This will work (IE >= 10), not want to search classList.add() replacement for IE<10,
var elems = document.querySelectorAll('#id li');
for (var i = 0; i < elems.length; i++) {
var elem=elems[i];
elem.addEventListener("click", function (e) {
this.classList.add('active');
});
}
fiddle
Am slowing get a hang of backbone.js, but i've run into a bit of bind.
I've successfully created a view, and am able to delegate events to element in the DOM, however i can seem to be able to use the jQuery "$(this)" in the following context
Chrono.Views.Sidebar = Backbone.View.extend({
//Page wrapper
el:"#wrapper",
//Delegate events to elements
events : {
"click .push-to":"loadPage"
},
loadPage: function(event) {
var url = $(this).attr("href");
alert(url);
event.preventDefault();
}
});
The click event is intercept but this line "var url = $(this).attr("href");"
In the context of loadPage, this has been bound to your Chrono.Views.Sidebar instance. However, you can get the DOM element that the event was triggered on through event.currentTarget. If you update your function to look like this it should work:
loadPage: function(event) {
var url = $(event.currentTarget).attr("href");
alert(url);
event.preventDefault();
}
In backbone this is bound to the view, but you can still get the element that was clicked by checking the event.target or the element that the event was bound to using event.currentTarget.
Take a look at this question
Backbone.js Event Binding
this is bound to the view, so you can access the View.$el property directly.
loadPage: function(event) {
var url = this.$el.find('.push-to').attr('href');
alert(url);
event.preventDefault();
}
forgive the code being bulkier than necessary, will tidy it up in due course.
everything seems to be working and yet, when you click a link after it's content has already been 'active' nothing happens.
i'm sure it's something simple but i can't see it.
EDIT: the following code now works in FF and Chrome, but does not work in IE8. Any ideas?
$(function(){
//initialize active link to not have a link on ready.
var linkId = $('#pricing_body div.active').attr('id');
var activeLink = $('#pricing_nav ul li#'+linkId+' a'); //just the link itself.
activeLink.parent().addClass('activeSection');
//var activeLinkContents = activeLink.parent().html(); //the link contained in the the list item and it's contents.
//alert(activeLinkContents);
var linkContents = activeLink.html(); //text content of the link.
activeLink.parent().html(linkContents);
//when link is clicked, store it's text for assignment after <a> is stripped out.
$('#pricing_nav ul li a').live('click',function(){
var clickedId = $(this).parent().attr('id');
var clickedLinkContents = $(this).html();
$(this).parent().addClass('activeSection');
$(this).parent().html(clickedLinkContents); //replaces <a><span>name</span></a> with just the span and text.
//fadeOut active div and give it inactive class. get list item with same id as div we are fading out.
$('#pricing_body div.active').fadeOut('500',function(){
$(this).removeClass('active').addClass('inactive');
var divId = $(this).attr('id');
var sisterLink = $('#pricing_nav ul li#'+divId);
sisterLink.removeClass('activeSection');
sisterLink.html(''+sisterLink.html()+''); //put link in between <li>.
//fadeIn the div with id of the link that has been clicked.
$('#pricing_body div#'+clickedId).fadeIn('500',function(){
$(this).addClass('active').removeClass('inactive');
var newActive = $('#pricing_nav ul li#'+clickedId);
});
});
});
});
Use live method to attach events to the elements. Here is the documentation.
Try:
$('#pricing_nav ul li a').live('click', function(){
---------
---------
---------
});
EDIT:
In reply of comment.
.live()
The .live() method is able to affect
elements that have not yet been added
to the DOM through the use of event
delegation: a handler bound to an
ancestor element is responsible for
events that are triggered on its
descendants.
.bind()
The .bind() method is the primary
means of attaching behavior to a
document. All JavaScript event types,
such as focus, mouseover, and resize,
are allowed for eventType.
Here is SO Question on this difference.