Hey, I'm new to JavaScript so this is most probably going to sound really basic but here goes.
My web page is made up of "modules" which I load into the page with jQuery, so that my JavaScript works with the new content that has been loaded into the page, I have been told to use callback functions.
My problem is though, how do I activate multiple callback functions?
here is some of my code:
function loadLoginForm() {
$('[name=loadLoginForm]').click(function() {
$("#mainWrap").css({ width:"300px", height:"200px" });
$("#mainWrap").load("modules/web/loginForm.php", null, loadRegisterForm);
});
}
This bit of code activates the function named "loadRegisterForm" but what do i do if I want to activate more than one?
I've tried a few ways of how I think it would be done but to no avail, also I tried Google but I believe I'm using the wrong terminology.
It may be something like what you need?:
function loadLoginForm() {
$('[name=loadLoginForm]').click(function() {
$("#mainWrap").css({ width:"300px", height:"200px" });
$("#mainWrap").load("modules/web/loginForm.php", null, function(data) {
loadRegisterForm_1(data);
loadRegisterForm_2(data);
loadRegisterForm_3(data);
});
});
}
EDIT II:
function loadLoginForm() {
$('[name=loadLoginForm]').click(function() {
$("#mainWrap").css({ width:"300px", height:"200px" });
$("#mainWrap").load("modules/web/loginForm.php", null, function(data) {
loadRegisterForm_1.call(this, data);
loadRegisterForm_2.call(this, data);
loadRegisterForm_3.call(this, data);
});
});
}
Related
I have the following code with which I used to refresh a captcha image via JavaScript. Is there anyway I can also achieve that using an AJAX request?
<script>
function refreshCaptcha() {
$("#captcha_code").attr('src','captcha_code.php');
}
</script>
<button name="submit" onClick="refreshCaptcha();">Refresh Captcha</button>
Yes it's possible, but then you need to handle session manually!
<script>
$(".RefreshCaptcha").click(function () {
$.post('captcha_code.php', function(data, status){
$("#captcha_code").attr('src', data);
console.log("ajax log: " + status);
});
});
</script>
<button class="RefreshCaptcha">Refresh Captcha</button>
w3shcools ajax.post
You can use the following code.
<script>
$(document).ready(function() {
setInterval(function() {
$.post('captcha_code.php', function(data) {
$('#captcha_code').html(data);
});
}, 1000);
});
</script>
Yes AJAX can be used to update the update the image via Javascript. Because the code already uses jQuery, a simple way would be to use $.post() to post to the PHP script. Presuming that captach_code.php merely returns the image source (e.g. base-64 encoded string), you can set the src attribute to the response value (e.g. in the function updateImage() below).
function refreshCaptcha() {
$.post('captcha_code.php', updateImage);
}
function updateImage(response) {
$("#captcha_code").attr('src',response);
}
See it in action in this phpfiddle. Note - there is no control of the filenames so PHP_SELF is used instead of captcha_code.php.
$.post() returns a jqXHR object, which implements the Promise interface. Because of this, .done() and other similar functions can be used instead of specifying the success callback:
function refreshCaptcha() {
$.post('captcha_code.php')
.done(function(response) {
$("#captcha_code").attr('src',response);
})
.fail(function() {
//fail handler...
})
.always(function() {
//handler for all cases
});
}
See it in action in this phpfiddle.
I'm super confused by my code. Let me show what it looks like:
$(document).ready(function ($) {
var customer_exists = false;
$.get(window.additional_parameters.customer_exists_url, "json")
.done(function () {
customer_exists = true;
})
.always(function () {
// Don't make request to buy clickable until we know if the customer exists
$('#request-to-buy').on('click', function(e) {
request_to_buy(customer_exists);
});
});
function request_to_buy(customer_exists) {
response = can_request_to_buy();
response.done(function (response) {
if (customer_exists) {
// Actually create the request on the server
$.post(window.additional_parameters.request_to_buy_url,
{'ticket_id': window.additional_parameters.ticket_id},
"json")
.done(function (response) {
request_to_buy_success(response);
})
.fail(function () {
var message = handle_ajax_response(response);
show_ajax_message(message);
});
} else {
show_pre_stripe_popup();
}
})
.fail(function (response) {
var error_message = handle_ajax_response(response);
show_ajax_message(error_message, 'danger');
});
}
$(document).ready(), we set a variable called customer_exists. This variable guides the path of the code afterwards and is pretty important. If the $.get AJAX request is successful, it's true, otherwise it remains it default value of false. After the AJAX response, we attach a click event to "#request-to-buy." My goal here is to create a closure and pass in the value of customer_exists that was just set. This doesn't happen.
A good portion of the time ( I had it work correctly once or twice ), when I inspect request_to_buy in the debugger, I can see that customer_exists is a jQuery click event. why ??? Shouldn't it take on the value of the customer_exists from the surrounding scope of where the function was created? Can anyone explain what is going on here?
Thank you
EDIT: Here's a little more information that describes how it works sometimes...
The first time that I click '#request-to-buy', the handler is
function(e) {
request_to_buy(customer_exists);
}
This is what we would expect. e contains the click event, customer_exists retains it's value, and everything works inside request_to_buy.
Every time I click '#request-to-buy' after the first, instead of the above function being called, request_to_buy is called directly, and instead of passing in customer_exists in the first parameter, the click event is passed in instead. I hope this helps someone.
You should be able to do this without the need for the cumbersome outer var customer_exists.
For example :
$(document).ready(function ($) {
$.get(window.additional_parameters.customer_exists_url, "json").then(function () {
// Don't make request to buy clickable until we know if the customer exists
$('#request-to-buy').on('click', request_to_buy);
}, function() {
$('#request-to-buy').on('click', show_pre_stripe_popup);
});
function request_to_buy(e) {
e.preventDefault();
can_request_to_buy().then(function(response) {
// Actually create the request on the server
$.post(window.additional_parameters.request_to_buy_url, {
'ticket_id': window.additional_parameters.ticket_id
}, "json").then(request_to_buy_success, function() {
show_ajax_message(handle_ajax_response(response));
});
}).fail(function(response) {
show_ajax_message(handle_ajax_response(response), 'danger');
});
}
}
show_pre_stripe_popup will also be passed an event and you may need to do e.preventDefault(); there too.
You will need to check that the correct parameters are passed to the various error handlers. I can't verify them.
If it still doesn't work, then you must suspect other code that's not included in the question, for example the function can_request_to_buy().
var customer_exists = false;
Declare this outside of ready block.
I have some standard plugins bindings on jQuery ready() function that works fine for all new requests. Now, as we add more and more ajax to the app, these new elements are left behind the initial bindings.
Example rules:
$(function () {
$('.date').datepicker({ showOn: 'button', buttonImage: "cal.gif" })
.blur(function (e) {
$(this).val(formatFecha($(this).val()));
})
$('.ui-datepicker-trigger').attr("tabindex", "-1");
$(".decimalnumber").numpadDecSeparator({ separator: "," })
.numeric(",")
.focus(function () { if ($(this).val() == '0,00' || $(this).val() == '0') $(this).val(''); });
$(".integernumber").numeric().focus(function () { if ($(this).val() == '0') $(this).val(''); });
$(".spinner").spinner({ min: 0, max: 10000000 });
$(".jbtn").button();
.......
I'm not talking about the live() function to bind events, as this are not events.
Since I think this is fairly common I'm wondering how do you people do it.
Place those functions in a separate function of their own. Call THAT function on document.ready and any other time you need to reload things.
function initialize() {
// do stuff;
}
$(document).ready(function() {
initialize();
});
$.ajax({
// url, data, etc.
success: function() {
initialize();
}
});
Be aware that some plugins, such as slideshows that alter the DOM, may need you to call a destroy method or option before re-initializing them.
I use a javascript library called TerrificJS. It allows me to easily load html with ajax and initialize the javascript that goes with it on time. But it's not quite that simple. TerrificJS relies on naming conventions.
Let's say the ajax return the following html:
<div class="mod modMyInteractiveModule">Cool stuff, buttons etc here</div>
I then have a helper function that scans the html returned on ajax success and picks out all elements with the css class mod and modX. The helper checks if there is a javascript class named X or, staying with the example above MyInteractiveModule.
Tc.Module.MyInterActiveModule = function () {
// Bindings go here
}
I hope I could shed some light, even if you don't want to use TerrificJS and implement your own solution. The TerrificJS example to this can be found on http://terrifically.org/api/sandbox/ under Add new widgets dynamically.
I would move all of the code specified in an init() function and call it on document.ready and on ajax success/failure, depending on what i'm trying to do
I ended up using a refined version of #Blazemonger code:
You just need to put to new elements a class name by convention.
function initialize(parent) {
$(parent + ' .date').datepicker({ showOn: 'button'})
$(parent + ' .autocomplete').each(function (i, el) {
addbuttonautocomplete(el);
});
....
// remove the class to avoid double initialization
$(".newelements").removeClass('newelements');
}
$(document).ready(function() {
initialize('body');
});
$.ajax({
// url, data, etc.
success: function() {
initialize('.newelements');
}
});
Proof of concept: http://jsbin.com/ireguj
To keep organized, I'd like to keep all the javascript for my site in a single file:
scripts.js
However, some of my scripts are only used on on some pages, other scripts are only used on other pages.
In my document-ready function it looks like this:
function home_page() {
// image rotator with "global" variables I only need on the home page
}
$('#form')... // jQuery form validation on another page
The problem with this, is that I am getting javascript to execute on pages it's not even needed. I know there is a better way to organize this but I'm not sure where to start...
One thing you could do would be to use classes on the <html> or <body> tag to establish the type of each page. The JavaScript code could then use fairly cheap .is() tests before deciding to apply groups of behaviors.
if ($('body').is('.catalog-page')) {
// ... apply behaviors needed only by "catalog" pages ...
}
Even in IE6 and 7, making even a few dozen tests like that won't cause performance problems.
I usually do something like this, or some variation (a little pseudo code below) :
var site = {
home: {
init: function() {
var self=this; //for some reference later, used quite often
$('somebutton').on('click', do_some_other_function);
var externalFile=self.myAjax('http://google.com');
},
myAjax: function(url) {
return $.getJSON(url);
}
},
about: {
init: function() {
var self=this;
$('aboutElement').fadeIn(300, function() {
self.popup('This is all about me!');
});
},
popup: function(msg) {
alert(msg);
}
}
};
$(function() {
switch($('body').attr('class')) {
case 'home':
site.home.init();
break;
case 'about':
site.about.init();
break;
default:
site.error.init(); //or just home etc. depends on the site
}
});
I ususally have an init() function that goes something like this:
function init() {
if($('#someElement').length>1) {
runSomeInitFunction()
}
... more of the same for other elements ...
}
Basically just check to see if the element exists on the page, if it does, run its own initialization function, if not, skip it.
The whole JS codes is cached by the browser after the first page load anyway, so there's no point in fragmenting your JS file down into page-specific pieces. That just makes it a maintenance nightmare.
You could use for each page object literals to get different scopes.
var home = {
other: function() {
},
init: function() {
}
};
var about = {
sendButton: function(e) {
},
other: function() {
},
init: function() {
}
}
var pagesToLoad = [home, about];
pagesToLoad.foreach(function(page) {
page.init();
});
After getting a new page with $.get none of the javascript will run on the new page.
Is there a way to make javascript use the new page too?
Many thanks
Dorjan
Edit: Example:
$(function() {
$('.viewPage').click(function() {
$('#mainarticle').fadeOut('slow')
$.get($(this).attr('href'), { js: "1" }, function(data) {
$('#mainarticle').html(data).fadeIn('slow');
});
return false;
});
});
Now this works fine however, the new page's anchor tags won't trigger (lets say it has a .viewPage).
I hope that clarify's the issue.
You need to bind events to your anchors using live:
$('a.something').live("click",function() {
alert('this will still work after a.something has been replaced via ajax');
});
Another way using $.get's callback:
$.get( "page.html", function(data) {
$('#someDiv').html(data);
$('a.something').click(function() {
alert('this will still work after a.something has been replaced via ajax');
});
});
Now that I've seen your code:
$(function() {
$('.viewPage').live("click",(function() {
$('#mainarticle').fadeOut('slow')
$.get($(this).attr('href'), { js: "1" }, function(data) {
$('#mainarticle').html(data).fadeIn('slow');
});
return false;
});
});
Yep; there is another jquery ajax method that will take the returned script from your page and execute it. Check the jquery docs.