locked
Composite Validator Control ASPX vs ASCX Rendering RRS feed

  • Question

  • User-1310972242 posted

    So I continue to find the DateValidation a bit unsatisfactory...

    I am attempting to write a server control that handles all my Date Validation needs.  I have succeeded. 

    The only caveat now is that when I use the control on an ASPX page, it works.  When I use it inside an ASCX (to use a template) control, the <span> tag of the validator is not rendered to the HTML and I get a javascript null reference when it can't find the control by ID.

    Obviously I can post all the code (might be easier for me to host a FTP of the project) relevant, but primarily, it works outside of this one tiny catch.

    Note: I am not overriding CreateChildControls since I don't need to modify the output but rather all the attributes (using RegisterExpandoAttribute) of the validator to validate the Dates on the client side.

    Any thoughts?

    Tuesday, November 10, 2009 4:17 PM

Answers

  • User-2106054853 posted

     Hi,

    Please have a look at this method:

    protected override bool ControlPropertiesValid()
            {
           

                if (String.IsNullOrEmpty(ComparisonControlToValidate))
                {
                    Control ctrl = Page.FindControl(ControlToValidate);//change to this.FindControl
                    return (ctrl != null);
                }
                else
                {
                    Control ctrl = Page.FindControl(ControlToValidate);
                    Control compCtrl = Page.FindControl(ComparisonControlToValidate);
                    return (ctrl != null && compCtrl != null);
                }
              
            }

    If the control is put in UserControl, Page.FindControl() method probably will return null. A more proper way is to use this.FindControl to find the target control. In this way it will search from the validation control and up to it's naming container. Thus the controls on the same level of the Validation control can be found.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, November 16, 2009 2:01 AM

All replies

  • User-1310972242 posted

    Ok, maybe I missed something somewhere, so here's some (abbreviated) code:


    [DefaultProperty("Text")]
    [ToolboxData("<{0}:DateValidator runat=server></{0}:DateValidator>")]
    public class DateValidator : BaseValidator
    {
            protected override bool ControlPropertiesValid()
            {
                if(String.IsNullOrEmpty(ComparisonControlToValidate))
                {
                    Control ctrl = Page.FindControl(ControlToValidate);
                    return (ctrl != null);       
                }
                else
                {
                    Control ctrl = Page.FindControl(ControlToValidate);
                    Control compCtrl = Page.FindControl(ComparisonControlToValidate);
                    return (ctrl != null && compCtrl != null);
                }
            }
            
    
            protected override void OnInit(EventArgs e)
            {
                base.OnInit(e);
                //add CSS.
                string cssLink = Page.ClientScript.GetWebResourceUrl(this.GetType(),
                                                                     "DAVCustomControls.DateValidator.DateValidator_Styles.css");
                Literal litCSS = new Literal();
                litCSS.ID = this.ID + "__litCSS_DV";
                litCSS.Text = "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + cssLink + "\" />";
                if (this.Page.Header.FindControl("litCSS_DV") == null)
                {
                    this.Page.Header.Controls.Add(litCSS);
                }
            }
            
    
            protected override void OnPreRender(EventArgs e)
            {
                //register our client script for usual post-back
                //(will do nothing in case of partial udpate)
                string scriptUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(),
                                                                       "DAVCustomControls.DateValidator.DateValidator.js");
                if(!Page.ClientScript.IsClientScriptIncludeRegistered("js_DV"))
                {
                    Page.ClientScript.RegisterClientScriptInclude("js_DV", scriptUrl);
                }
    
                // Determines whether the validation control can be rendered
                // for a newer ("uplevel") browser.
                // check if client-side validation is enabled.
                //evaluationfunction will be null if in PartialRendering, so we re-hash this below
                if (this.DetermineRenderUplevel() && this.EnableClientScript)
                {
                    if (this.EvaluationFunction == null)
                    {
                        Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "evaluationfunction", "validationCheck");
                        if (!String.IsNullOrEmpty(this.ComparisonControlToValidate))
                        {
                            Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "comparisonControlID", this.ComparisonControlToValidate);
                            Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "comparisonOperator", this.ComparisonOperator.ToString());
                        }
                        if (this.MinDate != new DateTime())
                        {
                            Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "minDate", String.Format("{0:MM/dd/yyyy}", this.MinDate));
                        }
                        if (this.MaxDate != new DateTime())
                        {
                            Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "maxDate", String.Format("{0:MM/dd/yyyy}", this.MaxDate));
                        }
                        if (this.UseDefaultErrorMessages)
                        {
                            Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "useDefaultError", this.UseDefaultErrorMessages.ToString());
                        }
                    }
                    else
                    {
                        Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "evaluationfunction", this.EvaluationFunction);
                    }
                    if (this.IsRequired)
                    {
                        Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "isRequired", "true");
                    }
                }
    
                //register our script during asynchronous postback
                //this code will just do nothing if there is no ASP.NET AJAX installed
                if (Ajax.IsControlInsideUpdatePanel(this) && Ajax.IsInAsyncPostBack(Page) || this.IsInAjaxUpdate)
                {
                    if (!Ajax.IsClientScriptIncludeRegistered(Page, "js_DV"))
                    {
                        Ajax.RegisterClientScriptInclude(Page, this.GetType(), "js_DV", scriptUrl);
                    }
                    if (this.EvaluationFunction == null)
                    {
                        Ajax.RegisterExpandoAttribute(Page, this.ClientID, "evaluationfunction", "validationCheck");
                        if (!String.IsNullOrEmpty(this.ComparisonControlToValidate))
                        {
                            Ajax.RegisterExpandoAttribute(Page, this.ClientID, "comparisonControlID", this.ComparisonControlToValidate);
                            Ajax.RegisterExpandoAttribute(Page, this.ClientID, "comparisonOperator", this.ComparisonOperator.ToString());
                        }
                        if (this.MinDate != new DateTime())
                        {
                            Ajax.RegisterExpandoAttribute(Page, this.ClientID, "minDate", String.Format("{0:MM/dd/yyyy}", this.MinDate));
                        }
                        if (this.MaxDate != new DateTime())
                        {
                            Ajax.RegisterExpandoAttribute(Page, this.ClientID, "maxDate", String.Format("{0:MM/dd/yyyy}", this.MaxDate));
                        }
                    }
                    else
                    {
                        Ajax.RegisterExpandoAttribute(Page, this.ClientID, "evaluationfunction", this.EvaluationFunction);
                    }
                    if (this.IsRequired)
                    {
                        Ajax.RegisterExpandoAttribute(Page, this.ClientID, "isRequired", "true");
                    }
                }
    
                base.OnPreRender(e);
            }
    }


    Thursday, November 12, 2009 8:48 AM
  • User-1310972242 posted

    Further Bumpage:

    When manually overriding the Render event of the class inheriting BaseValidator, I can force the SPAN tag to appear, but the validator's controltovalidate attributes etc all dissappear.

    It seems that the base render method is not firing when inside an ASCX.

    EDIT:  I actually just tested this by forcing the base.Render(writer) when already writing the span tag with the clientID.  I get an exception saying a control with that key already exists.  But when using just base.Render, nothing happens.


    EDIT2:  When put in the ASCX control, the Validator control (the custom class overridden from BaseValidator) is missing a very important JavaScript line:

    (IN THE ASPX PAGE)

    <script type="text/javascript">
    //<![CDATA[
    var Page_ValidationSummaries =  new Array(document.getElementById("cal"));
    var Page_Validators =  new Array(document.getElementById("valTest"));
    //]]>
    </script>

    (WHEN USED INSIDE AN ASCX)
    <script type="text/javascript">
    //<![CDATA[
    var Page_ValidationSummaries =  new Array(document.getElementById("uc1_cal"));
    //]]>
    </script>

    As you can see, it's added to the Page_Validators collection when run from within an ASPX, but not from within an ASCX.  Does anyone have any idea why?  This might help me figure out my issue.  It's also not setting the visibility: hidden CSS attribute when inside the ASCX.

    Thursday, November 12, 2009 4:41 PM
  • User-16411453 posted

    I didn't see an span tag in the code.

    Span tags are just labels

    IN VB

    Dim lbl_Title as Label produces <span></span>

    So here is some jibberish that may help you

    .ID = [ID] & "_lbl_Title" to make it very unique, and work with master pages

    .Attribute.Add("id", "lbl_Title") to make it work with custom Javascript, stays clear of id name changes after rendering



    Friday, November 13, 2009 12:48 AM
  • User-2106054853 posted

    Hi,

    Could you post a demo project that can reproduce this issue? You can upload the project to http://skydrive.live.com/ and paste download link here for me to test. 

    Friday, November 13, 2009 12:56 AM
  • User-1310972242 posted

    SkyDrived.

    The Web Application project is the start project and Default.aspx is the start page.  You can exclude the documentation project if you don't have Sandcastle installed, it doesn't effect the primary project.

    I just read something on CodeProject that had a completely different approach.  I hesitate to think that I will have to completely rebuild this.  But if that's the required approach to meld this with the Validator.js then I will.

    ----

    Re: The Span Tag.  When a validator control is added to the controls collection on the server, a span tag is rendered to the HTML output so that the error message can be dynamically shown/hidden.  Since BaseValidator is the class that implements this (for all validators) I don't need to override the RenderChildren method in the class to modify it's output HTML.  Thus I'm stumped.

    Friday, November 13, 2009 8:42 AM
  • User-2106054853 posted

     Hi,

    Please have a look at this method:

    protected override bool ControlPropertiesValid()
            {
           

                if (String.IsNullOrEmpty(ComparisonControlToValidate))
                {
                    Control ctrl = Page.FindControl(ControlToValidate);//change to this.FindControl
                    return (ctrl != null);
                }
                else
                {
                    Control ctrl = Page.FindControl(ControlToValidate);
                    Control compCtrl = Page.FindControl(ComparisonControlToValidate);
                    return (ctrl != null && compCtrl != null);
                }
              
            }

    If the control is put in UserControl, Page.FindControl() method probably will return null. A more proper way is to use this.FindControl to find the target control. In this way it will search from the validation control and up to it's naming container. Thus the controls on the same level of the Validation control can be found.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, November 16, 2009 2:01 AM