Lazy Developer : Extender Project News Feed 
Friday, February 02, 2007  |  From Lazy Developer : Extender Project

Welcome again in the topic. Some time ago we went through a course which gave us fully functional extender. Just to remember, the course has the four parts:

  • Introduction – what Atlas Extender is and how to create our own validation extender,
  • Page methods – how to add AJAX server-side validation,
  • Migration – from Atlas to ASP.NET 2.0 AJAX,
  • Integration with the page – how to integrate extender with the ASP.NET page to perform full form validation.

Today I've decided that this project has to be resurrected and should grow up. In the first shot I've change all project structure, name and redesign everything. The Validator Extender becomes now part of AJAX control toolbox I would like to build. It has been also updated to work with the 1.0 release of the ASP.NET AJAX. However, if you have an idea or want to join and add your controls to the library I will be more than glad to see you.

I named the project ASP.NET AJAX Control Set and I hope I will get along this with your help and comments and there will be something worth to download.

Friday, February 02, 2007  |  From Lazy Developer : Extender Project

Welcome again in the topic. Some time ago we went through a course which gave us fully functional extender. Just to remember, the course has the four parts:

  • Introduction – what Atlas Extender is and how to create our own validation extender,
  • Page methods – how to add AJAX server-side validation,
  • Migration – from Atlas to ASP.NET 2.0 AJAX,
  • Integration with the page – how to integrate extender with the ASP.NET page to perform full form validation.

Today I've decided that this project has to be resurrected and should grow up. In the first shot I've change all project structure, name and redesign everything. The Validator Extender becomes now part of AJAX control toolbox I would like to build. It has been also updated to work with the 1.0 release of the ASP.NET AJAX. However, if you have an idea or want to join and add your controls to the library I will be more than glad to see you.

I named the project ASP.NET AJAX Control Set and I hope I will get along this with your help and comments and there will be something worth to download.

Tuesday, November 21, 2006  |  From Lazy Developer : Extender Project

Welcome again in the last part of this series. So far we made the extender with bunch of features and then we had migrated to the new ASP.NET AJAX framework. So there only one left to do in order to get fully functional extender. As a current state our course contains the following parts:

  • Introduction – what Atlas Extender is and how to create our own validation extender,
  • Page methods – how to add AJAX server-side validation,
  • Migration – from Atlas to ASP.NET 2.0 AJAX,
  • Integration with the page – how to integrate extender with the ASP.NET page to perform full form validation.

In order to make the extender usable as a part of the page, we have to put it into validation cycle of the page. What we have to do is to find a way, how to stop form before submitting till all server-side validation requests are not accomplished. Let us first look at normal validation cycle and how our extender fit into that cycle.



Simplified submit cycle is shown on figure 1. Basically, function WebForm_OnSubmit() is attached the form's onsubmit event. This function is very simple itself and returns true, which allows submit, if validation is successful. Using validation groups makes all things a bit more complicated, but everything is done in scripts that are located in resources, so we will not care about them. In the normal page when all validators perform their validation successful, page is submitted, otherwise error messages are displayed, but when we insert our extender all cycle will be broken (Figure 2).


When the extender is set up to perform the server-side validation, the validation method returns false which stops the page from being submitted. That is quite reasonable, as we have to wait for the server-side validation results. The main problem is that we can't perform submit just after the server-side validation ends successfully because there can be more than one extenders and all the server-side validation checks pending and needs to be completed before we will decide if we can allow submit or not. So the best way is to count somehow how many server-side validations started and check this counter after each one is finished (Figure 3).

In fact, there are only two changes in the code we have to do. First what we will need is to count all server-side validations. In order to do this, we will add two global variables to store the counters. Then, we have to modify slightly the extender behaviour script and add a few lines into validate() and _onMethodComplete() functions (I've removed rest of function bodies in order to make changes more visible):

<textarea name="code" class="BLOCKED SCRIPTnogutter" cols="80" rows="10">validate : function(sender, args) { //... //increase counter __AtlasValidatorExtendersInvalid ++; __AtlasValidatorExtendersInProgress ++; //... } }, _onMethodComplete : function (sender, eventArgs) { //... __AtlasValidatorExtendersInProgress--; if (sender.get_result() == "") { //decrease counter if success __AtlasValidatorExtendersInvalid--; this._setNormal(); } else { this._setError(sender.get_result()); } formSubmitMockup(); //... } }, </textarea>

 

So it's quite simple. You can see two counter variables there __AtlasValidatorExtendersInvalid and __AtlasValidatorExtendersInProgress. First one is the number of the invalid results while second one is the number of validations pending. Other world, when __AtlasValidatorExtendersInProgress equals zero then all validation calls were completed, and when __AtlasValidatorExtendersInvalid equals zero then all validation were successful. So, before we will call the server-side validation method, both counters are increased and later then, when asynchronous call is completed, counters are decreased according to the result. At the end of _onMethodComplete() you can notice I'm calling formSubmitMockup() function.

This function is a mock-up function that is used to intercept the form submit event and forces it to wait for validation results. In simple format, that function looks as follow:

<textarea name="code" class="BLOCKED SCRIPTnogutter" cols="80" rows="10"> formSubmitMockup = function() { var originalSubmit = false; if (__AtlasValidatorExtendersInProgress <= 0) { originalSubmit = WebForm_OnSubmit(); if (__AtlasValidatorExtendersInvalid > 0 || !originalSubmit) { __AtlasValidatorExtendersInProgress = 0; __AtlasValidatorExtendersInvalid = 0; return false; } else { theForm.onsubmit = null; theForm.submit(); } } else { return false; } } </textarea>

 

As you can see, there is no magic here. First we are calling an original submit function WebForm_OnSubmit() and its result is remembered for later use. Because this original function will cause validation, so all asynchronous validations will be started and our counters will be set at some value. Then counter is checked and if is greater than zero, false is returned to stop form being submitted. After each of the server-side validations is completed counters are decreased and this mock-up function is called and every time counters are checked and if both are equal zero, the form is submitted.

Actually this mock-up function and counters has to be added to the page only once, so can't be included in behaviour script. Instead if that, we will add OnPreRender() event to the extender class. Finally then, all additional code looks as follow:

<textarea name="code" class="c#:nogutter" cols="80" rows="10"> protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); if (!Page.ClientScript.IsStartupScriptRegistered("ValidatorExtender")) { string script = "var __AtlasValidatorExtendersInProgress = 0;\n" + "var __AtlasValidatorExtendersInvalid = 0;\n" + "\n" + "formSubmitMockup = function() {\n" + " var originalSubmit = false; \n" + " if (__AtlasValidatorExtendersInProgress <= 0) {\n" + " originalSubmit = WebForm_OnSubmit();\n" + " if (__AtlasValidatorExtendersInvalid > 0 || !originalSubmit) {\n" + " __AtlasValidatorExtendersInProgress = 0;\n" + " __AtlasValidatorExtendersInvalid = 0;\n" + " return false;\n" + " } else {\n" + " theForm.onsubmit = null;\n" + " theForm.submit();\n" + " }\n" + " } else {\n" + " return false;\n" + " }\n" + "}\n" + "theForm.onsubmit = formSubmitMockup;\n"; Page.ClientScript.RegisterStartupScript(this.GetType(), "ValidatorExtender", script, true); } } </textarea>

 

Well, looks as we finished that small course, hope you enjoyed it. I hope I explained what I've done and all of this is readable and understandable as well. You can download all sources and binary files from the project page I've set up yesterday on the codeplex. As my intention is to create a bit more than one validator, you can expect that this page will grow soon with new extenders. If you will have any questions or comments use blog or codeplex page as prefer.

Wednesday, November 01, 2006  |  From Lazy Developer : Extender Project

Welcome in the second and half post in the series dedicated adventures with Atlas Extenders. Originally, this series consist of three parts, but some changes in the world forces me to add one more post into the series:

  • Introduction – what Atlas Extender is and how to create our own validation extender,
  • Page methods – how to add AJAX server-side validation,
  • Migration – from Atlas to ASP.NET 2.0 AJAX,
  • Integration with page – how to integrate extender with ASP.NET page to perform full form validation.

Last time I was blogging about new release of the Atlas. Honestly, I was the very first with that news, but none noticed that. What a pity. Anyway, I promised to write a bit more about changes and because I'm working on extender it is good opportunity to see how these changes are working in real life.

First of all, as I've mention before, several fundamental changes were made in the extender structure. Instead of four source files (Behavior.js, Designer.cs, Extender.cs and Property.cs) only three left. All properties have been relocated into the base Extender class. That's mean that we can't use multiple properties for the extender anymore, as it was in previous version, but we have to add separate extenders for every control we want to extend. It is not a big deal but a little waste of screen space.

Ok, the migration. After removing old references and namespace declarations as well, and after adding new ones, we can start converting existing extender.

Firstly, in the ValidatorExtender.cs, the class declaration should be changed for inherited from the ExtenderControlBase, as generic version of this base class does not exist anymore. Then all properties from the ValidatorProperties.cs should be copied to the Extender class and each of them should be followed by the ExtenderControlProperty attribute. Old Propertises.cs can be removed from the project now. Finally, the TargetControlType attribute should be added just before the Extender class to define type of target control. This allows us to limit extender to selected control type only.

Next step is a quick change in the ValidatorDesigner.cs, where the Designer class declaration should be modified to

class ValidatorDesignerExtenderControlBaseDesigner<ValidatorExtender>

{

}

Finally, we should change the ValidatorBahavior.js file where is a lot of important changes. The new Behavior.js consists of two parts, Validator.ValidatorBehavior object and prototype Validator.ValidatorBehavior.prototype. Because our old Behavior.js consists of only one part, we have to split our code. All property declarations should stay in main object whereas rest should go into prototype.

After splitting copying and reformatting the code, we have to ensure if we are using "this." in every field declaration and everywhere we are using them later. The getDescriptor() function is no longer required so should be removed. Because object doesn't contain this.control property anymore, rename all its occurrences of from "this.control.elements" to "this.get_element()". Then, everywhere we are using $(name) it should be changed to $get(name) and finally, last two lines should be replaced as follows:

//before

Validator.ValidatorBehavior.registerSealedClass('Validator.ValidatorBehavior', Microsoft.AtlasControlExtender.BehaviorBase);

Sys.TypeDescriptor.addType('Validator'.toLowerCase() /* Safari Compat */, 'ValidatorBehavior', Validator.ValidatorBehavior);

 

//after

Validator.ValidatorBehavior.registerClass('Validator.ValidatorBehavior', AjaxControlToolkit.BehaviorBase);

After completing this boring part, we can start refactoring more important things around calling the WebMethod. In the first shot, _onMethodAborted function should be removed and then, arguments in all three functions left should be changed to (sender, eventArgs). To get user context we need now to use sender.get_userContext() and sender.get_result() in _onMethodComplete to get result.

Last thing to do is changing the way, how the WebMethod is invoked. Because this part of framework has been completely changed, we can't use Sys.Net.PageMethod.invoke() anymore. Instead of that, we have Sys.Net.ServiceMethodRequest class that will do exactly the same, so the WebMethod call will now looks as follow:

      var svr = new Sys.Net.ServiceMethodRequest();

      svr.set_methodName(this._serviceMethod);

      svr.get_parameters()["Value"] = args.Value;

      svr.get_parameters()["IsValid"] = args.IsValid;

      svr.add_completed(Function.createDelegate(this, this._onMethodComplete));

      svr.add_error(Function.createDelegate(this, this._onMethodError));

      svr.add_timeout(Function.createDelegate(this, this._onMethodTimeout));

      svr.invoke(this._currentCallID);     

Well, that class does the same but not exactly. I've found unexpected problems with calling the WebMethod. I've found somewhere (can't find it again) information that there is an issue in framework that allows to call WebMethods only when is located in script block in aspx page. Hope this will be corrected soon.

Process of the migration of the web application itself is well described in guide, provided on ASP.NET 2.0 AJAX webpage so that's all for now. After tests everything is working well and I can focus again on finishing extender, so the next, final part will be ready soon.

Tuesday, October 10, 2006  |  From Lazy Developer : Extender Project

Welcome in the second post in the series dedicated adventures with Atlas Extenders. This series consist of three parts:

  • Introduction – what Atlas Extender is and how to create our own validation extender,
  • Page methods – how to add AJAX server-side validation,
  • Integration with page – how to integrate extender with ASP.NET page to perform full form validation.

Previous part has introduced us into Atlas Extender where we have had created simple extender with client behaviour. As I mention before, we have to repeat extender declaration in aspx for each validator we want to extend. In fact, there is no problem with this, but we have to add an extra two lines for every validator, only to declare extender itself. The same way control tree grows, we have to use and remember number of id’s and so on. Nothing serious but it is not and elegant solution. In order to make it more friendly and elegant, we will modify our extender in way, which will allow us using only one extender and adding only properties for each validator:

    <cc1:ValidatorExtender ID="ValidatorExtender1" runat="server" ScriptPath="ValidatorExtenderBehavior.js" >

      <cc1:ValidatorProperties ErrorCssClass="error" TargetControlID="TestValidator" />

      <cc1:ValidatorProperties ErrorCssClass="error" TargetControlID="TestValidator2" />

    </cc1:ValidatorExtender>

This task is simpler than it looks like when I was writing the first part. We do not have to iterate through properties or do other weird and difficult task. In fact, there is nothing to do about this, just simple change declaration as shown above.

Let us then jump to the next part and see how things are going with server-side validation. As I mention in the first part, extender will not work with the CustomValidator, mainly because, by default this type of validator have no client script validation we can catch and use. Unfortunately, the CustomValidator is perfect for complex validation such as validation against a database. To keep this feature, and even make it better, we can use a Page Method, which is server-side method executed asynchronously in the background, what makes it perfect to perform server validation. So let us do some coding.

First, we need new properties in the extender: ServiceMethod where server-side method will be stored and UpdatingCssClass for class that will indicate that control is during validation. Let’s then add the following code in ValidatorProperties.cs

    /// <summary>

    /// The method name of the web service of page method to call.

    /// </summary>

    [DefaultValue("")]

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", Justification = "Assembly is not localized")]

    public string ServiceMethod

    {

      get

      {

        return GetPropertyStringValue("ServiceMethod");

      }

      set

      {

        SetPropertyStringValue("ServiceMethod", value);

      }

    }

 

    /// <summary>

    /// A CSS style to apply while the validation is in progress

    /// </summary>

    [DefaultValue("")]

    public string UpdatingCssClass

    {

      get

      {

        return GetPropertyStringValue("UpdatingCssClass");

      }

      set

      {

        SetPropertyStringValue("UpdatingCssClass", value);

      }

    }

and corresponding code in ValidatorBehavior.js

  var _updatingCssClass;  //updating css class for fields

  var _serviceMethod;  //web method with validation

 

  this.getDescriptor = function() {

    var td = Validator.ValidatorBehavior.callBaseMethod(this, 'getDescriptor');

    td.addProperty('ErrorCssClass', String); 

    td.addProperty('ServiceMethod', String);

    td.addProperty('UpdatingCssClass', String);

    td.addProperty('IsValid', Boolean);   

    return td;

  }

 

  this.get_ServiceMethod = function() {

      return _serviceMethod;

  }

  this.set_ServiceMethod = function(value) {

      if (_serviceMethod != value) {

          _serviceMethod = value;

          this.raisePropertyChanged('ServiceMethod');

      }

  } 

  this.get_UpdatingCssClass = function() {

    return _updatingCssClass;

  }

  this.set_UpdatingCssClass = function(value) {

    _updatingCssClass = value;

  }

In order to execute Page Method we will have to modify evaluationfunctionMockup function created before, but first let us look how this should work. Because executing of the Page Method can possibly be relatively long, like contacting database or making other difficult tasks, we have to do this asynchronously using Sys.Net.PageMethod.invoke() method from Atlas. This method runs selected server-side method asynchronously and assigns event handlers. Investigation of the Atlas client class library allows finding possible, however I am not entirely sure about last three parameters. I have estimated this syntax based on Sys.Net.WebMethod.invoke, which seems to be similar, but if anyone knows exact syntax, send me info please. This or another way possible syntax could be:

  Sys.Net.PageMethod.invoke = function(

    methodName,        //name of the method to execute

    params,            //parameters

    onMethodComplete,  //function to be executed when method has been completed

    onMethodTimeout,    //function to be executed on timeout

    onMethodError,      //function to be executed on error

    onMethodAborted,    //function to be executed when methos execution has been aborted

    userContext,        //user context

    timeoutInterval,    //timeout

    priority,

    useGetMethod

  )

As I mention, we have to modify evaluationfunctionMockup function to run Page Method. This modification id quite simple:

  this.evaluationfunctionMockup = function(val) {

    var value = "";

    var isValid = val.defaultEvaluationfunction(val); //call original validation function

    if (typeof(this.control.element.controltovalidate) == "string") {

        value = ValidatorGetValue(this.control.element.controltovalidate);

    }

    var controltovalidate = $(this.control.element.controltovalidate);

    //set visual style for assigned field according to validation result

    if (!isValid) {

      controltovalidate.className = _errorCssClass;

      controltovalidate.title = this.control.element.defaultErrorMessage;

    }

    else

    {

      if (_serviceMethod) {

        var args = {Value:value, IsValid:isValid};

        this.validate(val, args);

        isValid = false;

      }

      else

      {   

        controltovalidate.className = controltovalidate.defultClassName;

        controltovalidate.title = "";

      }

    }

    return isValid;  //return validation result for further processing

  }

At very beginning, default client validation is checked. I have assumed that the client side validation have priority over the server. If validator is valid, and the extender’s property ServiceMethod has been set, arguments are prepared and this.validate() function is executed. This function changes the CSS class as defined in the UpdatingCssClass property and calls the Page Method. Because, standard validator adds onChange event validation to the validated control we should disable the control to avoid executing another validation until current one will complete.

  this.validate = function(sender, args) {

    _currentCallID = ++_callID;

    if (_serviceMethod) {

      var controltovalidate = $(this.control.element.controltovalidate);

      controltovalidate.disabled = true;

      controltovalidate.className = _updatingCssClass;

      // Call the helper web service

      Sys.Net.PageMethod.invoke(

        _serviceMethod,

        { 'Value' : args.Value, 'IsValid' : args.IsValid },

        Function.createDelegate(this, this._onMethodComplete),

        Function.createDelegate(this, this._onMethodTimeout),

        Function.createDelegate(this, this._onMethodError),

        Function.createDelegate(this, this._onMethodAborted),

        _currentCallID

      );

    }       

  }

When Page Method execution will complete, _onMethodComplete() function will be called, where the validation is finalised. I’ve assume that validation is successful Page Methods returns an empty string while when validation will not succeed than validation message will be returned. The control is set back enabled, then control’s CSS class is set according to the validation result, and finally validator property isvalid is set to indicate the validation result.

  this._onMethodComplete = function (result, response, userContext) {

    if (userContext != _currentCallID)

      return;

    // Time has passed; make sure the element is still accessible

    if (this.control && this.control.element) {

      var controltovalidate = $(this.control.element.controltovalidate);

      controltovalidate.disabled = false;

      if (result == "")

      {

        this.control.element.isvalid = true;

        controltovalidate.className = controltovalidate.defultClassName;

        controltovalidate.title = "";

      }

      else

      {

        controltovalidate.className = _errorCssClass;

        controltovalidate.title = result;

        this.control.element.isvalid = false;

      }

    }

  }

Functions for other three events that could possibly happen during Page Method execution are quite basic:

  this._onMethodError = function(result, response, userContext) {

      if (userContext != _currentCallID)

        return;

      this.control.element.innerHTML = "WebService call failed: " + response.get_statusCode();       

  }

 

  this._onMethodTimeout = function(request, userContext) {

      if (userContext != _currentCallID)

        return;

      this.control.element.innerHTML = "Webservice call timed out.";

  }

 

  this._onMethodAborted = function(request, userContext) { 

      if (userContext != _currentCallID)

        return;

      this.control.element.innerHTML = "Webservice call aborted.";

  }

Therefore, we have done. In order to test, let us change declaration in the page

      <cc1:ValidatorProperties ErrorCssClass="error" TargetControlID="TestValidator" ServiceMethod="ServerSideValidation" UpdatingCssClass="updating" />

and add validation method to the page code behind.

  [System.Web.Services.WebMethod]

  public string ServerSideValidation(string value, bool isValid)

  {

    System.Threading.Thread.Sleep(2500);

    if (value != "1234")

      return "value from server should be '1234'";

    else

      return "";

  }

 

As you probably have already noticed, our extender can now validate using Page Methods, but form will not care about results of this validation. Application is rather limited do far. In the next part, I will show how to stop form from postback until all validation calls complete.

Wednesday, October 04, 2006  |  From Lazy Developer : Extender Project

I don’t actually remember when I’ve met Atlas very first time, but it was some time ago. For almost everything I was working on, UpdatePanel and a few controls from Toolkit were absolutely fine and everything worked well, so there was no need to do anything more. Then my time came. I always had problems with validators, especially with displaying messages, exclamations and other visual stuff. Whatever I’ve done, I was not satisfied with the results. All these exclamations, stars and messages has stopped me from creating a slick interface. What I’ve always wanted was just simply change the way input field displays when there is an error by changing its class or so.

The very first idea to make myself happier was to create a bunch of classes that would extend the standard validators but instead of displaying messages, it would change properties of the validated input control. Sounds easy but doesn’t solve the postback problem at all. So I’ve decided to use an Atlas extender and just extend and change the validators’ functionality. In this series, I will show you how to extend the standard ASP.NET validator with some new exciting features. If everything will be fine and the sky will not fall onto my head we will finish in four or so parts with server side validation and couple other funny things.

Let us begin with a short introduction into the Atlas extender. Extender is a class that wraps the other components to extend their functionality, very similar to the decorator pattern. After adding Atlas Control Project to the site, we will see a number of files created.

 

The extender is composed of Java Script file with all client side behaviour and three server side classes. In this part, we are about extending some client side behaviour so we will focus on two parts only, Java Script and server side Properties.

Before we will begin coding, let us look what we want to achieve. The standard validator looks … well everyone knows already how it looks like. We want to hide an error message that displayed by default, then change CSS class of the validated control assigned to and finally add the message as a tooltip.

 

Basic steps of creating extenders are described in Atlas Control Toolbox, so I will just mention the most important things here. To make the extender easier to use, we should limit it only to controls inherited from BaseValidator, so we should change part of declarations in ValidatorExtender.cs, ValidatorDesigner.cs and ValidatorProperties.cs classes similar to this:

public class ValidatorProperties : TargetControlPropertiesBase<BaseValidator>

Next step is adding the property for CSS class name that will be assigned to the validated control:

[DefaultValue("")]

public string ErrorCssClass

{

  get

  {

    return GetPropertyStringValue("ErrorCssClass");

  }

  set

  {

    SetPropertyStringValue("ErrorCssClass", value);

  }

}

Most of the work left in ValidatorBehavior.js client side script file. In normal case, this file is included into the extender and added to the page as a web resource, which is great but makes it hard to debug and test. We can avoid that by using ScriptPath attribute, which will add selected script file from the application directory. After compiling and adding extender to the test page, we should copy ValidatorBehavior.js from the extender project directory to the application and set extender as follows:

<cc1:ValidatorExtender ID="ValidatorExtender1" runat="server" ScriptPath="ValidatorBehavior.js">

  <cc1:ValidatorProperties ErrorCssClass="error" TargetControlID="TestValidator" />

</cc1:ValidatorExtender>

Now we can easily debug and test all Java Script. First, we should add functions to read and write the property we created above and variable to store its value and modify getDescriptor function to add property to the descriptor.

  var _errorCssClass;  //error css class for fields

  this.get_ErrorCssClass = function() {

    return _errorCssClass;

  }

  this.set_ErrorCssClass = function(value) {

    _errorCssClass = value;

  }

 

  this.getDescriptor = function() {

    var td = Validator.ValidatorBehavior.callBaseMethod(this, 'getDescriptor');

    td.addProperty('ErrorCssClass', String);       

    return td;

  }

In order to change behaviour of the validator we have to catch original validation function. After a few experiments we can find, that the validator has a function named evaluationfunction, generated by ASP.NET and depended on type of the validator but it always has the same parameters and returns true or false as a validation result. To catch this function we can store the original function in a separate property and change old one function to mockup that will call the original and then do what we want. Because we want to change the CSS class for the input associated with the validator to value stored in ErrorCssClass property, we have to store the original class to be able to restore it later when validation will be successful. Almost the same way we will deal with the error message. Therefore, first we have to modify initialize function as follows:

    1   this.initialize = function() {

    2     Validator.ValidatorBehavior.callBaseMethod(this, 'initialize');

    3     //store original validation function and replace it by extender mockup

    4     control.element.defaultEvaluationfunction = control.element.evaluationfunction;

    5     control.element.evaluationfunction = Function.createDelegate(this, evaluationfunctionMockup);

    6     //store original error message from the validator and clean the validator content

    7     control.element.defaultErrorMessage = control.element.innerText;

    8     control.element.innerText = "";

    9     //store original css class from the field assigned to validator

   10     var controltovalidate = $(control.element.controltovalidate);

   11     controltovalidate.defultClassName = controltovalidate.className;   

   12   }

After original initialisation, we are storing the default validation function in the separate property for later use and changing it to delegate to the mockup function described below. To get control, which the extender has been assigned to, we can use extender’s control.element property. Later then we are storing the original error message and clearing it to prevent the validator from displaying the message on his own. Finally, the same way we are storing the original CSS class from the validated control. Because the extender has been limited only to use with the validator control we can assume that there always will be correct properties. Now, when the validator will be validated, the mockup function will be executed instead of the original. There it is:

    1   this.evaluationfunctionMockup = function(val) {

    2     var isValid = val.defaultEvaluationfunction(val); //call original validation function

    3     var controltovalidate = $(this.control.element.controltovalidate);

    4     //set visual style for assigned field according to validation result

    5     if (!isValid) {

    6       controltovalidate.className = _errorCssClass;  //set error css class

    7       controltovalidate.title = val.defaultErrorMessage;  //set message as a tooltip

    8     }

    9     else

   10     {

   11       controltovalidate.className = controltovalidate.defultClassName; //restore original css class

   12       controltovalidate.title = ""; //clear tooltip

   13     }

   14     return isValid;  //return validation result for further processing

   15   }

On the very beginning, the original validation function executes to perform validation. Depend on the validation result the CSS class for the validated control is changed and the message tooltip is set up.

This easy extender shows how to change behaviour of original validator. What is important, this will not work with CustomValidator with server side validation. We will deal with this later in the course.

Next:

The above extender can be assigned to the only one validator and has to be repeated for each validator on the form. In the next part, I will show how to create one extender for all validators.

 Lazy Developer : Extender Project News Feed 

Last edited Dec 7, 2006 at 11:16 PM by codeplexadmin, version 1

Comments

mutual_mill May 29, 2007 at 6:01 PM 
The ajax validatorextender seems to catch the postback of any button, exp: submit button on the page, and does not call the postback even when the control is valid. The method of the button click is never called.