I have a JavaScript file here http://www.problemio.com/js/problemio.js and I am trying to place some jQuery code into it that looks like this:
$(document).ready(function()
{
queue = new Object;
queue.login = false;
var $dialog = $('#loginpopup')
.dialog({
autoOpen: false,
title: 'Login Dialog'
});
var $problemId = $('#theProblemId', '#loginpopup');
$("#newprofile").click(function ()
{
$("#login_div").hide();
$("#newprofileform").show();
});
// Called right away after someone clicks on the vote up link
$('.vote_up').click(function()
{
var problem_id = $(this).attr("data-problem_id");
queue.voteUp = $(this).attr('problem_id');
voteUp(problem_id);
//Return false to prevent page navigation
return false;
});
var voteUp = function(problem_id)
{
alert ("In vote up function, problem_id: " + problem_id );
queue.voteUp = problem_id;
var dataString = 'problem_id=' + problem_id + '&vote=+';
if ( queue.login = false)
{
// Call the ajax to try to log in...or the dialog box to log in. requireLogin()
}
else
{
// The person is actually logged in so lets have him vote
$.ajax({
type: "POST",
url: "/problems/vote.php",
dataType: "json",
data: dataString,
success: function(data)
{
alert ("vote success, data: " + data);
// Try to update the vote count on the page
//$('p').each(function()
//{
//on each paragraph in the page:
// $(this).find('span').each()
// {
//find each span within the paragraph being iterated over
// }
//}
},
error : function(data)
{
alert ("vote error");
errorMessage = data.responseText;
if ( errorMessage == "not_logged_in" )
{
//set the current problem id to the one within the dialog
$problemId.val(problem_id);
// Try to create the popup that asks user to log in.
$dialog.dialog('open');
alert ("after dialog was open");
// prevent the default action, e.g., following a link
return false;
}
else
{
alert ("not");
}
} // End of error case
}
}); // Closing AJAX call.
};
$('.vote_down').click(function()
{
alert("down");
problem_id = $(this).attr("data-problem_id");
var dataString = 'problem_id='+ problem_id + '&vote=-';
//Return false to prevent page navigation
return false;
});
$('#loginButton', '#loginpopup').click(function()
{
alert("in login button fnction");
$.ajax({
url:'url to do the login',
success:function() {
//now call cote up
voteUp($problemId.val());
}
});
});
});
</script>
There are two reasons why I am trying to do that:
1) I am guessing this is just good practice (hopefully it will be easier to keep track of my global variables, etc.
2) More importantly, I am trying to call the voteUp(someId) function in the original code from the problemio.js file, and I am getting an error that it is an undefined function, so I figured I'd have better luck calling that function if it was in a global scope. Am I correct in my approach?
So can I just copy/paste the code I placed into this question into the problemio.js file, or do I have to remove certain parts of it like the opening/closing tags? What about the document.ready() function? Should I just have one of those in the global file? Or should I have multiple of them and that won't hurt?
Thanks!!
1) I am guessing this is just good practice (hopefully it will be
easier to keep track of my global variables, etc.
Yes and no, you now have your 'global' variables in one spot but the chances that you're going to collide with 'Global' variables (ie those defined by the browser) have increased 100% :)
For example say you decided to have a variable called location, as soon as you give that variable a value the browser decides to fly off to another URL because location is a reserved word for redirecting.
The solution to this is to use namespacing, as described here
2) More importantly, I am trying to call the voteUp(someId) function
in the original code from the problemio.js file, and I am getting an
error that it is an undefined function, so I figured I'd have better
luck calling that function if it was in a global scope. Am I correct
in my approach?
Here's an example using namespacing that will call the voteUp function:
(function($) {
var myApp = {};
$('.vote_up').click(function(e) {
e.preventDefault();
myApp.voteUp();
});
myApp.voteUp = function() {
console.log("vote!");
}
})(jQuery);
What about the document.ready() function? Should I just have one of
those in the global file? Or should I have multiple of them and that
won't hurt?
You can have as many document.ready listeners as you need, you are not overriding document.ready you are listening for that event to fire and then defining what will happen. You could even have them in separate javascript files.
Be sure your page is finding the jquery file BEFORE this file is included in the page. If jquery is not there first you will get function not defined. Otherwise, you might have other things conflicting with your jquery, I would look into jquery noConflict.
var j = jQuery.noConflict();
as seen here:
http://api.jquery.com/jQuery.noConflict/
Happy haxin
_wryteowl
Extending what KreeK has already provided: there's no need to define your "myApp" within the document ready function. Without testing, I don't know off the top of my head if doing so is a potential source for scope issues. However, I CAN say that the pattern below will not have scope problems. If this doesn't work, the undefined is possibly a script-loading issue (loading in the right order, for example) rather than scope.
var myApp = myApp || {}; // just adds extra insurance, making sure "myApp" isn't taken
myApp.voteUp = function() {
console.log("vote!");
}
$(function() { // or whatever syntax you prefer for document ready
$('.vote_up').click(function(e) {
e.preventDefault();
myApp.voteUp();
});
});
Related
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.
A very interesting problem I am facing these days is regarding one of my JavaScript function. My JavaScript function with some specific name is not working but if I change its name to anything else then it is working. Have a look -
// function to retain the jquery ui css for toolbar
function retain_css() {
alert('hi');
$( "#new_sort_options" ).buttonset();
}
// new sort
$(document).on("click", ".new_sort_button", function() {
var order = $(this).val();
var make_id = $('#new_make_id').val();
$.ajax({
beforeSend : start_loader(),
type : 'POST',
url : '/ajax/new-sort.php',
data : 'order='+order+'&make_id='+make_id,
dataType : 'json',
success : function(data) {
$("#new_results_toolbar").html(data.toolbar);
$("#new_results").html(data.models);
retain_css();
end_loader();
}
});
});
But retain_css() is not working at all. Even alert() is not firing. But if i change its name to anything such as my_fun() then the code works. I don't understand why it is happening so? Any idea? Don't worry about end_loader() function as it has nothing to deal with my problem. I also changed the order of code when retain_css() was being used but didn't work.
Try not to create global functions because it may collide with other frameworks or libraries.
//define private namespace
window.user3779493Functions = {};
//define method
user3779493Functions.retain_css = function() { ... }
//call method
user3779493Functions.retain_css();
Some functions are already programmed like 'alert('hi');', that is a function called alert:
function alert() {
/* do something */
}
That function also doesn't work.
I'm trying to call a function and not the alert and I thought it was as easy as just doing something like this: FunctionsName(); and delete the alert(''); but it's not working for me :(
Can someone please look at the code I have below and tell me what is wrong ?
Thank you so much!!
<script type="text/javascript">
var comper;
function checkComper() {
var onResponse = function(comperNow) {
if (comper === undefined) {
comper = comperNow;
return;
}
if (comper !== comperNow) {
// show a message to the visitor
alert("New Info Added"); // <--*** I WANT TO TAKE THIS OUT AND CALL $("#append").click(function(e)
comper = comperNow;
}
};
$.get('getlastupdate.php', onResponse);
}
var tid = setInterval(checkComper, 2000);
$(function() {
var $table = $("table.tablesorter");
$("#append").click(function(e) {
e.preventDefault();
$.get('updatetable.php', function(data)
{
$table
.find('tbody')
.html('')
.append(data);
$table.trigger("update", [true]);
});
});
/*........ and so on.... */
</script>
What about changin that :
alert("New Info Added");
to that :
$('#append').trigger('click');
It will simulate a click and trigger the function.
One thing important to distinguish:
alert("New Info Added") is a function. Actually, alert() is a function, being passed the parameter "New Info Added".
$('#append').click(function(e) { is not a function, at least, not in the same way. $('#append') is a jQuery selector function, which selects all elements with an id of "append". $('#append').click() is a function that sets a click event on all elements returned in the selector.
What the whole syntax of $('#append').click(function(e) { means is on its own a syntax error. What you're doing is telling the elements found in the selector what their click function should be. But the function(e) { says that it's the start of the code of the function. That line of code isn't complete until the ending }) - the } closing the function declaration and the ) closing the call to click.
So, you can't simply replace alert("New Info Added"), which is a complete function call, with $('#append').click(function(e) {, because it's a syntax error - you haven't completed the function(e) declaration, nor the click function call. You can trigger the click function, as Karl's answer told you. Or, you can use the shortcut:
$('#append').click()
Note that this is a full proper sentence, and can therefore replace the alert.
I am using the cakephp framework and I created 2 separate javascript files and placed them into my webroot/js folder. The first javascript file contains modal dialog variables that contain the settings for the dialog boxes. The second javascript file contains other click event handlers that post data to an action and then open up the dialog.
The problem I am having is that the second file calls a variable from the first file using
$variablename and I get an error saying varaibleName is not defined.
Some code is below to show you what I mean.
From the first file:
var $editSel = $("#editSel_dialog").dialog(
{
autoOpen: false,
height: 530,
width: 800,
resizable: true,
modal: true,
buttons:
{
"Cancel": function()
{
$(this).dialog("close");
}
}
});
From the second file:
$('.neweditSel_dialog').live('click', function()
{
$.ajaxSetup({ async: false });
var selected = [];
$("#[id*=LocalClocks]").each(function()
{
if(false != $(this).is(':checked'))
{
var string = $(this).attr('id').replace('LocalClocks', '');
string = string.substring(10);
selected.push(string);
}
});
if(0 === selected.length)
{
$selError.dialog('open');
$selError.text('No Local Clocks Were Selected')
}
else
{
$.post('/LocalClocks/editSelected', { "data[Session][selected]": selected }, function(data)
{
});
$editSel.load($(this).attr('href'), function ()
{
$editSel.dialog('open');
});
}
return false;
});
This was working when I was using jquery-1.4.2.min.js, but I am using jquery1.7 now.
I also ended up putting the first file with all the variables inside of $(document).ready(function(){}); I tried putting the second file inside of a document.ready() function but that made no difference.
Any help would be great.
Thanks
You are dealing with an issue in scope. In javascript:
function foo() {
var greet = "hi";
}
function bar() {
console.log(greet); // will throw error
}
However:
var greet;
function foo() {
greet = "hi";
}
function bar() {
console.log(greet); // will log "hi"
}
You must define your variable in a common parent of both functions that need to access it. Unfortunately, since you do not use any modeling convention or framework, that is the window object (why are global variables bad?).
So, you must define var $whateveryouneed before and outside of both $(document).readys.
Also, keep the declaration and definition seperate. Your definition instantiates a jQuery object, so you must encapsulate it inside a $(document).ready() (use $(function() {}) instead):
var $editSel;
$(function () {
$editSel = $("#editSel_dialog").dialog(
{
autoOpen: false,
height: 530,
width: 800,
resizable: true,
modal: true,
buttons:
{
"Cancel": function()
{
$(this).dialog("close");
}
}
});
});
I don't think you can guarantee the order in which handlers will be fired, which means that the document ready may be fired in different order than you expect. Is the variable you are trying to access in the second file a global variable? Try to think about your variables scope as I would have thought this is the issue.
You cannot guarantee that one file will be loaded before the other. And you cannot guarantee that document.ready in one file will fire before the other.
Therefore, I suggest you wrap your code in functions and call them in a single document.ready handler in the order you need.
For example:
function initVariables(){
window.$editSel = ... // your code from the first file here
}
function initHandlers(){
// your code from the second file here
}
And then:
$(document).ready(function() {
initVariables();
initHandlers();
});
You'll notice that I used the global window object to expose your variable. It would be even better if you used a common namespace for them.
So i have all these links in html like this
Gen Invoice
Gen Invoice
Gen Invoice
then i wrote some javascript which binds to the click event
and i want it to submit an ajax request, and replace the anchor with the returned text.
but if i have clicked on multiple links so that several are running asychronously, then it doesn't update all the anchors with the returned text, only the last anchor i clicked on.
i am guessing that the anchor variable is being overwritten each time it is run, how would i structure my code so that each time the click event is triggered, it updates the correct anchor on completion?
here is the javascript
<script type="text/javascript">
$(document).ready(function() {
// bind geninvoice function to all invlink's
$('.invlink').bind('click', geninvoice);
});
function geninvoice() {
// stop double clicks
anchor = $(this);
anchor.unbind('click');
competition_id = $(this).attr('competition_id');
$.ajax({
type: "POST",
url: "<?php echo url::site('manage/ajax/geninvoice'); ?>/"+competition_id,
dataType: "json",
beforeSend: function() {
anchor.addClass("loading");
},
success: function(response, textStatus) {
anchor.replaceWith(response.invoice_number);
},
error: function(response) {
alert("Unknown Error Occurred");
anchor.bind('click', geninvoice); // rebind if error occurs
},
complete: function() {
anchor.removeClass("loading");
}
});
}
</script>
Yeah, the problem is that your anchor variable as it is written being 'hoisted' to a global scope. See this jsfiddle for a simplified example.
You can fix this, by putting a var in front of the variable, so its scope will be limited to the function:
function geninvoice() {
// stop double clicks
var anchor = $(this); //<-- put a var here
You can see the fix at this updated version of the above fiddle
Note, this will only help you for scoping within functions. The x variable in the following example will be hoisted to the top of the global scope even though it has been declared with a var:
var a = 1;
var b = 1;
if (a === b){
var x = 0;
}
alert(x); //alerts '0'
the advantages of scoping within functions is on of the reasons we often see the following convention around jQuery plugins:
(function($){
//plugin code
//all variables local to the invoked anonymous function
})(jQuery);
See at this JSFiddle