Reputation: 89
I am new to JavaScript and I am having trouble understanding the scope of variables in some script that I have pieced together from examples I have found. The code below is part of a tutorial that Matt Berseth put out on his website. The application has an ajaxToolKit:ModalPopupExtender with JavaScript functions to execute when the Yes or No buttons are clicked. The two variables that are supposed to hold the delete button location and a div do not seem to get populated and thus the code exceptions. When I click on the Yes or No button both the _Source and _popup variables are undefined.
I would really appreciate the time taken to provide an explanation as to what I have setup wrong in my code.
The button that is fires the OnClientClick event calling the SubmitPayment function
<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClientClick="return SubmitPayment(this); return false;" UseSubmitBehavior="False" AccessKey="S" ValidationGroup="Manual" />
A hidden field to save a value in (tested later in the javascript)
<div id="divHiddenFields">
<asp:HiddenField ID="hfTotalAmtDue" runat="server" />
</div>
The Dialog Panel
<div id="divConfirmPaymentDialog">
//panel that makes up confirmation dialog
<asp:Panel ID="pnlConfirmPaymentDialog" runat="server" style="display:none" CssClass="modalPopup" Height="200" Width="450">
<div align="center">
<p class="info">You are attempting to make a payment when your account(s) has/have no balance!</p>
<p class="info">If you do this you will have a credit applied to your account in the amount of your payment.</p>
<p class="info">Are you sure that you want to do this?</p>
<asp:Button ID="btnConfirmPaymentYes" runat="server" Text="Yes" Width="75" />
<asp:Button ID="btnConfirmPaymentNo" runat="server" Text="No" Width="75" />
</div>
</asp:Panel>
//modal dialog extender that implements showing the modal dialog with panel
<cc1:ModalPopupExtender ID="mpeConfirmPayment" runat="server" BehaviorID="mpeConfirmPaymentBehaviorID" BackgroundCssClass="modalBackground"
CancelControlID="btnConfirmPaymentNo" OnCancelScript="btnConfirmPaymentNo_Click();" OkControlID="btnConfirmPaymentYes" OnOkScript="btnConfirmPaymentYes_Click();"
PopupControlID="pnlConfirmPaymentDialog" TargetControlID="pnlConfirmPaymentDialog" />
</div>
The Javascript
<script type="text/javascript">
//this system function sets the App_init handler function as the initialization handler
Sys.Application.add_init(App_Init);
//this function handles the hookup of the beginrequest and endrequest ="divhandlers. The two functions are called
//at the begin and end of the webpage lifecycle
function App_Init()
{
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequest);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequest);
}
//this function handles the begining of the webpage lifecylce
function BeginRequest(sender, args){
$(document).ready(function(){
//if btnYes was clicked then block the UI
$('#<%= btnYes.ClientID %>').live('click', function(e){
//e.preventDefault();
$.blockUI();
});
});
}
//this function handles the end of the webpage lifecylce
function EndRequest(sender, args) {
//call unblockUI
$(document).ready(function() {
$('#<%= btnYes.ClientID %>').live('click', function(e) {
$.unblockUI();
});
});
//check for errors that occurred during page execution
if (args.get_error() != undefined) {
var errorMessage;
if (args.get_response().get_statusCode() == '200') {
errorMessage = args.get_error().message;
}
else {
// Error occurred somewhere other than the server page.
errorMessage = 'An unspecified error occurred. ';
}
args.set_errorHandled(true);
if (errorMessage.indexOf('ValidationError:') > 0) {
alert(errorMessage.replace('Sys.WebForms.PageRequestManager', '').replace('ServerErrorException:', ''));
}
}
}
//this funcion will raise the viewccreceipt dialog when called
function OpenReceipt() {
window.open('ViewCCReceipt.aspx', 'Name', 'height=600,width=800');
}
// keeps track of the delete button for the row
// that is going to be removed
var _source;
// keep track of the popup div
var _popup;
//This function will be called when the submit button on the creditcard entry screen is pressed.
//The function will check to see if the balance is already zero and message the customer that they will have a
//credit balance if they continue and allow the to confirm the payment.
function SubmitPayment(source) {
$(document).ready(function() {
//Get the Total Amount Due from hidden field hfTotalAmountDue
var TotalAmtDue = $('#<%= hfTotalAmtDue.ClientID %>').val();
if (TotalAmtDue <= 0) {
this._source = source;
this._popup = $find('mpeConfirmPaymentBehaviorID');
// find the confirm ModalPopup and show it
this._popup.show();
}
});
}
//event handler for the btnConfirmPaymentYes button
//when this handler is executed the modal popup is hidden and a postback is done
function btnConfirmPaymentYes_Click(){
// find the confirm ModalPopup and hide it
this._popup.hide();
// use the cached button as the postback source
__doPostBack(this._source.name, '');
}
//event handler for the btnConfirmPaymentNo button
//when this handler is executed the modal popup is hidden and the postback permanently shut down
function btnConfirmPaymentNo_Click(){
// find the confirm ModalPopup and hide it
this._popup.hide();
// clear the event source
this._source = null;
this._popup = null;
}
</script>
Upvotes: 1
Views: 394
Reputation: 20215
Scope is a tricky thing, and here are the basics.
The only scope is function scope. Variables declared in a function stay in the function. Variables declared outside of a function are in global scope. Global variables are to be avoided though, as they're bad style.
Functions are objects that don't have a home. You can only depend on the value of this
in two circumstances:
functionname.call(context, params)
, where context is the value of this
this
will be the object it's a part of
If a function is called in this way: functionname(params)
, then this
will be whatever this was in the calling scope. It's kind of weird though, so if you're going to use this, be sure you know what it is.
You should assume that this
will never refer to the global scope, and you should never use this
in the global scope.
I would use some kind of packager to avoid using the global scope. I use ender.js, and it's nice because the default packages are pretty similar to jQuery, so there's a small learning curve.
Douglas Crockford is the man at explaining JavaScript:
http://javascript.crockford.com/
Upvotes: 1
Reputation: 120496
this._source
is different from var _source
in JavaScript.
Instead of doing
this._source = source;
this._popup = $find('mpeConfirmPaymentBehaviorID');
maybe you should do
_source = source;
_popup = $find('mpeConfirmPaymentBehaviorID');
which will assign it (on document load) to variables declared in a scope that contains the event handler function definitions: btnConfirmPayment{No,Yes}_Click
.
A lot of the time the two are equivalent since this
refers to the global scope by default, and your var
declaration is in the global scope, but on load event handlers are probably run with this
being some DOM node.
Upvotes: 2