I'm writing some TS code to generate a button dinamically, the button appear on page, but all events on it not works.
I already read answers about delegation and I using it, but the problem is not solved.
The most strange thing is that if I call $("#myID").click() or .mouseover() or .mousedown() in console, all events works correctly.
EDIT AND CLOSE:
Sorry for waste of time, I just put to my background the z-index css attribute to -100, and I don't know why, but the button was impossible to be clicked cause, even if it was visible, it was behind the background div.
Hierarchical selectors can often be avoided simply by attaching the handler to a more appropriate point in the document. For example, instead of $( "body" ).on( "click", "#commentForm .addNew", addComment ) use $( "#commentForm" ).on( "click", ".addNew", addComment ).
https://api.jquery.com/on/
I suspect your delegation is too complex. Consider the following example.
$(function() {
$("#add").click(function(e) {
var item = $("<div>", {
id: "image-button-1",
class: "button"
}).appendTo("#container");
$("<img>", {
src: "https://i.imgur.com/9yMnjGx.png"
}).appendTo(item);
});
$("#container").on("click", "#image-button-1", function(e) {
console.log("Click");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">Add</button>
<div id="container"></div>
Edit: Please don't refer to this, it is incorrect
Can you try this. Enclosing your logic in a function and passing it to jQuery ensures that it is called after the page is loaded completely.
When you are trying to bind event handlers to an element, you have to ensure that the element is actually present in the DOM.
this.htmlElement = "<div id='" + this.ID + "' class='" + this.cssClasses + "'>" + this.buttonImage + "</div>";
$("#" + this.idContainer).append(this.htmlElement);
$(function() {
if (this.enabled) {
$(document).on('mousedown', "#" + this.ID, function (event) {
console.log("down");
});
$(document).on("mouseup", "#" + this.ID, function () {
console.log("up");
});
$(document).on("click", "#" + this.ID, this.action);
}
});
Related
I am using this code for the click handling on a button inside my page:
$(document).on("click", $('#' + GlobalVariables.currentUserType).find(".addDocumentToSection"), function (e) {
addItemToDocumentGrid();
$('#removeDocumentFromSection').disable(true).addClass("disabled");
$('#removeSelection').disable(true).addClass("disabled");
});
But the event fires as soon as I click anywhere in the page. Even if it is not the supposed button which I want to select with $('#' + GlobalVariables.currentUserType).find(".addDocumentToSection").
$('#' + GlobalVariables.currentUserType).find(".addDocumentToSection") returns one element which is actually the button which I want to be selected.
Why does it behave like that?
If you want to use event delegation, the second argument should be a selector, not a jQuery object.
$(document).on("click", '#' + GlobalVariables.currentUserType + " .addDocumentToSection", function (e) {
// ---------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
addItemToDocumentGrid();
$('#removeDocumentFromSection').disable(true).addClass("disabled");
$('#removeSelection').disable(true).addClass("disabled");
});
If you don't want to use event delegation, you need to call on on the element you want to hook the event on:
$('#' + GlobalVariables.currentUserType).find(".addDocumentToSection").on("click", function (e) {
addItemToDocumentGrid();
$('#removeDocumentFromSection').disable(true).addClass("disabled");
$('#removeSelection').disable(true).addClass("disabled");
});
This is all covered in the on documentation.
You are attaching onClick event to a document element. Try:
var button = $('#' + GlobalVariables.currentUserType).find(".addDocumentToSection");
button.on("click", function() {
addItemToDocumentGrid();
$('#removeDocumentFromSection').disable(true).addClass("disabled");
$('#removeSelection').disable(true).addClass("disabled");
});
$('#' + GlobalVariables.currentUserType).find(".addDocumentToSection").on("click", function(e){
});
jQuery can use selectors before the .on("click", this should work for you.
The solution may be obvious, but when clicking the .remove element, I am trying to remove the entire .tag element that is the parent. Currently, clicking the .remove element has no response.
HTML
'<div class="tag"><input id="' + id + '" type="hidden" name="' + name + '" value="' + value + '" />' + input + '<i class="remove dismiss fa fa-remove"></i></div>'
JS
$('.remove').on('click', '.remove', function() {
$(this).parent().remove();
});
Try this : As you are adding remove link dynamically, you need to register click handler using .on(). But in your case you have error in using .on(). Please use below code.
$(document).on('click', '.remove', function() {
$(this).parent().remove();
});
More Information on jQuery .on()
You can try this:
http://jsfiddle.net/myyzrwwe/
$('.remove').on('click', function() {
$(this).parent().remove();
});
You shouldn't always use delegate the event to the same element that has been delegated. You need to select a static parent. In my example, the document object is the parent of everything.
$('body').on('click', '.remove', function() {
$(this).parent().remove();
});
The problem might be you are binding the event to .remove, if this content is dynamic you might have a problem. Its better, in those cases, to bind to document.
$(document).on()
The callback has the event parameter, use that to remove.
function(e) {
$(e.currentTarget).parent().remove();
}
Check if you undelegate elements.
$(function() {
$.getJSON("companies.json", function(response) {
var html = '<table id="tbl">';
response.businesses.forEach(function(row) {
html += '<tr><td>' + row.id + '</td><td>' + row.name;
});
html += '</table>';
$("#tabledata").html(html);
});
$(".move").click(function() {
var $id = $(this).attr("idname");
$.getJSON("companies.json", function(response) {
$.map(response.businesses, function(obj) {
if (obj.id == $id)
console.log(obj);
return obj; // or return obj.name, whatever.
});
});
});
});
HTML:
<div id="tabledata" class='left'></div>
<div class="right"></div>
Please help?
As your .move element is added to your page dynamically, you have to make use of jQuery's on() method to delegate the event to an ancestor of the .move element which does exist when your JavaScript first loads.
$(document).on('click', '.move', function() { ... });
Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.
You can read more about jQuery's event delegation here.
If you use event delegation, your problem goes away (and your app becomes more performant and less prone to memory leaks).
// Only do this once, when your page loads...
$(document.body).on('click', '.move', function (ev) {
// This is the link that was clicked.
var $targ = $(ev.target);
});
Try This
$('#tabledata').on('click', '.move', function(e) { ... });
The reason the event isn't being triggered is because the event is only added to elements that exist on the page when you call the .click() method.
Instead, you can use event delegation:
$(document.body).on('click', '.move', function (ev) {
var $targ = $(ev.target);
});
which really says: call the function when any element that matches .move that's inside document.body is clicked.
I know others have said this already but I wanted to make event delegation clearer.
I've made a site that displays a user's Facebook photos. The code below appends the photos to the div "facebook-images". This part works fine. The problem I have is that the images are being appended after the Javascript code below is loaded; so the handler "fb-image" is not created when the browser reads the click function code at the bottom, therefore it does not work.
I believe I need to use jQuery on(), but where? I've tried to put on() everywhere in the code below. I've tried to bind with append, I've tried live (which I know is deprecated but worth a shot). Nothing is working.
Any ideas?
<div class="target">
</div>
<div id="facebook-images">
</div>
<script>
$.when(window.deferredes.fbLoaded, window.deferredes.fbLoggedIn).then(function () {
$.getJSON('https://graph.facebook.com/me/photos?access_token=' + FB.getAccessToken(), function (data) {
$.each(data.data, function (i, face) {
$('#facebook-images').append("<div class='fb-image'><img src='" + face.source + "' ></div>");
});
});
});
$(".fb-image img").click(function () {
$(".target").append("<h1>hi</h1>");
});
</script>
The simplest way to fix this is to add the click handlers AFTER the images are inserted into the page.
<script>
$.when(window.deferredes.fbLoaded, window.deferredes.fbLoggedIn).then(function () {
$.getJSON('https://graph.facebook.com/me/photos?access_token=' + FB.getAccessToken(), function (data) {
$.each(data.data, function (i, face) {
$('#facebook-images').append("<div class='fb-image'><img src='" + face.source + "' ></div>");
});
$(".fb-image img").click(function () {
$(".target").append("<h1>hi</h1>");
});
});
});
</script>
You can also use delegated event handling if you want. To do that, you set the event handler on a common parent that does exist at the time you run the event handling code with .on() and you use the delegated form of .on() by passing it a selector like this:
<script>
$.when(window.deferredes.fbLoaded, window.deferredes.fbLoggedIn).then(function () {
$.getJSON('https://graph.facebook.com/me/photos?access_token=' + FB.getAccessToken(), function (data) {
$.each(data.data, function (i, face) {
$('#facebook-images').append("<div class='fb-image'><img src='" + face.source + "' ></div>");
});
});
});
$("#facebook-images").on('click', ".fb-image img", function () {
$(".target").append("<h1>hi</h1>");
});
</script>
The delegated form of .on() works like this:
$(selector of static parent).on(event, selector that matches dynamic object, fn);
I've made a constructor in my script that formats <div>s so they can be created and destroyed on the fly.
Here's the function:
function formatDiv(target,divId,divClass,content,onclick)
{
$("#"+target).append("<div id=\'" + divId + "\' class=\'" + divClass + "\' onclick=\'" + onclick + "\'>" + content +"</div>");
}
What I've been trying to do with this is pass in a function call as a string from an array, like "Main()" for main menu, and assigning it to the <div>'s onclick="" property. This worked fine prior to upgrading my code with jquery, but now when I click on <div>, the console returns: ReferenceError: Main is not defined.
Assuming that this was caused by the inclusion of jquery (as it still works in my old backup), I decided to update the constructor to us jquery's .click event handler,
resulting in this:
function formatDiv(target,divId,divClass,content,onclick)
{
$("#"+target).append("<div id=\'" + divId + "\' class=\'" + divClass + "\'>" + content +"</div>");
$("#"+divId).click(function(){$(onclick)});
}
, and I changed the formatting of the functions to be called in the array piping info to the onclick parameter from "Main()" to Main.
Now when clicking on a <div>, nothing happens at all, no errors or anything.
What is the best way to add an onclick handler to my <div>s? Am I using .click incorrectly? Jquery is still new to me (despite w3schools lessons and the tutorials on jquery's site), so I'm forced to guess that I'm using it incorrectly. Any help would be appreciated.
Here's the whole script:
$(document).ready(function () {
$(Main);
//main menu
function Main()
{
var mainList = [">New List",">Show Lists",">Delete Lists"];
var onClick = [NewList,Main,Main];
var mainMenu = new Menu("Main Menu","menuMain",mainList,onClick);
mainMenu.contentMenu();
}
//new list menu
function NewList()
{
var mainList = ["> Create a New List"];
var onClick = [Main];
var newListMenu = new Menu("New List","menuMain",mainList,onClick);
newListMenu.contentMenu();
}
//menu class
function Menu(name,divClass,content,onclick)
{
$("#interface").html(null);
//title
formatDiv("interface",name,divClass,name,null);
//return
if(name != "Main Menu")
{
formatDiv(name,null,"return","^ Main Menu","Main()");
}
//display options
this.contentMenu = function()
{
for(i=0; i<content.length; i++)
{
formatDiv("interface",content+i,"menuContent",content[i],onclick[i]);
}
}
}
//format divs
function formatDiv(target,divId,divClass,content,onclick)
{
$("#"+target).append("<div id=\'" + divId + "\' class=\'" + divClass + "\'>" + content +"</div>");
$("#"+divId).click(function(){$(onclick)});
}
});
Since your divs are created dynamically, you can't use .click() to bind as that only binds to elements that already exit when the script runs. You can however use .on() and bind to an existing element on the page. A worst case would be something like the body element but you can probably find an element closer to where the divs reside than that.
For example:
$("#"+target).append("<div id=\'" + divId + "\' class=\'" + divClass + "\'>" + content +"</div>");
$('body').on('click', "#"+divId, function(){$(onclick)});
From the .on() documentation:
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().
To ensure the elements are present and can be selected, perform event
binding inside a document ready handler for elements that are in the
HTML markup on the page. If new HTML is being injected into the page,
select the elements and attach event handlers after the new HTML is
placed into the page. Or, use delegated events to attach an event
handler, as described next.
It sounds like you are looking for live() type functionality.
You don't actually want to use .live() though. Here is a good answer to why you want to actually use .on().
If you want to call a function just use functionName() instead of $(functionName) so change your code like this
$(document).ready(function () {
Main();
....
//display options
this.contentMenu = function () {
for (i = 0; i < content.length; i++) {
formatDiv("interface", "content" + i, "menuContent", content[i], onclick[i]);
}
}
....
//format divs
function formatDiv(target, divId, divClass, content, onclick) {
$("#" + target).append("<div id=\'" + divId + "\' class=\'" + divClass + "\'>" + content + "</div>");
$("#" + divId).click(onclick);
}
lets start by how you are making a div with jquery. The way you are making a div is correct but not the most efficent.
You can make any html element with jQuery with the following syntax
$('<NODE_NAME>')
so for a div it will be
$('<div>')
Now that we have a jquery object we need to add attributes to it, we do that with the attr method. we
pass it an object of attribute name/value pairs.
$('<div>').attr({
className: divClass ,
id: divId
});
Now, to add the content in the div we use the .html method
$('<div>')
.attr({
className: divClass ,
id: divId
})
.html(
content
);
and finally we add the onclick handler
$('<div>')
.attr({
className: divClass ,
id: divId
})
.html(
content
)
.click(
onclick
);
What you are doing wrong with the onclick handler is wrapping it in $(). This does not make sense, you want to call the main function, not pass it as a value
to the jquery function.