![]() |
![]() |
![]() |
|
FAQ 0006Michael W. Moore deals with a number of issues related to client-side scripting in .aspx pages:
Part 1 Client click code may not be necessary Custom validators are very flexible Different validation for different buttons Assign a new function to the event Part 3 Controlling the sequence of events There are several little known functions which may meet your needs better than adding a client click event. Plus, there are several methods to add code to the click event. I'm leaning towards attachEvent as my favorite. This may not be the final word on this subject, but below is my opinion. Responses and critiques are welcome in news://msnews.microsoft.com/microsoft.public.dotnet.framework.aspnet. Part 1 Client click code may not be necessaryA client-click event may not be necessary. Here are some methods which may make it unneeded. Disable individual validatorsSuppose you only want to require text in a text box if a check box is checked. Start with a RequiredFieldValidator that is enabled. In your client onload event, disable it and set the check box to UNchecked. Then add code to the check box's onchange event to enable/disable the RequiredFieldValidator. Call ValidatorEnable and pass it the validator object [document.all("NameOfValidator")], and true or false. ValidatorEnable(validator, boolean) Custom validators are very flexibleIf you leave a custom validator's "ControlToValidate" blank, then it will always run with every form submission. Currently, it will NOT run if it's set to a blank text box. If not set to any control, then it always runs. Add whatever code you want (both client and server code) to have it test anything in the document. Different validation for different buttonsSuppose you have two (or more) sections in your form. Before ASP.NET, you could put each in its own form and submit them separately. Now, we only have one form. You can still control validation so that it skips the controls in the other sections. There are several ways to do this. One is to have only one section active at a time. You could add buttons which allow the user to enable the section they want to submit. This button would be a HTML button which does NOT post the form. It would just call client code to enable & disable the various controls and validators -- ValidatorEnable(validator, boolean). Another, very similar, way to do this is to have two buttons, in each section, to submit the section. One would be named "Validate" and the other "Submit". "Submit" would be disabled until the Validate button is clicked & validation passes correctly. The Validate button would be an HTML button that runs client code. It would first call Page_ClientValidate and then enable the Submit button if Page_IsValid is true. Another way is to use an HTML button to fire a client function. In this function, call Page_ClientValidate and then, if Page_IsValid = true, call Form1.submit(), or __doPostBack(...). Note that you will need to add SERVER code to execute server-side validation -- Page.Validate(). Another way is via pre-submission processing. In the OnSubmit() function, use event.srcElement to determine which button was clicked (for Navigator it's event.target, though client validation is normally off for Navigator). [As shown below, you can also do this in the Submit() function.] Pre-submission processingSome objects, such as web server buttons, actually end up on the client browser as "submit" buttons. These controls will run validation, then call OnSubmit(), and then post to the server. Other objects, such as links, render to the client browser as calls to __doPostBack(...). These call Submit() and then post to the server. All HTML objects which post a form either execute the onsubmit() function or the submit() function. Therefore, adding your own code to one or both of these allows you to add your own code to the submission process. You can easily add your own code to the onsubmit function. Using RegisterOnSubmitStatement in server code is the recommended method. If you know that the click event you need is one that triggers OnSubmit(), then adding code to OnSubmit() could be solution for you. The submit() function is harder. The submit() function is compiled binary code rather than a string. The method described below, "Assign a new function to the event", is probably the only way to "add" your own code to this function. However, the "assign new function" method can make it harder for programmers to read or understand the page later. Also, if there are multiple overrides of the function, then it would be even harder to understand. Plus, if multiple overrides use the same variables, then the second use of the same variable will erase its previous contents and that will cause your page to never submit. Part 2 The client click eventattachEventThis method allows you to add one (or more) client function calls to your event. The button's standard click event will run first (so validation will run first). Then your added functions will run. If you attach multiple functions, they may run in any order. Thanks to Mark O'Sullivan for finding this method.
attachEvent documentationhttp://msdn.microsoft.com/workshop/author/dhtml/reference/methods/attachevent.asp One ambiguous note - the documentation says that detachEvent must also be called. However, only the *.HTC sample uses detachEvent. The HTML sample does not use it. To use this method The following is JavaScript. For VBScript, use GetRef("btn_onclick"). <PUBLIC:ATTACH ONEVENT="cleanup()" EVENT="ondetach" /> <script language="javascript"> function btn_onclick() { return confirm('Do this?'); } function cleanup() { document.all("Button1").detachEvent("onclick", btn_onclick); } function window_onload() { document.all("Button1").attachEvent("onclick", btn_onclick); } </script> Event specific script blockThis solution is nearly identical to the "CausesValidation=false" method, except:
This is normal. If you put an ordinary HTML button on a form and add both an onclick attribute inside the tag plus an onclick event script bock, then the script block will fire and the attribute will not fire. This is why I put this as the second solution. With this solution (with CausesValidation=True), it is confusing if you use View Source in your browser. You will see TWO onclick events. One inside the button tag, calling validation code. And, another in a separate event script block. It can lead to confusion to see both of these while only the script block code gets executed. Downside:
<script for="Button1" event="onclick" > if (typeof(Page_ClientValidate) == 'function') { Page_ClientValidate(); event.returnValue = Page_IsValid; } else { event.returnValue = true; } </script> Single custom validatorIf you only have one validation control, and it's a custom validator, then you can use its client validation function as your click event in addition to using it to validate your page. If you use more than one validator, then it may be difficult to control the sequence in which each validator is executed. Leave the custom validator's "ControlToValidate" property blank, then it always runs. Also, see below for: "Validate differently depending on which submit button was clicked" Modify the existing functionIn JavaScript, a function is essentially a string. You can use string functions to manipulate the contents of the function. First find the first curly brace and strip it off, along with everything before it. Then strip off the closing curly brace. Now you have just the code. You can add more code to the beginning or end of this string. If you add to the beginning, be sure to end your additional code with a semi-colon and a space. If you add to the end, then you need to do some extra work. Since many people do not add semi-colons at the end of their lines of code, you need to calculate, in your code, whether you need to add a semi-colon prior to your additional code. Note: Though there is nothing inherently wrong with this method, you are modifying the code inside another function. This could lead to unexpected results, especially if multiple client scripts are each modifying the same function. The validation controls already use this method on the onclick/onchange events of controls that are being validated. Also, some third party controls use this method. Caution is suggested. Here is a sample of this method. This sample is from WebUIValidation.js version 1_0_3705_0. var ev; if (control.type == "radio") { ev = control.onclick; } else { ev = control.onchange; } if (typeof(ev) == "function" ) { ev = ev.toString(); ev = ev.substring(ev.indexOf("{") + 1, ev.lastIndexOf("}")); } else { ev = ""; } var func = new Function("ValidatorOnChange(); " + ev); if (control.type == "radio") { control.onclick = func; } else { control.onchange = func; } CausesValidation = FalseWith this method, validation does not execute on its own. Your code has complete control over calling validation. Compatibility: ASP.NET client validation is functional with IE4 or greater. attachEvent only works with IE5 or later. This method allows you to customize server validation as well as client. Just add your custom validation code to the server code. Then you can duplicate the custom logic on both the client and the server. Problem: Though this method treats client & server equally (validation is turned off in both), the original problem was only a client-side problem. Turning off server validation is probably not wanted, though you can add server code to call Page.Validate(). If you do add a server-side call to Page.Validate(), you will most closely align your usage of it to the original if you add it as the first line of code in the server click event for the button that the end user clicked. Another option is to add it to the server-side page_load event. To use this method Set the button's CausesValidation property to false. Add this to code-behind page_load Button1.Attributes.Add("language", "javascript") Button1.Attributes.Add("OnClick", "Button1_onclick();") Add client code for the button, such as the following function Button1_onclick() { Var MyResult; //Your code here, before validation if (typeof(Page_ClientValidate) == 'function') { Page_ClientValidate(); MyResult = Page_IsValid; } else { MyResult = true; } //More of your code here, after validation return MyResult; } HTML buttonReplace the web server button control with an HTML button with the following added: Add: id="..." name="..." onclick="…();" runat=server Add: an event in the code-behind for this button's ServerClick event (otherwise it won't submit the form). This server-side procedure may be empty. Add: a client event for the control & add a call to validation within that procedure. The function should return true or false to allow or stop form submission. This control does not have a CausesValidation property. Therefore, its client-side click event should behave just like one would expect from an HTML button. Downside: It's not a web server control. It won't benefit from future enhancements such as newer or other controls adding functionality to buttons. Problem: Though this method treats client & server equally (validation is turned off in both), the original problem was only a client-side problem. Turning off server validation is probably not wanted, though you can add server code to call Page.Validate(). If you do add a server-side call to Page.Validate(), you will most closely align your usage of it to the original if you add it as the first line of code in the server click event for the button that the end user clicked. Another option is to add it to the server-side page_load event. To use this method function Button1_onclick() { if (typeof(Page_ClientValidate) == 'function') { Page_ClientValidate(); return Page_IsValid; } else { return true; } } Assign a new function to the eventThe idea here is to use a page level variable and code in the page_onload event to supercede the button's onclick procedure with a new procedure of your own. Within your own procedure, you also use the page level variable to call the original procedure. Thus, both your code and the original code get executed. Caution: This results in code that jumps around so much that it may not be feasible to maintain. It's even harder to follow than the old GoTo statement. This problem makes this method impractical to use. Caution: If there are multiple overrides of the function, then it would be even harder to understand. Plus, if multiple overrides use the same variables, then the second use of the same variable will erase its previous contents and that will cause the code from the original procedure to be lost. The following example shows overriding the submit() function. The method is the same for any function. var OldSubmit; function NewSubmit() { alert("test"); OldSubmit(); } function window_onload() { OldSubmit = Form1.submit; Form1.submit = NewSubmit; } Part 3 Controlling the sequence of eventsCurrently, there are two things that make you think you don't have control:
You can regain control of these as follows. Validator sequenceEven if the validation has already run before your client function runs (such as your click event code), you can still run validation again. In your code, you can run the validators in any sequence you wish. You can hard code the names of the validators or use the array (Page_Validators). Perhaps there's a validated field that you might be able to "fix" via code. You can run that validator, if false, run your code to attempt to fix the error, and then run it again. You can also disable unwanted validators via ValidatorEnable(validator, boolean). You can override a control's results by setting that control's isvalid (lower case) property to true/false. You can also set the page variable Page_IsValid to true/false. If you rerun any validators, or otherwise change the isvalid results of one or more validators, then you need to update the page variable Page_IsValid. You can do this by calling ValidatorUpdateIsValid(). It loops through the array of validators and updates Page_IsValid. attachEvent sequenceDon't use attachEvent more than once per event. If you want to add more to an event, use attachEvent once and then do something to add more code to the one function you already added to the event. Perhaps you might add logic to the one event so it decides which other functions to call. Perhaps you add additional functions to an array and then have the one function call all the functions in the array. Another option is to build a string containing all the code that you want to run. While assembling the string, add the code in the desired sequence. Finally, turn that code into a function with the JavaScript Function command. Then you can add it with attachEvent. Techniques like these allow you to write code which will execute in the sequence you want. Array of functions: //Add the function to the array //No parentheses after MyFunction MyFunction = Button1_onclick; arr(1) = MyFunction; //Run the function MyFunction = arr(1); MyFunction(); Part 4 ReferencesGeneral Validation InfoUser Input Validation in ASP.NET http://msdn.microsoft.com/library/en-us/dnaspp/html/pdc_userinput.asp Q316662 HOW TO: Use ASP.NET Validation Controls from Visual Studio .NET http://support.microsoft.com/support/kb/articles/q316/6/62.asp Server Control Form Validation http://samples.gotdotnet.com/quickstart/aspplus/doc/webvalidation.aspx QuickStart tutorial http://msdn.microsoft.com/library/en-us/cpqstart/html/cpsmpnetsamples-aspnetservercontrolformvalidation.asp In - Depth* ASP.NET Validation in Depth (includes how to selectively enable/disable validators on the server or on the client) http://msdn.microsoft.com/library/en-us/dnaspp/html/aspplusvalid.asp More ReferencesValidation with Navigator and Opera http://msdn.microsoft.com/library/en-us/cpguide/html/cpconvalidatorcontrolsamples.asp attachEvent http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/attachevent.asp Regular expressions http://www.effectiveperl.com/EP.04.pdf http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=sarMgCxQCHA.2348%40cpmsftngxa06 http://groups.google.com/groups?selm=E9Is4t.Arr.0.sheppard%40torfree.net&oe=UTF-8&output=gplain http://www.perldoc.com/perl5.6/pod/perlfaq6.html Validating blank fields and interrelated fields http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=6JgO0CQPCHA.2372%40cpmsftngxa07 Validate differently depending on which submit button was clicked [My reference for this is out-of-date. So, here's the info.] 1) You need some client code to execute. You can use this article to add a click event, or you can add a custom validation control (with its ControlToValidate left blank). 2) If your client code is via adding an onclick event, then you know which button was clicked. If your client code is via a custom validator, then use event.srcElement.name or document.all(event.srcElement).name. For Navigator clients, my documentation says to use "target" instead of "srcElement". Use one custom validation control for a VERY large number of controls (client-side sample code only) http://groups.google.com/groups?safe=images&ie=UTF-8&oe=UTF-8&as_umsgid=jr1JgvhVCHA.2960@cpmsftngxa10&lr=&hl=en 4) Enable & Disable Individual Validators I'm repeating this since it gets asked so much. You can enable/disable individual validation controls in either CLIENT code or in SERVER code. http://msdn.microsoft.com/library/en-us/dnaspp/html/aspplusvalid.asp Sample code extracted from the above link: Client: function OnChangeSameAs() { var enableShip = !event.srcElement.status; ValidatorEnable(rfvalShipAddress, enableShip); } Server: public override void Validate() { // Only check ship address if not same as billing bool enableShip = !chkSameAs.Checked; rfvalShipAddress.Enabled = enableShip; // Now perform validation base.Validate(); } This posting is provided "AS IS", with no warranties, and confers no rights. |
|||