I need to execute:
$('.btn-toolbar').toolbar({
content: '#toolbar-options'
});
Elements with .btn-toolbar class are not in DOM because are added after and ajax request. How can I select elements outside DOM?.
In other similar question it's solved with Delegate Event, but I don´t have any event for managing it, I don´t need enable click on it, hover or any other event. I just want to execute toolbar function for all elements with btn-toolbar, but $('.btn-toolbar') is empty at this time.
You can execute the code on the ajax call success/complete after it places the elements of class .btn-toolbar in the DOM.
$.ajax({
....
}).done(function() {
// Places/Inserts the .btn-toolbar elements in the page.
$('.btn-toolbar').toolbar({
content: '#toolbar-options'
});
});
If the ajax call is made by some other script where you cannot(for example - by some other plugin's minified script, or that script is from other site) inject your code, still you can interfere on the ajax call and attach your code to be run after.
You can use jQuery.ajaxSetup() to customize the ajax calls made in your site.
For example you can run your code whenever an ajax call completes successfully by:
$( document ).ajaxSuccess(function() {
$('.btn-toolbar').toolbar({
content: '#toolbar-options'
});
});
If an element is not in any element subtree (i.e. not a child of any other element), and you aren't holding a reference to it (nor is any other object referencing it), it's effectively gone, and subject to garbage collection.
If you are holding a reference to it, you will need to use that reference. If it's a child of some other element (whether or not that element is in the DOM tree), you'll need to include that parent element in your selection, which means you will need at least a reference to that parent element. Otherwise you don't really have any other way of reaching it.
If the element doesn't actually exist yet, and you're just saying "invoke this command on any .btn-toolbar as it gets loaded into the page", then you need a mutation observer.
Related
I know putting JavaScript in partials is a bad idea because the page will have to load up a new script every time a new partial is loaded. I am aware of and have read this question, but its answer did not work for me (putting the script into app/javascripts/application.js). I think it is because I am working with partials that are dynamically generated onto the page. I think the dynamically generated partial does not react to the script loaded up on the initial page.
For example, I have a "Rule" div with a select input that has a script to do something when the select input is changed. This works for every Rule div that is generated on page load. But then there is also a "+" or "ADD" button which will dynamically generate more Rule divs which do not respond to the script, unless that script is in the partial.
Is there a good way to keep the script out of the partial when the partial is dynamically generated?
JQuery sets listeners on page load (i.e. $(selector).on(etc.)), so it doesn't listen for events on dynamically added elements. There is a way around it, though. You need to use what is called a delegate.
$(document).ready( function() {
$('body').on('change', 'input.selector', function(e) {
// do something
});
});
I'm not sure what your event (here I put change) or selector for the select you are using (here I put input.selector), but if you replace those with the appropriate information, it should work even with dynamically added elements.
You can use JQuery to execute the code only after the document has loaded onto the DOM:
$( document ).ready(function() {
//Call your functions here
});
That way, your JS will have access to whatever is on the page, because you are ensuring that it is fully loaded.
If your divs are not in place on document ready, you can use event delegation, as suggested by ptd. Basically what this means is that you install a handler on a parent div (which will be present on document ready) which says, "hey, when you click on this dynamic div inside of me, call this function".
$('div#master').on('click', 'div.dynamic', function(event) {
console.log("action here")
var $dynamicDiv = $(event.currentTarget) //The current Target is the thing you clicked on, not the parent.
});
If you are adding elements to the DOM using AJAX calls, but want to keep your JavaScript in your assets folder only, here's a quick and clean way to accomplish this.
// /app/assets/javascript/foo.js
// On intial page load
$(document).ready(function() {
yourJavaScriptForPartials();
});
// After a subdomain field is loaded via AJAX
$(document).ajaxComplete(function() {
yourJavaScriptForPartials();
});
function yourJavaScriptForPartials() {
// Insert your javascript here.
};
Now, any JavaScript you put in the yourJavaScriptForPartials() function will be available both to the initially loaded DOM, and to any DOM elements added via AJAX. For reference, here is the JQuery page for the ajaxComplete event listener.
I have the following code:
var $reviewButton = $('span.review_button');
$reviewButton
.live('click',
function(){
$('#add_reviews').show();
}
)
Later in the script, I use an AJAX call to load some content and another instance of $('span.review_button') enters the picture. I updated my code above to use '.live' because the click event was not working with the AJAX generated review button.
This code works, as the .live(click //) event works on both the static 'span.review_button' and the AJAX generated 'span.review_button'
I see however that .live is depracated so I have tried to follow the jquery documentations instructions by switching to '.on' but when I switch to the code below, I have the same problem I had before switching to '.live' in which the click function works with the original instance of 'span.review_button' but not on the AJAX generated instance:
var $reviewButton = $('span.review_button');
$reviewButton
.on('click',
function(){
$('#add_reviews').show();
}
)
Suggestions?
The correct syntax for event delegation is:
$("body").on("click", "span.review_button", function() {
$("#add_reviews").show();
});
Here instead of body you may use any static parent element of "span.review_button".
Attention! As discussed in the comments, you should use string value as a second argument of on() method in delegated events approach, but not a jQuery object.
This is because you need to use the delegation version of on().
$("#parentElement").on('click', '.child', function(){});
#parentElement must exist in the DOM at the time you bind the event.
The event will bubble up the DOM tree, and once it reaches #parentElement, it is checked for it's origin, and if it matches .child, executes the function.
So, with this in mind, it's best to bind the event to the closest parent element existing in the DOM at time of binding - for best performance.
Set your first selector (in this case, div.content) as the parent container that contains the clicked buttons as well as any DOM that will come in using AJAX. If you have to change the entire page for some reason, it can even be change to "body", but you want to try and make the selector as efficient as possible, so narrow it down to the closest parent DOM element that won't change.
Secondly, you want to apply the click action to span.review_button, so that is reflected in the code below.
// $('div.content') is the content area to watch for changes
// 'click' is the action applied to any found elements
// 'span.review_button' the element to apply the selected action 'click' to. jQuery is expecting this to be a string.
$('div.content').on('click', 'span.review_button', function(){
$('#add_reviews').show();
});
There are some attributes of an html element that cannot be figured out until it is in the HTML DOM such as offsetHeight or offsetWidth. If I createElement('div') and want to use the div's offsetHeight, is there an event that fires when this element is appended to the document so that I know I can now use offsetHeight?
DOMNodeInserted might be what you are looking for.
See https://developer.mozilla.org/en/DOM/DOM_event_reference for details about DOM events
No, I don't think there is an event for that. But you can append a property to the newly created element telling your script it is appended. You could do something like:
function appendSignal(el,toElement){
to.appendChild(el);
el.isAppended = true;
}
var nwdiv = document.createElement('div');
// do stuff with nwdiv
appendSignal(nwdiv,document.body);
//doing other stuff
if (nwdiv.isAppended) {
/* nwdiv.offsetHeight should be available... */
}
Some browsers will initialise these attributes as soon as you've added it to the DOM. It needs to be in the DOM so CSS rules can be applied.
So you won't need to receive an event, just adding the element to the DOM as soon as it is created usually works.
But if you find the attributes you need are not initialised immediately, you can separate that code into another function (like you would for an event handler) and invoke it using setTimeout(otherFunction, 0) with no delay. Once your JavaScript has finished executing, the browser will respond to your DOM changes accordingly, and then immediately invoke your other function. This is kind of like having the event, but firing it yourself.
Not sure if this is a bug or I am not suppose be doing this.
I have a page with sidebars that loads the main body dynamically.
For page1, I have a callback for an element #id1, which works on initial load.
After the user navigates to page2, the main content will get replaced by contents of page2, which also has an element with #id1, they serve the same purpose. events are initialized there as well.
The problem is that everything on page 2 would work except the event associated with #id1.
If navigating back to page 1, #id1 wouldn't work as well.
After looking at the console, I found that when calling $("#id1") sometimes give me the initial load element (not destroyed?), which is probably the reason.
The ajax load simply uses:
$.get(path, function(data) {$('#main').html(data)});
Any idea what's going on here?
If the old elements are not 'properly destroyed in jquery', what is suppose to be done here.
While it's not clear exactly what you're binding, the solution is to use (depending on your jQuery version) live() or on() to ensure that you bind to elements that aren't in the DOM at execution time.
jQuery 1.7+: on()
$(document).on('click', '.selector', function() { ... });
jQuery <1.7: live()
$('.selector').live('click', function() { ... });
Remember that an ID should only occur once
Because you don't know what elements with ID's may still be living in the DOM after the Ajax call you should stick with classname's instead.
With that you can use jQuery's .live() to bind to elements that have been dynamically loaded.
You have to generate dynamic id for that. When you click the right bar option the id will generated and place the id in the body element "id" tag.So you know that which id is generated for which page. Call a javascript function on "onclick" event and pass that id to this function then call the body element as $("#id"+that generated_id).something;
I think this will help.
I'm still new to jQuery and I'm wondering how come the jQuery functions called inside .ready() work just fine but not outside?
For example, this would work:
$(document).ready(function() {
$('#field1').click(function() {
$('#result').load('/random_post #post');
});
});
But this won't:
$('#field1').click(function() {
$('#result').load('/random_post #post');
});
You cannot access the DOM until the document is fully parsed and the DOM constructed. That includes modifying any elements – such as #field1 and #result.
Since $(document).ready(..) is long and may be hard to remember, you can also use the short form $(onReadyFunction), i.e.
$(function() {
$('#field1').click(function() {
$('#result').load('/random_post #post');
});
});
By the way, jQuery does no magic here: It just registers your function to be called when DOMContentLoaded (or equivalent) event is triggered by the parsing and construction of the DOM tree.
How and if it works will depend on the order of which scripts and elements are laid out in your HTML, and it might also be affected by parameters outside your control (e.g. how the browser is programmed to behave).
I 'd hazard a guess that this script appears in your page before the element with id="field1" that gets a click handler added; this causes the script to run and find no such element in the document tree (yet). The element gets added after the script runs, which is why jQuery finds it just fine after the whole document has loaded.
If you move this script at the very end of your page it should work (although of course the correct solution is to use the document ready event, as in your first snippet).
The ready function is executed when the dom tree has been created. You get an error in your second piece of code because the dom tree element with id filed1 has not been created yet, i.e. the page hasn't loaded yet.