I cannot seem to get this to work. I am using jquery to create an html select, and I want some code to execute when its value changes.
code follows:
<script type ="text/javascript">
var firstweddingturn = '400';
$('#weddingturn').change(function() {
alert ("Wedding select change triggered!");
//var wedturn = $('#weddingturnselectid').val();
//$('#div3').append('<br>Wedding turn selected, ' + wedturn + '</br>')
});
$(document).ready(function() {
var html = [];
html[html.length] = '<select name="weddingturn" id="weddingturn">';
var a = firstweddingturn;
var b = Number(firstweddingturn) + 16;
while (a < b) {
// do some code
html[html.length] = '<option name="asdf" value = "1">' + a + '</option>';
a++;
} // end while
html[html.length] = '</select>';
$('#div1').append(html.join(''));
});
</script>
What am I doing wrong?
You need to use .delegate() (or .live()) since you are adding the select dynamically. When you attach an onChange handler with .change() it is only attached to existing matching elements, not elements which are added later on. To attach an event to all matching elements including those added to the page later, you use the .delegate() function, like this:
$('body').delegate('#weddingturn','change', function(){
alert('Wedding select changed to ' + $(this).find('option:selected').val() );
});
However, as some people point out, you can merely attach the event handler immediately after adding the <select> to the DOM. That way, you can still use .change() and your code should run faster.
Include this:
$('#weddingturn').live('change', function() {
alert ("Wedding select change triggered!");
//var wedturn = $('#weddingturnselectid').val();
//$('#div3').append('<br>Wedding turn selected, ' + wedturn + '</br>')
});
in your $(document).ready
And change it to use live
When the .change() event is bound, the element does not exist yet. You have 2 choices:
Bind the event after you create the element (the simplest and recommended option)
Use .delegate() (or .live()) to tell jQuery to bind the event to any element matching the selector whenever it is added to the DOM. If you choose this option, delegate() is the preferred method if you are using a recent version of jQuery > 1.4.2 since it is more performant than live().
You'll need to bind using live, since it is loaded post-DOM load:
$("#weddingturn").live("change", function() {
});
Also, I would place this within scope of $(document).ready, preferably after the code which loads it (just for the sake of logical linearity.)
You're hooking up the event handler BEFORE you've created the element.
(you can use .live() or you can just swap the order of operations)
your are dynamically adding the select to the DOM, at the time of declaration of your event handler the select doest not exists so the event handler doesn't get binded to the element use .live to attach the event handler to dynamically added element
$('#weddingturn').live('change',function() {
alert ("Wedding select change triggered!");
//var wedturn = $('#weddingturnselectid').val();
//$('#div3').append('<br>Wedding turn selected, ' + wedturn + '</br>')
});
DEMO
jquery live
You are setting the change function on a select that does not yet exist. Move that .change call to after the .append
Related
On page load, I have a search box that, once used, populates a div with multiple images. The javascript from the search uses this function to append all images into the div
function appendSomeItems(url, id, name, style) {
return '<div><div class="md-card md-card-hover"> <div id="getImage" class="gallery_grid_item md-card-content"> <img class ="uk-align-center imageClick"></a> <div class="gallery_grid_image_caption"> <span class="gallery_image_title uk-text-truncate">' + name + '</span> <span>' + style + '</span> </div></div></div></div>';
}
This works perfectly. Now I'm trying to make it so that when I click any one of the images it triggers an action (in this case a console log)
$('.imageClick').click(function handleImage() {
console.log(good);
});
However, it does nothing. No error but no console log.
What am I doing wrong here?
You need to use event-delegation in order to bind an event to dynamically created elements:
This approach uses document as the parent element, however, a good practice is to use the closest parent element.
$(document).on('click', '.imageClick', function handleImage() {
console.log(good);
});
Try with .on() to attach event on dynamically created element. This will allow attaching the event to the elements that are added to the body at a later time:
$('body').on('click', '.imageClick' function handleImage() {
console.log(good);
});
The problem is that you are calling $(".imageClick").click() before you dynamically create the items.
This means that jQuery doesn't actually bind the click listener to the items, since when $(".imageClick").click() is run, the elements don't actually exist yet.
Try this:
$("body").on("click", ".imageClick", function handleImage() {
console.log("good");
});
Also see this post for more information: In jQuery, how to attach events to dynamic html elements?
I have a section on an intranet page that allows for a summary view of Follow-up's a employee has made in relation to customer tickets. We have added a one-click event to delete a particular record by clicking on the standard close icon at the end of each row (has class .fudel) and (value="####"). The deletion is handled by PHP via a POST event. I use the same Jquery that initiates the deletion to reload the summary DIV after sending the POST so that the summary list is current.
The problem is the event will only trigger once, after the .load() has occurred Jquery can no longer detect click events within the dynamic div. If you look at the Jquery I used it uses the .on() method which as I understand it replaced .live() and is specifically intended to deal with event detection in dynamically loaded elements.
$('.fudel').on("click", function() {
var m = $(this).attr("value");
var answ = confirm("Press OK to DELETE follow-up record for: ("+ m +")");
if (answ == true) {
$.post("includes/phpfunctions.php", {
fudelete: m
});
$("#followup").load(location.href + " #followup > *");
}
else {
$.alert('Deletion Canceled', 'User Notice');
}
});
Also, in two recent question I found that a number of these event detection problems hovered around the need to add the second, third, fourth etc. etc. Jquery calls into the "Callback" of the on() event. If that ends up being an explanation for the problem here, I would ask someone to provide a good link to documentation that explains when Jquery actions need to fall within the callback scope vs when it can/should fall outside of the callback scope.
If the load() function is replacing the contents of the table (which includes the .fudel elements) you need to use a delegated event handler. Try this:
$('#followup').on('click', '.fudel', function() {
var m = $(this).attr("value");
var answ = confirm("Press OK to DELETE follow-up record for: ("+ m +")");
if (answ == true) {
$.post("includes/phpfunctions.php", {
fudelete: m
});
$("#followup").load(location.href + " #followup > *");
}
else {
$.alert('Deletion Canceled', 'User Notice');
}
});
Note that the click event is now bound to the #followup element and delegated to any child .fudel element.
Try delegation event, because if you make this:
$('.fudel').on("click", function() {
It attach the event to .fudel if this element exists, but if not exists in the DOM loading, you can make this:
$('body').on("click", ".fudel", function() {
By this mode you target an element that may exists in the future, but not neccesary on DOM ready.
I am working on HTML select Dropdown. I have two dropdowns one is for font size adjust and other is for text alignment.
When I select the fontsize from the dropdown it has to apply along with text-capitalize (bootstrap css) and If I select the font alignment all three should apply for the span element. For Example.
<div>
<span id="Title"class="text-capitalize">check</span>
</div>
Right now the code was like this
function changeFont_size () {
var select = document.getElementById('font_size');
// Bind onchange event
select.onchange = function() {
document.querySelector("#Title").className = this.value += " text-
capitalize";
};
}
function changeAlignment () {
var select = document.getElementById('text_align');
// Bind onchange event
select.onchange = function() {
document.querySelector("#Title").className = this.value;
};
}
Actually I am newbe on Javascript. Some how I am not getting.
The output result would be the combination of :
<span class="h1 left text-capitalize">Text</span>
Everything should be in pure javascript.
Thanks in advance. Kindly help me.
Here is the Link
This jsfiddle makes your code work. You need to run the code when the document is loaded, so that your onchange functions are being hooked in time.
It does not work exactly like you intended though. Your alignment classes need to be on the parent element and when you select your alignment, you disregard the previously set h1 or h2 class.
window.onload = function() {
var font_size = document.querySelector('#font_size');
// Bind onchange event
font_size.onchange = function() {
document.querySelector("#Title").className = this.options[this.selectedIndex].value += " text-capitalize";
};
var text_align = document.querySelector('#text_align');
// Bind onchange event
text_align.onchange = function() {
document.querySelector("#Title").className = this.options[this.selectedIndex].value;
};
};
You are mixing things up. There are two ways to bind events (well, two ways which are still common even with recent browsers).
The first one is to put a function call in the onsomething property of an element in the html code. Whatever is put there will be executed when the event happens.
<button onclick="alert('hi');">Click me</button>
You should pass the event object to an event handler instead of writing inline code.
<button id="helloworld" onclick="helloworld_onclick(event)">Run</button>
...
function helloworld_onclick(e) {
alert("Hello world!");
}
If you want to be able to bind events dynamically, if you want to bind multiple events to an object and if you want to keep the JavaScript outside of your HTML, the modern way to to so is with addEventListener.
document.querySelector("#helloworld").addEventListener("click", function(e) {
alert("Hello world!");
});
The event object passed (called e in my functions) contains information about what triggered the event and can be used to prevent default behavior and to control event propagation. You can't use "this" in event handlers, but the element which called the handler will be stored in e.target.
In your code, you created functions which, when called, bind events to the elements. Then you bound those functions to the elements with the html attributes.
Finally, you seem to be stuck between querySelector and getElementById. Note that querySelector(All) returns a static node/nodelist while getElement(s)By(...) returns a live node/nodelist. A static node is a copy of all the information about the element. A live node is a reference to the real element. If you modify the element, it modifies the live node, but the static node will keep the old information. You should use getElementById over querySelector for that, and because it runs faster. For code simplicity however, you might prefer always using querySelector. Just don't mix using querySelector("#something") on a line and getElementById("something") on another one, it's the best way to get confused and end up wasting time on a bug because you wrote querySelector("something") or getElementById("#something") instead.
function changeFont_size (element) {
if(element.options[element.selectedIndex].value != 'select'){
document.getElementById('Title').className = element.options[element.selectedIndex].value;
} else{
document.getElementById('Title').className = '' }
}
function changeAlignment (element) {
if(element.options[element.selectedIndex].value != 'select'){
document.getElementById('container').className = element.options[element.selectedIndex].value;
} else{
document.getElementById('container').className = '' }
}
Try this, Hope it will work
I have a list of items that are filled dynamically:
function ViewData(data) {
var SI = (typeof data) == 'string' ? eval('(' + data + ')') : data;
$('#ListContainer').empty();
for (var i = 0; i < SI.length; i++) {
var text = '<a href="Page.htm" rel="external" onclick= "SaveData();"
class="lesson" LessonID="' + SI[i].lessonID
'"><span class="lesson_subject">' + SI[i].sbj_Name +
'</span></b></a>
$('#ListContainer').append(text).trigger("create");
}
}
When one item of them is clicked, the page should navigate to another page carrying the data of this link.
I made this function to save the values of found in the link:
function SaveData() {
localStorage["LessonID"] = $('#ListContainer').find('.lesson').attr('LessonID');
localStorage["SubjectName"] = $('#ListContainer').find('.lesson_subject').text();
}
but it saves "All of the data". I want to save the data of the selected item only.
Do you have any ideas ?
Thanks.
It saves all of the data because your find('.lesson') will find every link inside #ListContainer. I would suggest removing your inline event handlers and taking advantage of event delegation with the on method:
$("#ListContainer").on("click", ".lesson", function() {
localStorage["LessonID"] = $(this).data("lessonid");
localStorage["SubjectName"] = $(this).data("subject");
});
Notice that I've used the data method instead of attr. That will require another change to your markup:
<a href="Page.htm" rel="external" class="lesson" data-lessonid="someID" data-subject="someSubject">
This uses HTML5 data-* attributes, which are the recommended approach when it comes to storing arbitrary data on an element.
Why use event delegation? It is more efficient, as it results in less event handlers bound to elements. Instead of one on every a.lesson element, there is just one on the #ListContainer element.
Because most DOM events bubble up the tree, a click on a descendant of #ListContainer will bubble up through the DOM tree, eventually reaching #ListContainer. The jQuery on method will pick up the event at this element, and check to see if it originated at an element matching .lesson. If so, it will execute the event handler.
Change this
onclick= "SaveData();"
to
onclick= "SaveData(this);"
Then change the saveData function to
function SaveData(elem) {
localStorage["LessonID"] = $(elem).attr('LessonID');
localStorage["SubjectName"] = $(elem).find('.lesson_subject').text();
}
Or even better, you can use $.on like #James Allardice showed in his answer.
You're mixing old world JavaScript and jQuery.
Use $("<a ...") to create your element, append it and then attach a .click handler which can use $(this) when it is fired. Use .data to add data to the elements when you add them which the .click handler can utilise.
The function associated with the selector stops working when I replace it's contents using .html(). Since I cannot post my original code I've created an example to show what I mean...
Jquery
$(document).ready(function () {
$("#pg_display span").click(function () {
var pageno = $(this).attr("id");
alert(pageno);
var data = "<span id='page1'>1</span><span id='page2'> 2</span><span id='page3'> 3</span>";
$("#pg_display").html(data);
});
});
HTML
<div id="pg_display">
<span id="page1">1</span>
<span id="page2">2</span>
<span id="page3">3</span>
</div>
Is there any way to fix this??...Thanks
Not sure I understand you completely, but if you're asking why .click() functions aren't working on spans that are added later, you'll need to use .live(),
$("#someSelector span").live("click", function(){
# do stuff to spans currently existing
# and those that will exist in the future
});
This will add functionality to any element currently on the page, and any element that is later created. It keeps you have having to re-attach handlers when new elements are created.
You have to re-bind the event after you replace the HTML, because the original DOM element will have disappeared. To allow this, you have to create a named function instead of an anonymous function:
function pgClick() {
var pageno = $(this).attr("id");
alert(pageno);
var data="<span id='page1'>1</span><span id='page2'> 2</span><span id='page3'> 3</span>";
$("#pg_display").html(data);
$("#pg_display span").click(pgClick);
}
$(document).ready(function(){
$("#pg_display span").click(pgClick);
});
That's to be expected, since the DOM elements that had your click handler attached have been replaced with new ones.
The easiest remedy is to use 1.3's new "live" events.
In your situation, you can use 'Event delegation' concept and get it to work.
Event delegation uses the fact that an event generated on a element will keep bubbling up to its parent unless there are no more parents. So instead of binding click event to span, you will find the click event on your #pg_display div.
$(document).ready(
function()
{
$("#pg_display").click(
function(ev)
{
//As we are binding click event to the DIV, we need to find out the
//'target' which was clicked.
var target = $(ev.target);
//If it's not span, don't do anything.
if(!target.is('span'))
return;
alert('page #' + ev.target.id);
var data="<span id='page1'>1</span><span id='page2'>2</span><span id='page3'>3</span>";
$("#pg_display").html(data);
}
);
}
);
Working demo: http://jsbin.com/imuye
Code: http://jsbin.com/imuye/edit
The above code has additional advantage that instead of binding 3 event handlers, it only binds one.
Use the $("#pg_display span").live('click', function....) method instead of .click. Live (available in JQuery 1.3.2) will bind to existing and FUTURE matches whereas the click (as well as .bind) function is only being bound to existing objects and not any new ones. You'll also need (maybe?) to separate the data from the function or you will always add new span tags on each click.
http://docs.jquery.com/Events/live#typefn