Razor directive to prevent element rendering - asp.net-mvc

I search for an option to render some div-tags in my cshtml files with razor conditionally like the angular directive ng-if.
Normally I write code like
#if (mycond) {
<div>blub</div>
}
And I search for a more readable approach like
<div asmarttag:mycond>blub</div>
Is there any option to achieve that?

Not sure if it's exactly what you want... but what about a custom HTMLHelper?
namespace System.Web.Mvc
{
public static class CustomHTMLHelpers
{
public static IHtmlString Render(this HtmlHelper helper, bool render, string html)
{
if (render)
{
return helper.Raw(html);
}
else
{
return new HtmlString("");
}
}
public static IHtmlString Render(this HtmlHelper helper, bool render, MvcHtmlString html)
{
if (render)
{
return html;
}
else
{
return new HtmlString("");
}
}
}
Then you could do:
#Html.Render(mycond, "<div>blub</div>")
or
#Html.Render(true, #Html.ActionLink("Home", "Index", "Home"))
Would certinly turn it into a one liner for you.

Related

How can I extend MvcForm so that It will not generate a form tag?

I would like to add a condition to a html beginform.
If the condition is false, I dont want the form tag to be generated.
Similar to this code:
public static MvcHtmlString If(this MvcHtmlString value, bool evaluation)
{
return evaluation ? value : MvcHtmlString.Empty;
}
I recently had to do something similar for a one off feature. This is proof of concept code but it looked something like:
public class NoForm : IDisposable
{
// Whatever this suppose to look like
// but actually does nothing
public void Dispose() { }
}
In the view:
#{
IDisposable form;
if (Model canShowForm)
{
form = Html.BeginForm(...);
}
else
{
form = new NoForm()
}
}
#using (form)
{
#* we might be in a form *#
}
Obviously this could be refactored into an HtmlHelper extension method, I just haven't done it.

Creating Generic View Components with Razor

I want to write my own custom HTML helper that extends an existing helper. E.g. I want to create to extend #Html.EditorFor like so:
#Html.EditorFor(model => model.percent, new { data_a_sign="%", data_p_sign="s" })
Becomes:
#Html.PercentEditorFor(model => model.percent)
How would one go about writing that?
Something like this?
namespace AdminPortal.Helpers
{
public static class HtmlHelpers
{
public static MvcHtmlString PercentEditorFor<TModel>(this HtmlHelper html,
Expression<Func<TModel>> expression)
{
// Some Magic?
}
}
}
Any pointers would be greatly appreciated.
It's just a matter of returning the existing EditorFor method from your own helper:
public static MvcHtmlString PercentEditorFor<TModel>(this HtmlHelper html,
Expression<Func<TModel>> expression)
{
return html.EditorFor(...);
}
Put your own modified parameters into the EditorFor method. No magic required :)

.net mvc Display field in view only if it has a value

I have some Customer Details and I only want to show fields which have a value.
For example if Telephone is null don't show it.
I currently have in my view model
public string FormattedTelephone
{
get { return string.IsNullOrEmpty(this.Telephone) ? " " : this.Telephone; }
}
And in my view
#Html.DisplayFor(model => model.FormattedTelephone)
This is working correctly, however, I would like to show the Field Name if the field has a value e.g.
Telephone: 02890777654
If I use #Html.DisplayNameFor in my view it shows the field name even if the field is null.
I also want to style the field name in bold and unsure of where I style it - the view or the view model.
For the bold style you can use this bit of code in your view, but of course it's proper to use an external style sheet.
<style type="text/css">
.telephone{
font-weight: bold;
}
</style>
You can do the check for null in your view and conditionally display the data:
#if (Model.FomattedTelephone != null)
{
<div class="telephone">
#Html.DisplayFor(model => model.FormattedTelephone)</div>
}
For style add a class for to the span you can put around field name.
You could create your own HtmlHelper that will only write if string is not null or empty.
Or you could add a DisplayTemplates something like here:
How do I create a MVC Razor template for DisplayFor()
For more background on helpers in razor read the following
http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx
And if they're in your App_Code folder read the answer to this
Using MVC HtmlHelper extensions from Razor declarative views
You'll probably want to over the default helper page with this (and inherit in your helper classes in App_Code)
public class WorkaroundHelperPage : HelperPage
{
// Workaround - exposes the MVC HtmlHelper instead of the normal helper
public static new HtmlHelper Html
{
get { return ((WebViewPage)WebPageContext.Current.Page).Html; }
}
public static UrlHelper Url
{
get { return ((WebViewPage) WebPageContext.Current.Page).Url; }
}
}
I would make a helper for this, something like this:
using System.Web.Mvc.Html;
public static class HtmlHelpers
{
public static MvcHtmlString LabelDisplayFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
{
StringBuilder html = new StringBuilder();
string disp = helper.DisplayFor(expression).ToString();
if (!string.IsNullOrWhiteSpace(disp))
{
html.AppendLine(helper.DisplayNameFor(expression).ToString());
html.AppendLine(disp);
}
return MvcHtmlString.Create(html.ToString());
}
}
Now, when you are in your View, you can simply do this (given you include the namespace in your view or web.config):
#Html.LabelDisplayFor(model => model.FormattedTelephone)
All it really does is check to see if your display helper is not an empty string, if it is, it will simply append your LabelFor and DisplayFor, if not, it will return an empty string.
I usually prefer to use Display/Editor Templates instead of HtmlHelper. Here is template that I have used to perform exactly the same task, its designed for bootstrap data list but anyone can adjust it easily.
#if (Model == null)
{
#ViewData.ModelMetadata.NullDisplayText
}
else if (ViewData.TemplateInfo.TemplateDepth > 1)
{
#ViewData.ModelMetadata.SimpleDisplayText
}
else
{
<dl class="dl-horizontal">
#foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
{
if(MvcHtmlString.IsNullOrEmpty(Html.Display(prop.PropertyName)))
{
continue;
}
if (prop.HideSurroundingHtml)
{
#Html.Display(prop.PropertyName)
}
else
{
<dt>#prop.GetDisplayName()</dt>
<dd>#Html.Display(prop.PropertyName)</dd>
}
}
</dl>
}
Key line is:
if(MvcHtmlString.IsNullOrEmpty(Html.Display(prop.PropertyName)))
Its based on object template so to use it you need use it on object or whole model like
#Html.DisplayForModel("TemplateName")

Checking if Viewbag property is empty, and using default value in a view

I have this piece of code in a MVC view that works, but it seams like a lot of code to achieve this simple thing. Any way to make it more efficient?
#if (string.IsNullOrEmpty(ViewBag.Name))
{
#:
}
else
{
#:ViewBag.Name
}
#(ViewBag.Name ?? Html.Raw(" "))
Any way to make it more efficient?
Yeah sure, use view models and get rid of the ViewBag:
public string FormattedName
{
get { return string.IsNullOrEmpty(this.Name) ? " " : this.Name; }
}
and then in your strongly typed view:
#Html.DisplayFor(x => x.FormattedName)
or if you prefer:
#Model.FormattedName
Another possibility is to write a custom helper:
public static class HtmlExtensions
{
public static IHtmlString Format(this HtmlHelper html, string data)
{
if (string.IsNullOrEmpty(data))
{
return new HtmlString(" ");
}
return html.Encode(name);
}
}
and then in your view:
#Html.Format(Model.Name)
or if you need to keep the ViewCrap you will have to live with a cast (sorry, .NET doesn't support extension method dispatch on dynamic parameters):
#Html.Format((string)ViewBag.Name)

How can I create a templated control with Asp.Net MVC?

I'm trying to create a templated control with Asp.Net MVC. By templated control, I mean a control that accepts markup as input like so:
<% Html.PanelWithHeader()
.HeaderTitle("My Header")
.Content(() =>
{ %>
<!-- ul used for no particular reason -->
<ul>
<li>A sample</li>
<li>A second item</li>
</ul>
<% }).Render(); %>
Note: Yes, this is very similar to how Telerik creates its MVC controls, I like the syntax.
Here's my PanelWithHeader code:
// Extend the HtmlHelper
public static PanelWithHeaderControl PanelWithHeader(this HtmlHelper helper)
{
return new PanelWithHeaderControl();
}
public class PanelWithHeaderControl
{
private string headerTitle;
private Action getContentTemplateHandler;
public PanelWithHeaderControl HeaderTitle(string headerTitle)
{
this.headerTitle = headerTitle;
return this;
}
public PanelWithHeaderControl Content(Action getContentTemplateHandler)
{
this.getContentTemplateHandler = getContentTemplateHandler;
return this;
}
public void Render()
{
// display headerTitle as <div class="header">headerTitle</div>
getContentTemplateHandler();
}
}
This displays the ul, but I have no idea how to display custom code within my Render method.
I have tried using the HtmlHelper with no success. I have also tried overriding the ToString method to be able to use the <%=Html.PanelWithHeader()... syntax, but I kept having syntax errors.
How can I do this?
public void Render()
{
Response.Write(getContentTemplateHandler());
}
It turns out that the Telerik MVC extensions are open-source and available at CodePlex so I took a quick look at the source code.
They create an HtmlTextWriter from the ViewContext of the HtmlHelper instance. When they write to it, it writes to the page.
The code becomes:
// Extend the HtmlHelper
public static PanelWithHeaderControl PanelWithHeader(this HtmlHelper helper)
{
HtmlTextWriter writer = helper.ViewContext.HttpContext.Request.Browser.CreateHtmlTextWriter(helper.ViewContext.HttpContext.Response.Output);
return new PanelWithHeaderControl(writer);
}
public class PanelWithHeaderControl
{
private HtmlTextWriter writer;
private string headerTitle;
private Action getContentTemplateHandler;
public PanelWithHeaderControl(HtmlTextWriter writer)
{
this.writer = writer;
}
public PanelWithHeaderControl HeaderTitle(string headerTitle)
{
this.headerTitle = headerTitle;
return this;
}
public PanelWithHeaderControl Content(Action getContentTemplateHandler)
{
this.getContentTemplateHandler = getContentTemplateHandler;
return this;
}
public void Render()
{
writer.Write("<div class=\"panel-with-header\"><div class=\"header\">" + headerTitle + "</div><div class=\"content-template\">");
getContentTemplateHandler();
writer.Write("</div></div>");
}
}
*I know, the code is a mess
You might want to do something like Html.BeginPanel() / Html.EndPanel(), similar to how forms are created with Html.BeginForm() / Html.EndForm(). This way you can wrap the contained content rather than need to pass it as a parameter.

Resources