New to The Big Boy MVC Series?
Read the series from its humble beginnings.
In a somewhat elderly article, Karl Seguin suggests that all programmers should know Linux. And C. And memory management. And pointers. Karl stops just short of requesting that you cease making love to other people. But, if abstinence helps you become pseudo (homonymical pun intended) good at Linux, well then so be it. Stop making love. That’s why I stopped making love, in fact. Not because the demand for my love-making skills plummeted. But because I wanted to learn.
When we talk about “improving” our skills as knowledge-hungry developers, I find it interesting that we rarely mention the people in our lives (not Karl Seguin, alas) who we inevitably and repeatedly injure with our sloppiness: namely, designers. Yes, those people, over there, cloaked in Urban Outfitter attire, crying, listening to Bon Iver (or, like, whatever). We’re responsible for 90% of their personal anguish, and yet, when it comes time to improving ouselves, we dive deeper and deeper into the black subhuman vortex of pure, unadulterated, unstyled nerdiness, all while ignoring the needs and desires of our poor (though good-looking and well-dressed) designer. It’s time to change that.
Today, we’re going to make eye-contact. We’re going to try to feel the pain of the designer. We’re going to hug. And, in the end, we’re going to harness the power of MVC to make the life of our designer (or, in this case, the lives of ourselves) as easy as possible.
Step 1: Create an EditorTemplate folder. Place this folder in the Views/Shared subfolder. A.K.A.:
Step 2: Avoid touching others. Learn more about EditorTemplates before doing something ill advised. There are two amazingly helpful resources that you should devour before continuing here. First, read Brad Wilson’s multi-post series about MVC templates here. Second, read Elijah Manor’s post about opinionated template helpers here. That should get you better acquainted with the technical aspects of our magical journey.
Step 3: Create a design-friendly EditorTemplate. As mindblowingly awesome as Brad and Elijah’s proclamations are, I encountered some real trouble when I started to style the rendered output. I decided that each of my EditorTemplates should double as a design module. That way, when I want to change the look and feel of a form, I can swap out one EditorTemplate for another. Hopefully, as we go along, you’ll begin to see why this approach will make the design process a bit more manageable for us.
For starters, we’ll place the following code into a MVC partial, and we’ll save it as Grid3-6.ascx. Place Grid3-6.ascx into the newly created EditorTemplates folder. Simple enough. If you read Elijah’s post, you’ll notice that I stole a sizable chunk of this code from his helpful code snippet:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<div class="template">
<% if (ViewData.TemplateInfo.TemplateDepth > 1) { %>
<%-- outlet for a shallow dive in a deep pool --%>
<%= ViewData.ModelMetadata.SimpleDisplayText %>
<%
} else {
var data = ViewData.ModelMetadata;
var template = ViewData.TemplateInfo;
var properties = data.Properties.Where(m => m.ShowForEdit && !template.Visited(m));
%>
<% foreach (var property in properties) { %>
<% if (property.HideSurroundingHtml) { %>
<%-- no label, no validation message, no skirt --%>
<%= Html.Editor(property.PropertyName) %>
<% } else { %>
<div class="field">
<span class="label grid-3">
<label for="<%: property.PropertyName %>"><%: property.DisplayName %>:</label>
<span class="req <%: property.IsRequired? "visible" : "invisible" %>">*</span>
</span>
<span class="input grid-6">
<%: Html.Editor(property.PropertyName) %>
</span>
<% if (!ViewData.ModelState.IsValidField(property.PropertyName)) { %>
<span class="validation grid-6 prefix-3">
<span class="error icon"></span>
<%: Html.ValidationMessage(property.PropertyName) %>
</span>
<% } %>
</div>
<% } %>
<% } %>
<% } %>
</div>
Notice that we’re taking advantage of our 960 grid system. For starters, our label will be 3 grid-lengths long, and the wrapper around our input field will be 6 grid-lengths long. Below the label and the input field, we’ll display a validation error message (if it exists). That validation message should be left-aligned with our input field. Also, as an added (though possibly unnecessary touch), required fields will be marked with a visible red asterisk. Unrequired fields will also be marked with a red asterisk, but those asterisks will be set to visibility:hidden, thus maintaining easy alignment.
Step 4: Update the FoodAdd page. If you’ve been following along, we’ve already done a considerable amount of work on our FoodAdd page. Time now for another quick, painless iteration:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<FoodAdd>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Big Fat Dish - Add a New Food
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
<div class="container-16 wrap">
<div class="block">
<h1>Add a New Food to Big Fat Dish</h1>
<% Html.BeginForm(); %>
<div id="add-image" class="grid-4">
<div id="image-input" class="new">Click to Add an Image</div>
</div>
<%: Html.EditorForModel("Grid3-6") %>
<div id="add-food" class="grid-14 submit">
<input type="submit" value="Add Food" />
</div>
<% Html.EndForm(); %>
</div>
</div>
</asp:Content>
Step 5: Style your EditorTemplate. If the process of styling your EditorTemplate isn’t easy, or if the resulting styles aren’t reusable, you should consider reworking your EditorTemplate. For the sake of your designer. Because the goal here is to make the design process as easy and as modularized as possible. Because your designer is sensitive. And the EditorTemplate should be his friend.
To style my EditorTemplate, I downloaded the overly extensive Fugue Icon Set. I also did some peripheral styling. I added some fades, some borders, some margins, and some much-need padding. You know, designer stuff. All in all, you can tell that I’m a bit of a fanboy of the Envato Technique:
/* generic */
html, body
{
background-color:#2c2a29;
font-family: Helvetica, Geneva;
}
.hide
{
display:none;
}
.invisible
{
visibility:hidden;
}
ul.no-list li
{
list-style-type:none;
}
.no-decor
{
text-decoration:none;
}
/* containers */
.container-16.wrap
{
border:1px solid #bbb;
overflow:hidden;
}
.block
{
border:1px solid #fff;
overflow:hidden;
background-color:#f6f6f6;
padding:40px 0px 20px 60px;
}
/* frame */
#header, #navigation, #content, #footer-top, #footer-bottom
{
overflow:hidden;
}
#header, #navigation, #footer-top, #footer-bottom
{
color:#86806b;
}
#header a, #navigation a, #footer-top a, #footer-bottom a
{
color:#cdc0a9;
text-decoration:none;
}
#header
{
height:60px;
padding:5px 0px 10px 0px;
background:#3b3b3b url("images/fades/fade_3b3b3b_1x199.png") repeat-x;
}
#navigation
{
background:#4a4439 url("images/fades/fade_4a4439_1x32.png") repeat-x top left;
}
#navigation ul li
{
padding-top:17px;
border-left:1px solid #5e5749;
height:33px;
text-align:center;
margin:4px 0px 2px 0px;
}
#navigation ul li.last /* last nav tab */
{
border-right:1px solid #5e5749;
}
#content
{
padding:40px 0px 50px 0px;
background:#d2d1cf url("images/fades/fade_d2d1cf_1x190.png") repeat-x top left;
border-bottom:1px solid #efefef;
}
#footer-top
{
height:200px;
background:#3b3630;
border-top:1px solid #010000;
border-bottom:1px solid #4e4a44;
}
#footer-bottom
{
background:#2c2a28;
}
#footer-bottom
{
padding-top:10px;
height:60px;
border-top:1px solid #232220;
font-size:11px;
}
/* form elements */
.field
{
overflow:hidden;
margin-bottom:10px;
}
.field input, .field .label
{
font-size:16px;
}
.field input
{
/* TODO: handle checkboxes, etc */
width:100%;
border:1px solid #ccc;
}
.field .label
{
text-align:right;
}
.field .req
{
color:#aa2c2c;
}
.field .validation
{
margin-top:5px;
font-size:13px;
color:#aa2c2c;
}
.field-validation-error
{
display:block;
float:left;
}
.icon
{
margin-right:10px;
display:block;
float:left;
width:16px;
height:16px;
}
.error.icon
{
background:transparent url("images/icons/fugue/exclamation-red.png") no-repeat;
}
.submit
{
height:70px;
margin:40px 10px 10px 10px;
}
.submit input
{
height:100%;
width:100%;
}
.button, .submit input
{
border:none;
text-align:center;
background:#ea6e4c;
color:#fff;
font-size:35px;
cursor:pointer;
padding:10px 0px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
/* home index */
#foods
{
float:left;
margin-top:10px;
}
#add-food
{
margin:40px 10px 30px 10px;
}
/* add food */
#image-input
{
text-align:center;
font-size:16px;
background:#efefef;
width:100%;
height:180px;
}
#image-input.new
{
padding-top:20px;
border:1px solid #ccc;
}
Step 6: Test out your designer-friendly template. Make sure that it looks acceptable in all of the standard browsers (I tend to care less about Internet Explorer’s feelings). Once you’ve done that, you can bask in the glory of all of your hard, hard work:
My design could surely still use a real designer’s touch. But, when that touch finally comes, it should be a swift and painless one. Like chocolate-coated dreams.
At the very least, our newly created, quasi-modularized design is definitely an improvement over our original page style (if I don’t say so myself):
Now, with a little bit of elbow grease, we can easily create as many EditorTemplates as we desire.
But, first, it might not be a bad idea to buy your favorite designer some tropical flowers. Or a copy of Objectified. Or, that movie about Helvetica. Or, a firm manly hug. Or, a letter. Or, a copy of Linux for Designers.
Move on to The Big Boy MVC Series — Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!
Read More
You can leave a response, or trackback from your own site.
6 Responses to “The Big Boy MVC Series — Part 24: Dear EditorTemplates, Are We Done Posting Yet?”
Leave a Reply





[...] Move on to Part 24: Dear EditorTemplates, Are We Done Posting Yet?. [...]
It’s always nice to show off a website to your work colleagues, only for the first picture he sees to be a naked guy.
Actually… Not so nice…
Dan,
I’ve removed the naked man. Only because (a.) it will cause intrigue, and (b.) it makes YOU seem kind of crazy for leaving that comment where there’s no “naked man” anywhere in sight.
So, what naked man? I don’t see a naked man?
Anywho. No naked man. Anymore.
C,e
I have a problem when I post with all fields empty. The property ModelState.IsValid returns true, as if the mapping between Food and FoodAdd had not worked.
What type is your action Add look for : Food or FoodAdd ?
And also, can you give a link to download your fade png.
Merci.
[...] good news: in my last Big Boy post, we created a prettyish design-friendly EditorTemplate. That was fun. So, with our EditorTemplate [...]
Hey Michel,
Sorry for keeping you in the dark. I just posted all of the information you should need to make your post all happy-like (Part 25). Let me know if you have any troubles!
Cheers,
Evan