Welcome to AspAdvice Sign in | Join | Help

Remember expando attributes with custom controls

Today I replied to a question related to a custom validator control deriving from BaseValidator. Control registered its client-side script with following kind of code snippet.

protected override void OnPreRender(EventArgs e)   
{     
  if(this.DetermineRenderUplevel() && this.EnableClientScript)     
  {
          this.Attributes["evaluationfunction"] = "ListItemVerify";
          this.RegisterClientScript();     
  }      else
       {
          this.Attributes.Remove("evaluationfunction");     
  }     
  base.OnPreRender(e);   
}

What's wrong with that? From IE standpoint it, client side validation, seems to work, but try that with Firefox or Opera. If you check what's rendered in the control's markup it seems right.

<span id="..." evaluationfunction="ListItemVerify" ... >

But no love, client side validation doesn't work. It just posts back.

These custom attributes, often called as expando attributes, are fine in Firefox etc but they are not part of DOM. They would be available only via getAttribute/setAttribute method. ASP.NET 2.0's validation script library refers to these properties/attributes straight like obj.evaluationfunction, when it doesn't work in any other browser than IE. E.g your custom client-side validation function won't get called at all.

But luckily, ASP.NET 2.0 addresses this problem. ClientScriptManager class, which you access via Page.ClientScript property, has RegisterExpandoAttribute method. When you call it, a special script block is registered to be outputted, and it looks like this.

<script type="text/javascript">
<!--
var validateCBL = document.all ? document.all["validateCBL"] : document.getElementById("validateCBL");
validateCBL.evaluationfunction = "ListItemVerify";
...
</script>

Trick is, that this preserves XHTML compatibility and results to validation now working again in non-IE-browsers. So, the solution to the original problem is to rewrite the method.

 protected override void OnPreRender(EventArgs e)
        {
            if (this.DetermineRenderUplevel() && this.EnableClientScript)
            {
                Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "evaluationfunction", "ListItemVerify");
                this.RegisterClientScript();
            }
            base.OnPreRender(e);

        }

Now, it happens in OnPreRender. Note that since usually attributes are rendered in AddAttributesToRender method, it might feel more familiar to move registering expando attributes there. Separating previous logic like this


protected override void OnPreRender(EventArgs e)
        {
            if (this.DetermineRenderUplevel() && this.EnableClientScript)
            {
                this.RegisterClientScript();
            }
            base.OnPreRender(e);

        }

        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(writer);
            if (this.DetermineRenderUplevel() && this.EnableClientScript)
            {
                Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "evaluationfunction", "ListItemVerify");
            }
        }

However, which one of these previous two approaches you use, is totally up to you. They work the same. Using the first approach seems good also, because all code is within those few lines and uplevel browser-detection happens in tthe same snippet.

Sponsor
Published Saturday, August 26, 2006 6:44 PM by joteke
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
required 
(required) 
Enter the code you see below