javascript events not working with dynamic content added with json - javascript

I'm stuck with a situation where my DOM elements are generated dynamically based on $.getJSON and Javascript functions for this elements are not working. I'll post some general idea on my code because I'm looking just an direction of what should I do in this situation.
site.js contains general features like
$(document).ready(function() {
$('.element').on('click', function() {
$(this).toggleClass('active');
});
$(".slider").slider({
// some slider UI code...
});
});
After that:
$.getJSON('json/questions.json', function (data) {
// generating some DOM elements...
});
I have also tried to wrap all site.js content into function refresh_scripts() and call it after $.getJSON() but nothing seems to be working.

Firstly you need to use a delegated event handler to catch events on dynamically appended elements. Then you can call the .slider() method again within the success handler function to instantiate the plugin on the newly appended content. Try this:
$(document).ready(function(){
$('#parentElement').on('click', '.element', function() {
$(this).toggleClass('active');
});
var sliderOptions = { /* slider options here */ };
$(".slider").slider(sliderOptions);
$.getJSON('json/questions.json', function(data) {
// generating some DOM elements...
$('#parentElement .slider').slider(sliderOptions);
});
});

Instead of calling on directly on the element, call it on a parent that isn't dynamically added and then use the optional selector parameter to narrow it to the element.
$('.parent').on('click', '.element', () => {
// do something
});
The difference between this and:
$('.element').on('click', () => {});
is with $('.element').on(), you're only applying the listener to the elements that are currently in that set. If it's added after, it won't be there.
Applying it to $(.parent), that parent is always there, and will then filter it to all of it's children, regardless when they're added.

the easiest way is to add this after you add/generate your DOM
$('script[src="site.js"]').remove();
$('head').append('<script src="site.js"></script>');
of course your js function that generates DOM needs to be on another file than your site.js

Related

Firing a function with a newly added class

I've tried to simplify it, simple enough to make my question clearer.
The alert 'I am a boy' didn't popup with even after the addClass has been executed.
Here is my code:
$(".first").click(function () {
var a = $(this).html();
if (a=='On') {
$(this).removeClass('first').unbind().addClass('second');
$(this).html('Off');
}
});
$(".second").click(function () {
alert('I am a boy');
});
<button class="first">On</button>
This behavior is because you are apply a class to an element after the DOM has loaded, in other words dynamically. Because of this, your event listener attached to the control for '.second' isn't aware of the newly added class and doesn't fire when you click on that control.
To fix this, you simply need to apply your event listener to a parent DOM object, typically $(document) or $('body'), this will ensure it is aware of any children with dynamically added classes.
As George Bailey said, you can refer here for a in depth explanation.
In regards to your specific code, the fix is to simply adjust it as so:
$(".first").click(function () {
var a = $(this).html();
if (a=='On') {
$(this).removeClass('first').unbind().addClass('second');
$(this).html('Off');
}
});
/* Changed this:
$(".second").click(function () {
alert('I am a boy');
});
*/
// To this:
$(document).on('click', '.second', function () {
console.log('I am a boy');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="first">On</button>
The function you pass to $.post doesn’t run until later (a callback). So the class is added after you try to select it. Do it inside the callback, the same way you added the class (and you don’t need to select that class, just use $this)

Force My jquery to run on any newly added dom elements

I have the following scripts, which contains two selectors:-
$(document).ready(function () {
if ($("#ChoiceName2").prop("checked")) {
&
$("#ChoiceTag2, #ChoiceName2").each(function () {
$(this).change(function () {
The selectors will not fire on any newly added Dom elements, usually i use the .on to force my jquery to run on any newly added elements as follow:-
$("body").on('click', '#DCSort', function () {
but not sure how i can add the .on to mt first script ?
Since you are using #ChoiceTag2, #ChoiceName2 as selector, $.each is not required. As it's going to return you only one element always as it's an ID.
$('body').on("change", "#ChoiceTag2, #ChoiceName2", function () {
This will do the trick for the newly added elements
The best way to accomplish what you are trying to do is by using a CSS class that has no style definition, but will allow you to bind a delegate to events involving that class.
That way the delegate acts on the class, regardless of when it is added to the DOM.
Like this:
<button class='DCSort'>Some Button</button>
$('body').on('click', '.DCSort', function () {
}

JQuery event handler when select element is loaded

Is there an event handler to use in JQuery when a DOM select element has finished loading?
This is what I want to achieve. It is working with other events except 'load'.
This piece of code is loaded in the head.
$(document).on('load', 'select', function(){
var currentSelectVal = $(this).val();
alert(currentSelectVal);
} );
The question was badly formed earlier. I need to attach the event handler to all select elements, both present when the document is loaded and dynamically created later.
They are loaded from a JQuery Post to a php-page. Similar to this:
$.post("./user_functions.php",
{reason: "get_users", userID: uID})
.done(function(data) { $("#userSelector").html(data);
});
I think we're all confused. But a quick break down of your options.
After an update made to the Question, it looks like the answer you might seek is my last example. Please consider all other information as well though, as it might help you determine a better process for your "End Goal".
First, You have the DOM Load event as pointed out in another answer. This will trigger when the page is finished loading and should always be your first call in HEAD JavaScript. to learn more, please see this API Documentation.
Example
$(document).ready(function () {
alert($('select').val());
})
/* |OR| */
$(function() {
alert($('select').val());
})
Then you have Events you can attach to the Select Element, such as "change", "keyup", "keydown", etc... The usual event bindings are on "change" and "keyup" as these 2 are the most common end events taking action in which the user expects "change". To learn more please read about jQuery's .delegate() (out-dated ver 1.6 and below only), .on(), .change(), and .keyup().
Example
$(document).on('change keyup', 'select', function(e) {
var currentSelectVal = $(this).val();
alert(currentSelectVal);
})
Now delegating the change event to the document is not "necessary", however, it can really save headache down the road. Delegating allow future Elements (stuff not loaded on DOM Load event), that meet the Selector qualifications (exp. 'select', '#elementID', or '.element-class') to automatically have these event methods assigned to them.
However, if you know this is not going to be an issue, then you can use event names as jQuery Element Object Methods with a little shorter code.
Example
$('select').change(function(e) {
var currentSelectVal = $(this).val();
alert(currentSelectVal);
})
On a final note, there is also the "success" and "complete" events that take place during some Ajax call. All jQuery Ajax methods have these 2 events in one way or another. These events allow you to perform action after the Ajax call is complete.
For example, if you wanted to get the value of a select box AFTER and Ajax call was made.
Example
$.ajax({
url: 'http://www.mysite.com/ajax.php',
succuess: function(data) {
alert($("select#MyID").val());
}
})
/* |OR| */
$.post("example.php", function() { alert("success"); })
.done(function() { alert($("select#MyID").val()); })
/* |OR| */
$("#element").load("example.php", function(response, status, xhr) {
alert($("select#MyID").val());
});
More reading:
.ajax()
.get()
.load()
.post()
Something else to keep in mind, all jQuery Ajax methods (like .get, .post) are just shorthand versions of $.ajax({ /* options|callbacks */ })!
Why dont you just use:
$(document).ready(function () {
//Loaded...
});
Or am I missing something?
For your dynamic selects you can put the alert in the callback.
In your .post() callback function, try this:
.done(function(data) {
data = $(data);
alert(data.find("select").val());
});
Ok, correct me if I understand this wrong. So you want to do something with the selects when the document is loaded and also after you get some fresh data via an ajax call. Here is how you could accomplish this.
First do it when the document loads, so,
<script>
//This is the function that does what you want to do with the select lists
function alterSelects(){
//Your code here
}
$(function(){
$("select").each(function(){
alterSelects();
});
});
</script>
Now everytime you have an ajax request the ajaxSend and ajaxComplete functions are called. So, add this after the above:
$(document).ajaxSend(function () {
}).ajaxComplete(function () {
alterSelects();
});
The above code will fire as soon as the request is complete. But I think you probably want to do it after you do something with the results you get back from the ajax call. You'll have to do it in your $.post like this:
$.post("yourLink", "parameters to send", function(result){
// Do your stuff here
alterSelects();
});
Do you want all Selects to be checked when the User-Select is loaded, or just the User-Select?...
$.post("./user_functions.php", {reason: "get_users", userID: uID}).done(function(data) {
$("#userSelector").html(data);
//Then this:
var currentSelectVal = $("#userSelector").val();
alert(currentSelectVal);
});
If your select elements are dynamically loaded, why not add the event handler after you process the response?
e.g. for ajax
$.ajax({
...
success: function(response) {
//do stuff
//add the select elements from response to the DOM
//addMyEventHandlerForNewSelect();
//or
//select the new select elements from response
//add event handling on selected new elements
},
...
});
My solution is a little similar to the posters above but to use the observer (pubsub) pattern. You can google for various pub sub libraries out there or you could use jQuery's custom events. The idea is to subscribe to a topic / custom event and run the function that attach the event. Of course, it will be best to filter out those elements that have been initialize before. I havent test the following codes but hopefully you get the idea.
function attachEventsToSelect(html) {
if (!html) { // html is undefined, we loop through the entire DOM we have currently
$('select').doSomething();
} else {
$(html).find('select').doSomething(); // Only apply to the newly added HTML DOM
}
}
$(window).on('HTML.Inserted', attachEventsToSelect);
// On your ajax call
$.ajax({
success: function(htmlResponse) {
$(window).trigger('HTML.Inserted', htmlResponse);
}
});
// On your DOM ready event
$(function() {
$(window).trigger('HTML.Inserted'); // For the current set of HTML
});

How can I call a Jquery method on DOM elements that don't exist yet?

I'd like to use this lightbox plugin for some autocomplete links, that don't yet exist on my page.
You normally activate it using:
$(document).ready(function($) {
$('a[rel*=facebox]').facebox()
})
Since the a links aren't all on the page upon page load, I would normally look to the .live or .delegate methods to bind to an event, but in this case, what 'event' would I bind to to say "once this element is on the page, then call this method on it".
Or am I going about this totally the wrong way?
There is no such event.
You need to invoke the plugin when you add the elements to the page.
// create a new <a>, append it, and call the plugin against it.
$('<a>',{rel:"facebox"}).appendTo('body').facebox();
This example creates a new <a> element. If you're getting some elements from an AJAX response, call it against those:
var elems = $( response );
elems.filter( 'a[rel="facebox"]' ).facebox(); // if the <a> is at the top level
elems.find( 'a[rel="facebox"]' ).facebox(); // if the <a> is nested
elems.appendTo('body');
Not yet tested :
$(document).ready(function($) {
$(document).bind('change', docChanged) ;
})
function docChanged()
{
if ($('a[rel*=facebox][class!="faceboxed"]').length > 0)
{
$('a[rel*=facebox][class!="faceboxed"]').addClass("faceboxed").facebox();
}
}
This is entirely possible using the .live function. You just need to use the DOMNodeInserted event.
$(document).ready(function() {
$("a[rel*=facebox]").live("DOMNodeInserted", function() {
$(this).facebox();
});
});
You'll need to just add this call to the ajax that loads in the links.

Javascript + jQuery, click handler returning false to stop browser from following link

I'm trying to stop the browser from following certain links, rather I want to unhide some Divs when they are clicked.
I'm having trouble just getting the links to not be followed though.
Here's what I have:
var titles = $('a.highlight');
jquery.each(titles, function(){
this.click(function(){
return false;
});
});
It seems like the click handler is not being assigned. What am I missing?
Try
this.click(function(e){ e.preventDefault(); }
Actually, it looks like you might need to use the jQuery constructor on this:
$(this).click(function(){ return false; }
You could also try using parameters on the each function instead of using this:
jQuery.each( titles, function(index, elem) { $(elem).click( function() { return false; } ) } );
Personally, I would just do titles.each( ... though. In that instance you can use this to bind the click handler. I am not sure off the top of my head what this binds to with jQuery.each
Or just calling click on titles:
titles.click( function() { return false; } )
That will bind click to every element in titles. You don't need to loop through them.
You can compress that jquery a bit:
$('a.highlight').click(function() { return false; });
You should also make sure that:
There are no other click handlers registered for those elements later on.
The code you have is attaching after the elements have loaded. If they're not completely loaded, they won't be found in the $('a.highlight') selector. The easiest way to do this is to put your code in a $(document).ready(function() { *** code here *** }); block.
Edit: As per other responses - the problem was that this represents a DOM object, while $(this) is a jquery object. To use the .click function to attach a handler, you need a jquery object.
In short, using this inside the each loop won't work with what you're trying to do. You'll need to get a jquery representation by using $(this) instead.

Categories

Resources