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.
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.
So I have multiple delete buttons on a table and each button has there own unique id. I am trying to get this value via javascript but I can't get it to work at all.
Here is a section js that is working properly and loads the correct html (this is ran for each movie):
function createRow(movie) {
movie.NewDate = new Date(movie.ReleaseDate);
return '<tr><td><img class="movieImage" src="' +
movie.ImageLink +
'" alt="' +
movie.Title +
' Image" style="width:50px;height:75px">' +
'<td>' +
movie.Title +
'</td><td>' +
movie.NewDate.toLocaleDateString("en-US") +
'</td><td><button type="button" class="removeButton" value="' + movie.DVDID + '">Delete</button></td></tr>';
}
And here is the js where I am trying to retrieve the id:
$(document)
.ready(function () {
var deleteButtons = $(".removeButton");
deleteButtons.each(function (index) {
var currentButton = $(this);
var buttonValue = currentButton.val();
currentButton.click(function () {
alert(buttonValue);
});
});
});
I found the last snippet via Click one of multiple buttons, put value in text input
Right now just getting a proper alert would be sufficient.
Have you tried this approach:
$("#tableId").on("click", ".removeButton", function(){ alert($(this).attr("value")); })
This "on" binds all the ".removeButton" elements with the given function when click is triggered.
Your javascript should look like this:
$(document).ready(function () {
var deleteButtons = $(".removeButton");
deleteButtons.on('click', function() {
alert($(this).attr('value'));
});
});
Also, since you adding these buttons dynamicly with javascript, you may need to rebind button click events after you add new row. Also binding should be done after loading button html to DOM.
Since you are creating buttons dynamically, you won't be able to reach them properly because when the javascript was initiated they didn't exist in the DOM. So in order for you to be able to find the buttons, you'll have to look at the document scope and then find which button (class) you click on, like so:
$(document).on('click', '.removeButton', function(){
console.log($(this).val())
})
See fiddle for complete example
I'll try to explain my problem:
I have a website where the user dynamically adds elements. They all belong to the "toBuy" class. Whenever a new element is added to this class I need to attach a click-handler to only this element but not to all others. To keep my code clean I want to have a function that does this work. Here is what i've tried:
this is how the stuff is added:
$("#addItemButton").click(function(){
var item= $('#item').val();
$('#item').val("");
var quantity= $('#quantity').val();
$('#quantity').val("");
var comment=$('#addComment').val();
$('#addComment').val("");
//construct new html
var newitem="<div class='toBuyItem'><div class='item'>";
newitem+=item;
newitem+="</div><div class='quantity'>";
newitem+=quantity;
newitem+="</div><div class='comment'><img src='img/comment";
if(comment==""){
newitem+="_none"
}
newitem+=".png' alt='Comment'></div><div class='itemComment'>"
newitem+=comment;
newitem+="</div></div>";
$("#toBuyItems" ).prepend( newitem );
toggle("#addItemClicked");
initializeEventListeners();
});
then this is the initializeEventListeners function (which I also run when the page loads so that the existing elements have the event handlers already:
function initializeEventListeners(){
$(".toBuyItem").click(function(){
console.log($(this).html());
console.log($(this).has('.itemComment').length);
if($(this).has('.itemComment').length != 0){
console.log("toggling");
$(this).addClass("toggling");
toggle(".toggling .itemComment");
$(this).removeClass("toggling");
}
});
}
function toggle(item){
$( item ).slideToggle(500);
}
now apparently what happens is that when a new element is added the existing elements get a new event handler for clicking (so they have it twice). Meaning that they toggle on and off with just one click. Probably it's damn simple but I cannot wrap my head around it....
EDIT:
so this works:
$(document).on('click', '.toBuyItem', function(){
if($(this).has('.itemComment').length != 0){
console.log("toggling");
$(this).addClass("toggling");
toggle(".toggling .itemComment");
$(this).removeClass("toggling");
}
});
Use jquery's on method. This way you have to add event only once. This will be added automatically to dynamically added elements.
$(document/parentSelector).on('click', '.toBuyItem', function() {
// Event handler code here
});
If you are using parentSelector in the above syntax, it has to be present at the time of adding event.
Docs: https://api.jquery.com/on
You can use jQuery.on method. It can attach handlers to all existing in the DOM and created in future tags of the selector. Syntax is as follows:
$(document).on('click', '.toBuyItem', function(){
//do onClick stuff
})
As others have suggested, you can delegate click handling to document or some suitable container element, and that's probably what I would do.
But you could alternatively define a named click handler, which would be available to be attached to elements already present on page load, and (scope permitting) to elements added later.
You might choose to write ...
function buy() {
if($(this).has('.itemComment').length != 0) {
$(this).addClass("toggling");
toggle(".toggling .itemComment");
$(this).removeClass("toggling");
}
}
function initializeEventListeners() {
$(".toBuyItem").on('click', buy);
}
$("#addItemButton").on('click', function() {
var item = $('#item').val(),
quantity = $('#quantity').val(),
comment = $('#addComment').val();
$('#item', '#quantity', '#addComment').val("");
//construct and append a new item
var $newitem = $('<div class="toBuyItem"><div class="item">' + item + '</div><div class="quantity">' + quantity + '</div><div class="comment"><img alt="Comment"></div><div class="itemComment">' + comment + '</div></div>').prependTo("#toBuyItems").on('click', buy);// <<<<< here, you benefit from having named the click handler
$newitem.find(".comment img").attr('src', comment ? 'img/comment.png' : 'img/comment_none.png');
toggle("#addItemClicked");
});
in my jsFiddle example can you see that I made a button where I add some elements and links to delete this elements. In this example it is not about going to delete the elements, but to hover the (remove)link made by clicking the button so it highlights the element with the same "number" attribute.
I have tried to use live(); and on(); for it, but it does not do anything, because the items are made after building the page.
I prefer to use on(); now because jQuery says:
As of jQuery 1.7, the .live() method is deprecated. Use .on() to
attach event handlers. Users of older versions of jQuery should use
.delegate() in preference to .live().
My jQuery code:
function numbers() {
return $('#links span').length;
}
$('#add').on('click', function () {
$('#links').append('<span number="' + (numbers() + 1) + '">Remove element ' + (numbers() + 1) + '</span><br />');
$('#elements').append('<div number="' + numbers() + '" class="element">Element ' + numbers() + '</div>');
});
$('#links span').live('hover', function () {
var number = $(this).attr('number');
if ($('#elements .element').attr('number') == number) {
$(this).addClass('highlight');
}
});
First of all, you should dynamically bind the events, since the elements are added dynamically. Second of all, you should make use of mouseenter and mouseleave events, since you want to toggle the highlighting and need to know when the cursor is leaving the element. And third of all I recommend using data--attributes instead of a custom attribute called number.
function numbers() {
return $("#links span").length;
}
$("#add").on("click", function () {
var number = numbers() + 1;
$("#links").append("<span data-number='" + number + "'>Remove element " + number + "</span><br />");
$("#elements").append("<div data-number='" + number + "' class='element'>Element " + number + "</div>");
});
// Dynamically bind mouseenter and mouseleave events, so they also apply to dynamically added elements
$("body").on("mouseenter", "#links span", function () {
var number = $(this).data("number");
$(".element[data-number='" + number + "']").addClass("highlight");
}).on("mouseleave", "#links span", function () {
var number = $(this).data("number");
$(".element[data-number='" + number + "']").removeClass("highlight");
});
FIDDLE
I'm just getting into Javascript and I've run into the same problem a number of times with different pieces of code: I have a function that creates a type of element and a function that does something with that type of element. It seems obvious to me that I need to call the "do something" function after the element has been created, but when I do, it ends up running more times than I'd like.
Here's an example of my problem:
function rightClick(){
$(".element").mousedown(function(e){
switch (e.which){case 3: alert( $(this).attr("id") )};
});
};
function doubleClick(){
var counter = 0;
$(document).dblclick(function(e){
counter++;
elementId = "element" + counter;
$("#new_elements").append("<div class='element'" +
"id='" + elementId + "'" +
"style='position:absolute;" +
"top:" + e.pageY + ";" +
"left:" + e.pageX + ";'>" +
elementId+ "</div>");
rightClick();
});
In this example, if I create 4 elements and I right-click on the first one I created, I end up getting 4 alert boxes instead of one. If I right-click on the second element I created, I get three alerts; the third: 2 alerts; the fourth: one alert.
Can anyone explain to me why this is happening, and how to fix it so that I only get one alert each time I right-click on an element?
Binding is the act of associating an event with a DOM element. The .mousedown and similar events only bind on elements that already exist.
Each time you call rightClick() you bind a new event to all current .element elements.
You can bind functions to the same element as much as you'd like, which is why you see the function being called many times.
For dynamic elements should checkout .on or .delegate which work like this:
Example of jQuery.fn.on
$(document.body).on("mousedown", ".element", function(e) {
if (e.which === 3) alert($(this).attr("id"));
});
Example of jQuery.fn.delegate
$(document.body).delegate(".element", "mousedown", function(e) {
if (e.which === 3) alert($(this).attr("id"));
});
Only call this once and you should be pretty much okay. If you're not using jQuery 1.7 or higher you will want to use .delegate() instead of .on.
You do not need to bind the event everytime you insert and element into the DOM. You can use .on to attach event handlers for elements that are dynamically inserted.
$(document).on('mousedown','.element', (function(e){
switch (e.which){
case 3: alert( $(this).attr("id") );
break;
};
});
var counter = 0;
$(document).dblclick(function(e){
counter++;
elementId = "element" + counter;
$("#new_elements").append("<div class='element'" +
"id='" + elementId + "'" +
"style='position:absolute;" +
"top:" + e.pageY + ";" +
"left:" + e.pageX + ";'>" +
elementId+ "</div>");
});
I believe you are adding the same handler several times, meaning that when you click a button you are re-binding the action to the same function.
You've bound your event handler to the class '.element'. This means that every element with the class '.element' on your page will fire that event when the right click occurs.