As part of my ongoing “stop coding like it’s 1999″ regime, I managed to think my way out of some code in the following scenario:
My business object returns a phone number, but it happens to be a raw number, i.e. there’s no formatting: (416) 967-1111 comes back as 4169671111. I’ve got a repeater control in ASP.NET, and I want to pretty it up.
In the past, I’d:
- Code a new property into the business object to give me a formatted string.
- Add an ItemDataBound event handler to the repeater, which calls FindControl and fills in the value all pretty-like.
- Ignore the issue and hope nobody notices.
The new and improved Luke does this in his <ItemTemplate> node:
<%# String.Format(
”{0:(###) ###-####},
Convert.ToInt64(
DataBinder.Eval(Container.DataItem, “PhoneNumber”)))
%>
Not the prettiest thing in the world, but (after some thinking) the easiest, and it actually puts the presentation details at the right layer.
If I’m not careful, I might actually become productive.
Pop quiz: is there a cleaner way to do this?
harsha | 08-Dec-05 at 3:45 pm | Permalink
rice one..it would rather do all my formating on client side…
harsha | 08-Dec-05 at 3:48 pm | Permalink
What i really meant was that I would my formating using javascript/vbscript …:)
Luke | 08-Dec-05 at 4:00 pm | Permalink
Yeah, but the idea here is to do less work, not more. Do you have a URL with an example of formatting a phone number via javascript? It sounds like overkill to me…
Luke
Kelly | 14-Mar-06 at 3:12 pm | Permalink
Luke, you are the man. I’ve been trying to use formatting in item templates with the old VBScript formatting functions and sometimes they just don’t work. It never occurred to me that I could use the String.Format Static method in the HTML. Thanks
Luke | 14-Mar-06 at 4:49 pm | Permalink
Funny you should mention that today, Kelly, I just did a weird bit of data binding this morning that reminded me of this post! I should get off my butt and write more about this stuff, it’s the only way I’ll remember it…
jeaux | 16-Oct-06 at 1:22 pm | Permalink
DataBinder.Eval(Container.DataItem, “Phone_Number”,”{0:(###) ###-####}”)
Jason | 27-Oct-06 at 9:43 am | Permalink
Jeaux, that won\’t work - the var is defined as a string, so the formatting is pretty much ignored, as far as I can tell - you need to convert it to a number first. I had a lovely example page made up, but WP doesn\’t want to let me add it to the comments, so you\’ll just have to trust me, or try it for yourself.
Victor Escobar | 20-May-07 at 5:44 pm | Permalink
When I used your code, I got the following error:
Object cannot be cast from DBNull to other types.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidCastException: Object cannot be cast from DBNull to other types.
Source Error:
Line 40: HeaderText=”Phone Number” SortExpression=”strPhoneNumber”>
Line 41:
Line 42:
Line 43:
Line 44:
Source File: C:\inetpub\XXX\YYY\ZZZ.aspx Line: 42
Stack Trace:
[InvalidCastException: Object cannot be cast from DBNull to other types.]
System.DBNull.System.IConvertible.ToInt64(IFormatProvider provider) +54
System.Convert.ToInt64(Object value) +25
ASP.admin_admin_evaluator_aspx.__DataBind__control16(Object sender, EventArgs e) in C:\inetpub\XXX\YYY\ZZZ.aspx:42
System.Web.UI.Control.OnDataBinding(EventArgs e) +99
System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +206
System.Web.UI.Control.DataBind() +12
System.Web.UI.Control.DataBindChildren() +216
System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +216
System.Web.UI.Control.DataBind() +12
System.Web.UI.Control.DataBindChildren() +216
System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +216
System.Web.UI.Control.DataBind() +12
System.Web.UI.WebControls.GridView.CreateRow(Int32 rowIndex, Int32 dataSourceIndex, DataControlRowType rowType, DataControlRowState rowState, Boolean dataBind, Object dataItem, DataControlField[] fields, TableRowCollection rows, PagedDataSource pagedDataSource) +221
System.Web.UI.WebControls.GridView.CreateChildControls(IEnumerable dataSource, Boolean dataBinding) +3004
System.Web.UI.WebControls.CompositeDataBoundControl.PerformDataBinding(IEnumerable data) +59
System.Web.UI.WebControls.GridView.PerformDataBinding(IEnumerable data) +11
System.Web.UI.WebControls.DataBoundControl.OnDataSourceViewSelectCallback(IEnumerable data) +111
System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) +29
System.Web.UI.WebControls.DataBoundControl.PerformSelect() +149
System.Web.UI.WebControls.BaseDataBoundControl.DataBind() +70
System.Web.UI.WebControls.GridView.DataBind() +4
System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound() +82
System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls() +69
System.Web.UI.Control.EnsureChildControls() +87
System.Web.UI.Control.PreRenderRecursiveInternal() +41
System.Web.UI.Control.PreRenderRecursiveInternal() +161
System.Web.UI.Control.PreRenderRecursiveInternal() +161
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1360
——————————————————————————–
Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.210
Jason | 22-May-07 at 11:02 am | Permalink
Victor, can you email me the source file so I can see what else is going on? I’ll try to put an update on demos tonight…
Kathleen Anderson | 07-Jul-07 at 9:00 pm | Permalink
Thanks for this - I have been Googling for the last 24 hours for something like this. I did find your syntax was off just a tad - this is what worked for me:
‘
Kathleen Anderson | 07-Jul-07 at 9:05 pm | Permalink
String.Format(”{0:(###) ###-####}”, Convert.ToInt64(DataBinder.Eval(Container.DataItem,”homephone”)))
Cetin Basoz | 18-Aug-07 at 10:29 am | Permalink
Pardon me but telephone numbers are not made up of digits all the time. Wouldn’t something like this cause a parsing error?
800VERIZON
or (formatted):
+1 (555) 1234567 [1234]
+1 555 1234567 - 1234
+1 555 123 45 67 - 1234
00 1 (555) 1234567
444 0 MSI
etc.
Maybe storing it as end users wrote is the way. People are accustomed to type in such data in the format they are familiar most.
To me it’s neither the job of data layer nor presentation. Humans can easily interpret those numbers.
ASP.NET Applications | 09-Oct-07 at 3:02 am | Permalink
Good info. But I agree with the Harsh- I prefer the client side to do all the ugly work…
ASP.NET Applications | 24-Oct-07 at 7:09 am | Permalink
Great post
I agree with Cetin Basoz.
I believe that storing it as the users do- is the way.
Jeremy | 28-Nov-07 at 12:57 pm | Permalink
Actually, it would be best to parse the digits out when accepting the data using regex. Storing various formats of the same style is a nightmare to maintain. Taking a we’ll-just-deal-with-whatever-they-input approach will eventually cause a lot of problems (especially on the security side).
Haniel Croitoru | 25-Dec-07 at 11:43 pm | Permalink
Hi all,
This post is very useful. One additional question I have on this is, how do I deal with the situation where the phone number may be blank? The browser throws an exception at that point.
Andy | 28-Dec-07 at 3:59 pm | Permalink
public static string FormatPhoneNumber(string pNum)
{
pNum = RemoveNonIntegers(pNum);
if (pNum.Length == 10)
return String.Format(”{0:(###) ###-####}”, Int64.Parse(pNum));
else if (pNum.Length == 7)
return String.Format(”{0:###-####}”, Int64.Parse(pNum));
else return “Invalid string format”;
}
Jason | 01-Jan-08 at 11:42 am | Permalink
Haniel, there’s not a lot of error handling (i.e. none) in this technique - a helper function like Andy provided would be a better approach here.