Some HTML / ASP.NET Thoughts …
On a particular real estate website, we have a "Property Summary" section that contains each property's name, the address, a phone number (if it exists), and a contact email address (if it exists).
The information is data bound to properties in the page's code-behind, and the ASP.NET code basically looks like this:
<div>
<%# Property Name%>
<%# AddressLine1 %>
<%# AddressLine2 %>
<%# AddressLine3 %>
<%# CityStateZIP %>
<%# Phone %>
<%# Email %>
</div>
<%# Property Name%>
<%# AddressLine1 %>
<%# AddressLine2 %>
<%# AddressLine3 %>
<%# CityStateZIP %>
<%# Phone %>
<%# Email %>
</div>
Because lots of these elements are optional, all of these properties have all been written to work like this in the code-behind:
Protected Readonly Property AddressLine1 as String
Get
If _AddressLine1 = "" Then
Return ""
Else
Return _AddressLine1 + "<br>"
End if
End Get
End Property
Get
If _AddressLine1 = "" Then
Return ""
Else
Return _AddressLine1 + "<br>"
End if
End Get
End Property
It was written this way so that there will not be extra empty lines where the data is missing, and there will be a line break if data exists. Typically, AddressLine2 and AddressLine3 are blank, but they may be present. The Email property, since it is a link, is even worse:
Protected Readonly Property Email as String
Get
If _Email = "" Then
Return ""
Else
Return String.Format("<a href='mailto:{0}'>{0}</a><br>", _Email)
End if
End Get
End Property
Get
If _Email = "" Then
Return ""
Else
Return String.Format("<a href='mailto:{0}'>{0}</a><br>", _Email)
End if
End Get
End Property
That a lot of HTML in the code-behind that ideally we'd have in the markup. My first instinct to make this a little cleaner/simpler was to create a function like this:
Protected Function CheckBR(TextToCheck as string) as String
If Text.Trim() = "" Then
Return ""
Else
Return "<br>"
End if
End Function
If Text.Trim() = "" Then
Return ""
Else
Return "<br>"
End if
End Function
That way, I could remove the empty check and the append of the <BR> tag in my properties, and then use my function on the Page like this:
<div>
<%# Property Name%><br>
<%# AddressLine1 %><br>
<%# AddressLine2 %><%# CheckBR(AddressLine2)%>
<%# AddressLine3 %><%# CheckBR(AddressLine3)%>
<%# CityStateZIP %><br>
<%# Phone %><%# CheckBR(Phone)%>
<%# Email %><%# CheckBR(Email)%>
</div>
<%# Property Name%><br>
<%# AddressLine1 %><br>
<%# AddressLine2 %><%# CheckBR(AddressLine2)%>
<%# AddressLine3 %><%# CheckBR(AddressLine3)%>
<%# CityStateZIP %><br>
<%# Phone %><%# CheckBR(Phone)%>
<%# Email %><%# CheckBR(Email)%>
</div>
That way, all optional lines will only have breaks if they exist; only non-optional lines will have <br> tags specified. This still seemed sloppy. I thought adding "runat=server" to the "<br>" tags and then specifying the Visible property like this:
<br runat="server" visible='<%# Email.Trim() <> "" %>' />
but that really seemed like overkill and didn't appear to make things any cleaner. Isn't there an easier way? I wondered if I should create a custom ASP.NET "conditional line break" control ...
Then I remembered how browsers render empty tags: Even if the tag is a block element, and the tag is empty, nothing is rendered -- including the line break! For example, this:
<div>Hello</div>
<div></div>
<div>Bye</div>
<div></div>
<div>Bye</div>
displays as:
Hello
Bye
Bye
That is because the middle <div> contains no text (not even a single space) or any other content that is visible. Thus, all we need to do is use <div> tags, not <br> tags, for our line breaks, like this:
<div>
<div><%# Property Name%></div>
<div><%# AddressLine1 %></div>
<div><%# AddressLine2 %></div>
<div><%# AddressLine3 %></div>
<div><%# CityStateZIP %></div>
<div><%# Phone %></div>
<div><a href='mailto:<%# Email %>'><%# Email%></a></div>
</div>
<div><%# Property Name%></div>
<div><%# AddressLine1 %></div>
<div><%# AddressLine2 %></div>
<div><%# AddressLine3 %></div>
<div><%# CityStateZIP %></div>
<div><%# Phone %></div>
<div><a href='mailto:<%# Email %>'><%# Email%></a></div>
</div>
Notice that our Email property can simply return the email address and not worry about creating a link, and all of our properties can simply return raw data. We always output the <a> tag without the need to check if the email address is present; if the containing text is empty, neither the link nor the <div> will render in the browser. That is,
<div>Hello</div>
<div><a href="someurl"></a></div>
<div>Bye</div>
<div><a href="someurl"></a></div>
<div>Bye</div>
still displays as:
Hello
Bye
Bye
in the browser.
This is a little off topic and has nothing to do with SQL Server directly, but it may be a handy tip or reminder for some. It's nice to get rid of the embedded HTML in the code behind and to eliminate some extra code. This same concept also applies to <p> tags, though in this case we are not using them because the spacing would be too much. (You could alter this via CSS, of course).
UPDATE: In the comments, JD suggests an alternative which I like better. The only negative is that html tags are being "hidden" in your code-behind, and you'd have to adjust your function (or create a new one) to handle hyperlinks or more complicated output.
But, if you can and would like to create additional functions to help with the formatting, that is a good option. If you cannot create additional functions or want to eliminate as much code-behind as possible, then the "empty block element" trick can be useful, especially if you already have the tag on your page.
For example, instead of using server-side logic
<p runat="server" visible='<%# SomeText.Trim() <> "" %>'>
<%# SomeText %>
</p>
<%# SomeText %>
</p>
or using a function that wraps non-blank text in <p> tags:
<%# PrintAsParagraph(SomeText) %>
you can simply write:
<p><%# SomeText.Trim() %></p>
By eliminating the spacing, the paragraph and all of the associated spacing will not display at all if SomeText is blank.
Thanks for the input, JD!
see also:
- Splitting a single DataTable into Parent/Child DataTables for Hierarchical Processing (e.g., nested ASP.NET Repeater controls)
- Creating CSV strings in SQL: Should Concatenation and Formatting Be Done at the Database Layer?
- ASP.NET 1.1 -- Appsettings in Web.config
- Minimizing the ViewState for an ASP.NET 1.1 DataGrid
Legacy Comments
JD
2007-10-17 |
re: Quick HTML / ASP.NET Tip ... Excuse me, but I disagree. Creating more DIV-tag-soup is not a great idea. Why not do this? <div> <%# PrintWithBreak(Property Name) %> <%# PrintWithBreak(AddressLine1) %> <%# PrintWithBreak(AddressLine2) %> <%# PrintWithBreak(AddressLine3) %> <%# PrintWithBreak(CityStateZIP) %> <%# PrintWithBreak(Phone) %> <%# PrintWithBreak(Email) %> </div> And your PrintWithBreak function will return empty string if the input is empty. Otherwise it will return a new line, property value and <BR> tag. [If you return new line, your source code is also formatted.] JD P.S.: I am a regular visitor and really appreciate your insightful posts on SQL Server. Keep them coming! |
Jeff
2007-10-17 |
re: Quick HTML / ASP.NET Tip ... JD -- very nice, I didn't think of that. that seems to make much more sense. I don't think the extra DIV tags are necessarily a bad thing, but this is definitely a nice way to do it and still use BR tags. |