Introduction
How do we make an entire Web Page editable or readonly based on certain conditions without using a bunch of If else
conditions? While searching for an answer to this question, I came across lots of ways, i.e., as follows:
- We can create two different views and can call based on the required condition:
@if (readonly)
{
@Html.DisplayForView()
}
else
{
@Html.EditorForView()
}
In this, we will need to create two different partial views, which seems to be code redundancy.
- The second approach I found is to set the
If else
condition in the @Html.Control
:
@Html.EditorFor(x => x.Name,IsReadonly ? (object) new
{ htmlAttributes = new { @readonly = "readonly"} }
: new { htmlAttributes = new { @readonly = ""} })
In this case, if my form has multiple EditorFor
, then it becomes a tedious job to do the conditioning and also, your view becomes clumsy and heavy.
So just to manage everything in one place, I created a Custom HTML Helper and set the readonly
attribute based on the Page Mode which I managed to pass using ViewBag
. Following is the code for the same.
Index.cshtml
@{
Layout = null;
}
@using CustomHTMLHelperPageMode.Helper
@model CustomHTMLHelperPageMode.Models.User
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<!--
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!--
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
</head>
<body>
<div>
@using (Html.BeginForm())
{
<div class="container">
<div class="form-group">
@Html.LabelFor(model => model.Name)
@Html.PageModeTextBoxFor(model => model.Name,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="form-group">
@Html.LabelFor(model => model.Phone)
@Html.PageModeTextBoxFor(model => model.Phone,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="form-group">
@Html.LabelFor(model => model.Email)
@Html.PageModeTextBoxFor(model => model.Email,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="form-group">
@Html.LabelFor(model => model.Address)
@Html.PageModeTextBoxFor(model => model.Address,
new { htmlAttributes = new { @class = "form-control" } })
</div>
@if (ViewBag.PageMode != "View")
{
<input type="submit" value="Create" class="btn btn-default" />
}
</div>
}
</div>
</body>
</html>
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace CustomHTMLHelperPageMode.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult ViewIndex()
{
ViewBag.PageMode = "View";
return View("Index");
}
}
}
PageModeTextBox.cs (Helper)
using System;
using System.Collections.Generic;
using System.Web.Mvc.Html;
namespace CustomHTMLHelperPageMode.Helper
{
public static class PageModeTextBox
{
public static System.Web.Mvc.MvcHtmlString PageModeTextBoxFor<TModel, TValue>
(this System.Web.Mvc.HtmlHelper<TModel> html,
System.Linq.Expressions.Expression<Func<TModel, TValue>> expression,
object htmlAttributes = null, bool readOnly = false)
{
System.Web.Mvc.ModelMetadata oModelMetadata =
System.Web.Mvc.ModelMetadata.FromLambdaExpression(expression, html.ViewData);
Dictionary<string, object> dynamicAttribute = new Dictionary<string, object>();
foreach(var prop in htmlAttributes.GetType().GetProperties())
{
if(prop.Name== "htmlAttributes")
{
var propValue = prop.GetValue(htmlAttributes, null);
foreach (var innerProp in propValue.GetType().GetProperties())
{
dynamicAttribute.Add(innerProp.Name, innerProp.GetValue(propValue, null));
}
}
else
{
dynamicAttribute.Add(prop.Name, prop.GetValue(prop));
}
}
if (html.ViewBag.PageMode == "View")
{
if (dynamicAttribute.ContainsKey("readonly") == false)
{
dynamicAttribute.Add("readonly", "read-only");
}
}
return (html.TextBoxFor(expression, dynamicAttribute));
}
}
}
User.cs (Model)
using System.ComponentModel;
namespace CustomHTMLHelperPageMode.Models
{
public class User
{
[DisplayName("Name")]
public string Name { get; set; }
[DisplayName("Contact No")]
public string Phone { get; set; }
[DisplayName("Email")]
public string Email { get; set; }
[DisplayName("Address")]
public string Address { get; set; }
}
}
Edit Mode
View Mode
The sample code is available on GitHub.
If any of the readers have an improved and better workflow for the above requirement, I would like to add the same to my knowledge.
CODE IT !!!