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.
Related
I just started learning web development and someone gave me this code to use. However, I want to understand it so that I can change it the way that I would like. However, I am having some trouble understanding it completely. I have the basics of computer programming. I just am having a hard time understanding what this code here is doing. I've done some research here https://api.jquery.com/. I understand the individual concepts kind of, but can't put them together. So here is what I understand so far:
.ready(): It makes sure that the page is loaded and is ready for use. And I'm assuming the following code won't execute unless the page is fully loaded and ready for interaction.
.click(): Basically responds to a click.
.each(): Kind of a like a for loop.
.next(): Goes to the next element.
.hide(): Hides the element (which is kind of confusing, because it doesn't actually hide it, it just makes it jump up)?
.toggle(): It reveals a hidden element?
Here is the code:
$(document).ready(function(){
$('.info').click(function(){
$('.info').each(function(){
$(this).next().hide();
});
$(this).next().toggle();
});
});
I think that's it. But I'm not sure how it all fits in. Could someone please explain it to me?
Also, why doesn't the code above work without this line:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
The line
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
loads the jQuery library from the CDN URL above. This Javascript file contains the definition of all the above functions you're using as well as many other useful functions. You can read more on the official docs. https://api.jquery.com/
Code Explanation
$(document).ready(function () {
This registers a ready event on document. In other words, the callback anonymous function is called when the DOM is completely loaded and is ready to be manipulated.
$('.info').click(function () {
Just like the ready event handler, this code binds a click event on all the elements having class of info.
$('.info').each(function () {
$(this).next().hide();
});
This part of code will loop over all the elements having the class of info and hides the next element of each element one by one.'
$(this).next().toggle();
This will toggle the visibility of the next element of the clicked-$(this) element. Not really, this is showing the next element as in the above each loop, you've hide all the next elements of .info class.
}); // End of click
}); // End of ready
Your code can also written without loop as
$(document).ready(function () {
$('.info').click(function () {
$('.info').not(this).next().hide();
// Hide all elements that are nextSibling of the elements having class info other than the clicked one
$(this).next().show();
// Show the next element of the clicked element
});
});
First of all, you should know js is a language, and most of the functions you mentioned here are jQuery functions.
jQuery is a library written in js which has a lot of functions and options to support development.
So the line of script you included, loads the jQuery library in to the page.
As for the other questions:
.ready(): It makes sure that the page is loaded and is ready for use. And I'm assuming the following code won't execute unless the page is fully loaded and ready for interaction.
As you wrote - this is a function to deal with page loading, although the following code will execute before page is done loading, and that is because js is a non-blocking script
so the proper use of .ready() is:
$(document).ready(function(){
....//all code you need after page is fully ready goes here
});
.click(): Basically responds to a click.
Correct. this responds to a DOM event of a DOM element. It is really impotent to understand what is DOM and how to use it when developing for web.
$(element).click(function(){
....//all code you need after clicking element goes here
});
.each(): Kind of a like a for loop.
Correct. this loops through DOM elements, and in each iteration you get a reference to the current one
$(elements).each(function(){
var element = $(this) //jquery wrapper of current iterated DOM element. this refers to current iterated DOM element
});
.next(): Goes to the next element.
this is a way of "walking" through the DOM tree, to manipulate elements in it
.hide(): Hides the element (which is kind of confusing, because it doesn't actually hide it, it just makes it jump up)?
this does actually hide the element. This would probably be done using css to hide the element
.toggle(): It reveals a hidden element?
this is a shortcut for hide() and show(). It checks if element is hidden, and if it is, it uses show(), otherwise, it uses hide(). as mentioned, this would also probably be done with css
In this example someone shows a jQuery onclick event.
My shows this:
$(function() {
$('.post').on('click', function() {
SOME STUFF
});
});
But what are the first and last line doing?
if i remove the lines, it's not working:
$('.post').on('click', function() {
SOME STUFF
});
But why? In the linked example is a second commenter. He shows this way (without first/last line).
Can someone explain this?
It is a shortcut for $( document ).ready(...)
See http://api.jquery.com/ready/
Quoting the doc :
While JavaScript provides the load event for executing code when a page is rendered, this event does not get triggered until all assets such as images have been completely received. In most cases, the script can be run as soon as the DOM hierarchy has been fully constructed. The handler passed to .ready() is guaranteed to be executed after the DOM is ready, so this is usually the best place to attach all other event handlers and run other jQuery code. [...]
All three of the following syntaxes are equivalent:
* $( document ).ready( handler )
* $().ready( handler ) (this is not recommended)
* $( handler )
That is short for document.ready. It waits until the entire document is loaded and the element with class .post can be found and bound to.
If you omit that part, the jQuery function will not find the element and your event will not work.
The first and last lines create an anonymous function. In computer programming, an anonymous function is a function defined, and possibly called, without being bound to an identifier.
In the example here it is used to set the event listener that is loaded onload of the page.
$(function() {
$('.something').on('click', function() {
alert('hello');
$(this).addClass('classOne');
});
});
$(function(){});
is jQuery short hand for
$(document).ready(function() {});
which ensures your document is ready for manipulation before executing anything within it. In many ways its similar to the browser window.onready event. See jQuery docs..
The risk if you don't wrap your jQuery code in either of these forms of the functions is that you will try and manipulate elements before they have been created by the browser. Your code is not guaranteed to fail, but you could, at the very least, get inconsistent behaviour.
First of all, I tried the answers in this, and this similar questions, but that does not seem to work for me at all.
I would like to do stuff on a click event bound to an element that is created via ajax so it is not in the DOM at first.
I notice that the following coffeescript in my_asset.js.coffee works as expected:
$ ->
$('#div').on "click", ".link", (e) ->
#do stuff
According to JQuery Doc:
this function is bound to all "selected_div" click events, even if they are added to the DOM via ajax later
And the do stuff part works ok
However I would like to:
$(this).after("<%= insert some long view here %>")
So, in order to do that, I guess I should move the $(this).after part from the asset.js.coffee to my_view.js.erb
where I could embed render partial
There, in my_view.js.erb, I have tried the following, (equivalent) javascript:
$(function() {
$("#div").on("click", ".link", function() {
$(this).after("<%= render partial here %>");
});
});
But it does not work for the first click, (it does, however, for the subsequent clicks)
I think it is related to the fact that .link is not in the DOM when the page loads for the first time.
Why is this happening? Is that the cause? And how could I get in the view the same behaviour that I get in the asset ?
You'll bind to a container element (typically document or body), and delegate the event to the to-be-created object:
$(document).on("click", "#div .link", function() {
$(this).after("<%= insert some long view here %>");
});
Binding
As you've pointed out, JS binds events to elements of the DOM on page load
If your element is not present at load, JS won't be able to bind, thus causing a problem. To fix this, you'll have to delegate the bind to an element higher in the DOM hierarchy, allowing JS to bind the event to any new elements in relation to your container
I am using an infinite scroll plugin which uses ajax.
When the 'next page' is loaded via ajax, all other ajax related scripts that are on the next page do not work. I have been told that I have to use 'delegated events'(ie change $(id).click() to $(document).on) - problem is that means editing multiple plugins and changing dozens of function calls.
Is there any way I can avoid changing everything to $(document).on and do something cool with the infinite scroll?????
I'd much rather modify the infinite scroll plugin rather than modifying other ajax related plugins to make them fit.
Unfortunately you have very few options here, and switching to delegated events is by far the best of them.
The problem is that your old code was assigning behaviour to "particular elements" when what it should really have been doing is creating page-wide responses to "certain types of actions".
I see 3 possibilities, and only one of them is guaranteed to work.
Run any scripts that are needed on new pages each time a new page is loaded. The downside here being that unless you are careful about also "tearing down" between content loads you will have behaviours repeating or colliding with each other (eg: double popups, broken animations).
Encapsulate the dynamic areas in <iframe>s. Depending on your architecture this may or may not be possible, and certainly won't be easy to integrate with some kind of infinite scrolling plugin which already expects a certain page structure.
Bite the bullet and fix the crappy code.
Loading scripts inside your ajax loaded content is a bad way to start with anyway. What you need is event delegation to attach itself to any dynamically added elements.
$("body").on("click", ".yourclass", function() {
//This function will run for every element with `yourclass` class you load via ajax
});
If you must keep using .click() then you must have a function you can call on the new content to re-hook the events every time you add more content to the page.
e: though it is worth noting that a change from .click to .on can often be handled by a properly structured find/replace
Event delegation is the correct solution. The issue is that the HTML elements on the "next page" were not part of the DOM when the page loaded. Therefore, if you did something like:
$(function() {
$('#some-element-on-the-next-page').click(function() {
foo();
});
});
Your handler did not bind.
I wouldn't attach the events to $(document). I would attach them to the closest parent which is available when the DOM loads. For example, the body tag or the fixed width wrapper which is the first child of the body (assuming your layout uses this type of structure.)
Make sure that the element that you attach to is not emptied with .empty() or repopulated with .html() as that will break the binding. Attaching the delegated handlers lower down on the DOM tree will give you better performance since the events will not have to bubble all the way up to the document node to fire your methods.
You shouldn't need to rewrite all of your functions and plugins, just the bindings to the events that fire them.
I typically use the module pattern and de-couple my method definitions from the click handlers. All of my methods are defined in the outer closure. I'll have a "document ready" section where I bind user events like clicks.
For example:
var myModule = (function() {
var public = {};
public.foo = function() {
// do something cool here
};
// document ready
$(function () {
$('#site-container').on('click', '.js-foo', function() {
public.foo();
});
});
return public;
})();
If you need to change the bindings in the future you will only need to change the call inside the document ready section.
I have a javascript code and I couldn't understand that how it is executed after inserted to dom with jquery.
Also is domready event is triggered after a dom append|insert operation? It couldn't be happen but how this code is working if its not?
function insert() {
var data = '<script type="text/javascript"> $(function(){ alert("insert"); });<\/script>';
$("#example").html(data);
}
$(function () {
//If domready is triggered with the .html() method why this is not executed second time?
alert('ready');
});
JsFiddlle link
See the second quoted block for this ansewer https://stackoverflow.com/a/3603496/81053
All of jQuery's insertion methods use a domManip function internally to clean/process elements before and after they are inserted into the DOM. One of the things the domManip function does is pull out any script elements about to be inserted and run them through an "evalScript routine" rather than inject them with the rest of the DOM fragment. It inserts the scripts separately, evaluates them, and then removes them from the DOM.
I believe that one of the reasons jQuery does this is to avoid "Permission Denied" errors that can occur in Internet Explorer when inserting scripts under certain circumstances. It also avoids repeatedly inserting/evaluating the same script (which could potentially cause problems) if it is within a containing element that you are inserting and then moving around the DOM.