Is it safe to put all your code inside `$(document).ready`? - javascript

I'm using jQuery for a small project I have and it's one of my first times using it. Is it safe to put all my UI code in $(document).ready() ? I'm basically creating a form that pops up when a button is pressed, and the form is processed via AJAX. Basically, when I separate my AJAX function from the functions controlling the UI, the AJAX doesn't work. However, when I put both of them in $(document).ready(), everything works fine. Here's my code. Please ignore my comments, as they were for learning purposes.
$(document).ready(function(){ //ready for DOM manipulation
/*FORM UI*/
var container_form=$('#container_form'); //container form box
var addButton=$('.addButton'); //"+" add button
container_form.hide(); //initially hides form
$(addButton).click(function(){
$(container_form).toggle('fast');
/*SUBMISSION AJAX*/
$('form.ajax').on('submit',function() { //Make form with class "ajax" a JQuery object
var that = $(this), //"that"-current form, "url"-php file, "type"-post, "data"-empty object for now
url=that.attr('action'),
type=that.attr('method'),
data={};
that.find('[name]').each(function(index,value){ //search all elements in the form with the attribute "name"
var that=$(this), //legal attribute
name=that.attr('name'); //name of the legal attribute
value=that.val(); //value of text field in legal attribute
data[name]=value; //data object is filled with text inputs
});
$.ajax({
url: url, //url of form
type: type, //type of form
data: data, //data object generated in previous
success: function(response){ //reponse handler for php
if(!response){
console.log("Error");
}
console.log(response);
}
});
return false; //Stops submission from going to external php page.
});
});
});

Generally any selectors such as $('form.ajax')., $('#container_form'), $('.addButton') needs to be in doc.ready to ensure that the DOM is ready before you try to select an element from it, since it may not find the element if the DOM hasn't finished processing. So that pretty much applies to all of your code. If you had a function such as this:
//defines a function
function addThem(first,second)
{
return first + second;
}
You could declare it outside of doc ready, and call it from within doc ready.
$(document).ready(function(){
$('#someInput').val(
addThem( $('#anotherInput').val() , $('#thirdInput').val() )
);
});
The way I think about this, is doc ready is an event, so you should be doing things in response to the "document is now ready for your to query event", not declaring things. Declaring function just says what that function does, but doesn't actually do anything, so it can go outside of the document ready. It'd be pretty silly to declare this function inside of doc.ready since it can be defined at anytime (although it certainly is possible to put it inside doc ready, it just generally clutters things up). Even if it were selecting an element, that code isn't actually running until it is called:
function hideContainer()
{
//this code never runs until the function is called
//we're just defining a function that says what will happen when it is called
return $('#container').hide();
}
$(document).ready(function(){
//here we are calling the function after the doc.ready, so the selector should run fine
hideContainer();
});
Note that the act of wiring up to other events is an action in itself, such as when you subscribed to the click events and form submit events. You are saying, "find the form element with class .ajax, and subscribe to its submit event". You wouldn't want to try and wire up to events of DOM elements until the DOM is done processing. They might not "exist" yet as far as the browser is concerned if it is in the middle of processing the DOM, and thus your attempt to wire up to the click/form submit events may fail. I say may because depending on timing/processing lag it may sometimes work and sometimes not.

There's not only nothing wrong with putting all your code into one $(document).ready(), but there's nothing wrong with putting it into multiple $(document).ready() functions either so that you can separate repeated functionality into individual JS files.
For example, I use $(document).ready() in a script included on all my site's webpages to set up UI elements, prevent clickjacking, etc. At the same time, each page regularly has its own $(document).ready() which sets up page specific user interactions.

It is absolutely OK. If you find yourself needing to abstract your code into multiple function or multiple files, then by all means, but there's nothing wrong with throwing everything in $(document).ready().

Related

Best Practice with jquery functions and ajax

I'm new to ajax and want to best understand how to write my jQuery code so that then a page is called via ajax, my jQuery functions (simple stuff like slideshows and overlays) will still work.
Below is what I'm currently doing to make my jquery work on a stand alone page without ajax.
$('.microContentWrap').click(function(){
//perform some functions
});
In order to make this same function work when this page has been loaded via ajax, I'm duplicating my code and binding it to a div called "ajax-wrapper" that loads normally on this page. Without this step, the above code was not executing on the ajax page.
$("ajax-wrapper").on("click", ".microContentWrap", function() {
//exact same functions as above
});
Both of these things work, but is this the most efficient way? Seems repetitive to do this two step process for every single function in my file.
$("ajax-wrapper").on("click", ".microContentWrap", function() {
//exact same functions as above
});
Is saying: "when I click within 'ajax-wrapper' check to see if the element I clicked is 'microContentWrap', if it is, then do this function". The benefit of this approach is that 'microContentWrap' doesn't need to exist when you bind the click even listener.
Another approach would be to add the event listener to 'microContentWrap' in your ajax callback function. So for example:
$.ajax({
url:"getvalue.php",
success:function(data) {
$('body').append('<div class="microContentWrap"></div>');
$('.microContentWrap').click(function(){});
}
});
The solution to this was actually very simple, I just didn't understand binding. The problem I was having was that the ajax-wrapper gets destroyed after the microContent comes in. On other non-ajax pages there was no ajax-wrapper which is why I thought there needed to be two functions. By binding to the body, I eliminated the issue.
$("ajax-wrapper").on("click", ".microContentWrap", function() {
//exact same functions as above
});

Custom jQuery not working on Wordpress Ninja Forms plugin

I am having some problems when I want to add custom jQuery code that affects the form.
For example when someone clicks an input or radio button another input or element to be hidden or shown.I tried to get a result like console.log('trigger'); when clicked or something else but nothing in dev. console appeared.Also, I tried the following methods:
To call the click event with .on('click', function()... or to call the event with .trigger('click');, or to change the event to change
To embed the script within a file from ninja forms or to put it inside the page at the ending of body tag in footer.php
To change the opening declaration of jQuery to work inside a function like this : (function($) {$(document).ready(function(){.....
I know that I could try another plugin, I tried one and the custom jQuery works but I really like this one and don't know why this is happening ...
Thanks
Not sure if you need help with this any more as it's been some time since you posted your question, but this may help others in the future. I had the same/similar issue with not being able to run JS/jQuery on the Ninja Forms and found that it's because Ninja Forms load their forms asynchronously. So, when your document.ready function runs, the form doesn't yet exist and it's not able to bind.
Ninja Forms have their own event ready state that can be used as follows:
jQuery(document).on( 'nfFormReady', function( e, layoutView ) {
// Your code goes here...
});
The event isn't registered simply because the elements you're trying to bind the event to do not exist yet at that moment (on document load). Ninja forms loads the form contents asynchronously, so you'll have to wait until the form is fully loaded and then add your event listeners.
This works for me:
var formExists = setInterval(function() {
if ($(".nf-form-cont").length) {
// Set your event listeners here, example:
$("#nf-field-1").click(function(e) {
console.log("click!");
}
clearInterval(formExists);
}
}, 100); // check every 100ms

Run action on load and stay on same page

I am currently trying to run an action in my grails controller upon a page load in my application that will start a thread an continue with a task. I still have yet been able to successfully implement this in. This is my code:
$(document).ready(function(){
var $form = $("#background_thread");
$form.submit(function(e){
e.preventDefault();
$.post($(this).attr("background"), $(this).serialize(), function(data){
alert("should work" + data)
});
return false;
});
});
I cannot for the life of me figure out why it's not working. Is there some simple syntax I'm overlooking or a different way I should be doing this?
Update:
My form id is #background_thread and I am trying to do it asynchronously so that the page will still stay the same and my action will be run.
My script is run but fails on $form.submit(function(e){ and will not pass through.
You need to prevent the default behaviour on the event that has been generated.
$form.submit(function(e){
e.preventDefault();
// your code
}
Update:
You will certainly need to add the above regardless, once you get the overall script working. Also, please add your markup to the question. A few basic questions to make sure:
Is #background_thread the id of your form?
In your network tab in Chrome Inspector (or similar) is the request being fired off?
Is the markup being delivered asynchronously, as if it is, you will need to use .on to attach the event permanently, rather than just a basic selector?
Update 2:
Your form is being delivered asynchronously itself, therefore your event attaqchement must change to:
$(document).ready(function(){
$("body").on("submit", "#background_thread", function(e){
e.preventDefault();
$.post($(this).attr("background"), $(this).serialize(), function(data){
alert("should work" + data)
});
return false;
});
});
So, to explain, your event attachment was happening during document ready. Document ready fires, but the form hasn't been delivered to the DOM yet, so it doesn't have an attachment to it. Therefore, you use on() to permanently attach that event to that element for the lifetime of the entire page's rendering to the browser.
N.B. I attached it to body, to begin listening for submit at that point, in practice you would not do this for many reasons, you would attach it to the outermost point of AJAX replacement for the form, essentially, the nearest parent to the form that will be known on initial page load.
I hope that this has been of some use and good luck with your application.

Find a dynamical generated element by listening to a custom event (JavaScript)

I have a list whose li are generated dynamicaly via AJAX:
<ul>
<li id="hello"></li>
<li id="world"></li>
<li id="helloWorld"></li>
</ul>
I also have a global var in my script like this:
var world = 'world';
I want, on document ready, as soon as the list gets loaded, to find the li item with the same id as my global var:
$('ul').find('#' + world);
I can't use a conventional .on() event listener here since there is no other event to trigger it, except for the end of the loading itself.
So my next step was to trigger a custom event in my loading script:
$('ul').trigger('loadingDone');
And then listen for it:
$('ul').one('loadingDone', theFunctionThatDoesTheSearch );
Problem is, this failed and it completely ignored any of the generated elements.
I know that a possible solution would be to run these operations inside the success method of the ajax call, but the current architecture of the app I'm building doesn't allow for that. (I can and do trigger the event inside the success AJAX method, I just cant do the search there)
Basically what I am asking for are alternative solutions for allowing the loading script to let me know when it is done and ways to filter trough the generated content without doing the filtering inside the loading script itself.
$(document).on("customevent","ul",function(){
console.log("event triggered from inside the ajax success handler");
});
$.ajax({
url:'/echo/json/',
success:function(){
$('div').append("<ul><li>asd</li></ul>");
$("ul").trigger("customevent");
}
});
http://jsfiddle.net/xp7sr/2/
If your ajax request is performed through jquery, you could try http://api.jquery.com/ajaxComplete/.

how can i invoke a function after page is done loading? (and only then..)

I'm having trouble with some jquery code.
in my HTML page I use ajax to get some info, and then I'm changing an HTML element
with $("#id").html(...).
The problem is, I also have a $(document).ready code which I wanna call only once
when the page is done loading, but after each change in the html with the $("#id").html(...)
the code is called once again.
How can I run the $(document).ready code only once?
Here is an example:
$(document).ready(function(){
// this code will run not only once...
}
function f(){
$("#id").html(...);
}
Try:
var run = false;
$(document).ready(function() {
if(!run) {
...
run = true;
}
});
...or...
$(window).load(function() {
...
});
The first one will make sure it is only run once; the 2nd one is run when the entire page is finished loading (useful if you need to resize things once images have finished loading).
From the comments on the .ready documentation:
Looks like .ready() fires not only when page initially has settled the
DOM, but apparently also after changes to the DOM. This is an issue if
your ready handler changes the DOM. That will result in ready() firing
more than once. It may result in an endless loop if each invocation
adds yet more to the DOM. Firefox and IE behave differently to this,
including different error messages, and leaving the page display in
different states. So, if ready() modifies the DOM, then it would be
wise to have a way to check whether ready has already been fired.
Replying to self: Well it appears that part of the problem is not that
the ready function fires again (though that is possible aparently),
but that changing the DOM causes the script that creates the ready
function to fire again, adding an additional ready function, etc etc.
This seems to happen if the javascript is embedded in the html at a
point beyond (or contained in) the part of the DOM that the ready
handler modifies. (Obviously would be better to put script that
creates a ready function in the document head, but in this case that's
not an option.) Problem fixed by checking a global flag variable to be
undefined before executing jQuery(document).ready(...).
If this might be your problem, you can adopt the same solution:
var onLoadFired = false;
$(document).ready(function() {
/* Ensure this function only runs once */
if (onLoadFired) {
return;
}
else {
onLoadFired = true;
}
/* Business logic */
// .. your code here ..
});
Or, better, move your handler into a separate script file that's included by a script tag in your page's head element.
Try this:
$(window).bind("load", function() {
...
});

Categories