Hoje iniciarei uma sequência de posts técnicos referentes a experiências que tenho aqui na Light Solutions no setor de desenvolvimento sob medida,
o intuito é registrar essas experiências e ajudar outras pessoas com essas informações, atualmente já ajudo alguns amigos por Skype e no trabalho, então registrarei essas situações aqui no blog da empresa.
para esse primeiro post explicarei uma situação com ASP.NET MVC 3 / Razor / C# que utilizei no projeto Portal Mariaca Online
para montar um form necessitei de um @Html.LabelFor, mas preciso que os labels apresentem um “*” ao lado dos campos obrigatórios, mas respeitando os DataAnnotations que estão no Model, por exemplo:
[Required(ErrorMessage = "campo obrigatório")] [Display(Name = "nome")] public String ClienteSt;
no meu caso, o @Html.LabelFor(m => m.ClienteSt) deveria renderizar:
<label for="ClienteSt"> nome <span class="required">*</span> </label>
após uma breve busca no Google encontrei esse cara aqui:
http://kamranicus.com/Blog/Posts/3/a-better-mvc-label-helper
ele possui uma extensão quase perfeita para essa situação, onde será necessário utilizar @Html.FieldLabelFor(m => m.ClienteSt)
lembrando que é necessário adicionar sua classe com @using YourProject.Library.Extensions;
no inicios do .cshtml ou adicionar no web.config (referência: http://stackoverflow.com/a/11897078 )
só não é perfeita para essa situação porque ele adiciona “(optional)” nos campos não obrigatórios e no meu caso preciso de “*” nos campos obrigatórios, então fiz uma pequena alteração no código dele (linha 43)
if (metadata.IsRequired) { htmlBuilder.Append(" <span class='required'>*</span>"); }
isso resolve o problema, mas ainda sim tem uma situação que seria interessante no código dele que não foi adicionado, que seria a questão do class do CSS customizado, entre outros atributos HTML personalizados que poderiam ser adicionados através do helper, então fiz a seguinte alteração:
– adicionei o parâmetro object htmlAttributes no método e alterei a partir da linha 38 para:
StringBuilder htmlBuilder = new StringBuilder(); var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); TagBuilder tag = new TagBuilder("label"); tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(propName)); tag.MergeAttributes(attributes, false);
assim meu helper agora vai me pemitir @Html.FieldLabelFor(c => c.ClienteSt, new { @class = “css-customizado-1 css-customizado-2” })
espero que tenha conseguido explicar bem os códigos e as situações, abaixo segue o código final da minha extensão:
public static class MvcHtmlExtensions { public static MvcHtmlString FieldLabelFor<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression, object htmlAttributes, string labelText) { string propName = ExpressionHelper.GetExpressionText(expression); string unqualifiedPropName = propName.Split('.').Last(); // if there is a . in the name, take the rightmost part. ModelMetadata metadata = html.ViewData.ModelMetadata.Properties.First(p => p.PropertyName == propName); string finallabelText = labelText ?? metadata.DisplayName ?? metadata.PropertyName ?? unqualifiedPropName; if (String.IsNullOrEmpty(finallabelText)) { return MvcHtmlString.Empty; } StringBuilder htmlBuilder = new StringBuilder(); var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); TagBuilder tag = new TagBuilder("label"); tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(propName)); tag.MergeAttributes(attributes, false); htmlBuilder.Append(finallabelText); if (metadata.IsRequired) { htmlBuilder.Append(" <span class='required'>*</span>"); } // Check description in metadatatype too var metaDataType = metadata.ContainerType.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault(); var description = metadata.ContainerType.GetProperty(unqualifiedPropName) .GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault(); // No description attr on model prop, check metadatatype if (description == null && metaDataType != null) { var metaProp = ((MetadataTypeAttribute)metaDataType) .MetadataClassType.GetProperty(unqualifiedPropName); if (metaProp != null) description = metaProp.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault(); } if (description != null) { htmlBuilder.Append(String.Format("<span class=\"note\">{0}</span>", (description as DescriptionAttribute).Description)); } tag.InnerHtml = htmlBuilder.ToString(); return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal)); } public static MvcHtmlString FieldLabelFor<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression, object htmlAttributes) { return FieldLabelFor(html, expression, htmlAttributes, null); } public static MvcHtmlString FieldLabelFor<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression) { return FieldLabelFor(html, expression, null, null); } }
o resultado para @Html.FieldLabelFor(c => c.ClienteSt, new { @class = “col-lg-2 control-label” }) foi esse:
extender o MVC é bem simples e bacaninha, espero que esse post seja muito helps para alguém
qualquer coisa postem nos comentários ou me procurem no twitter @JapaDavid
http://kamranicus.com/Blog/Posts/3/a-better-mvc-label-helper
http://stackoverflow.com/a/11897078