I have this line of code:
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })
I have a variable in my view data dictionary called Readonly. How do I make Quantity read-only if ViewBag.Readonly
is true and not read only if it is false?
Simple thing, but the combination of Razor with HTML (which is ancient) makes otherwise simple things impossible.
Edits:
I don't want to use an if statement. That is a last resort because it violates DRY which I have been severely burned many times in the past for not following.
The line I have above does work insofar as it makes the text box read-only. I need to make this conditional based upon my view state.
Solution:
I've used the following. It still is a DRY violation, but it reduces it to one line.
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = ViewBag.Readonly ? (object)new { @class = "form-control", @readonly = "htmlsucks" } : (object)new { @class = "form-control" } })
EditorFor does not allow for styling as there are no parameters for additional attributes. The reason for this is because the EditorFor doesn't always generate a single element as it can be overridden. To style a specific type of element you need to use the specific editor you want to use.
EditorFor<TModel,TValue>(HtmlHelper<TModel>, Expression<Func<TModel,TValue>>, String, String, Object) Returns an HTML input element for each property in the object that is represented by the expression, using the specified template, HTML field name, and additional view data.
EDIT: MVC 5
Controller
ViewBag.Readonly=true;//false
View
@Html.EditorFor(model => model.Quantity, ViewBag.Readonly ? (object)new { htmlAttributes = new { @readonly = "readonly", @class = "form-control" }} : new { htmlAttributes = new { @class = "form-control" } })
It's very simple. Do it like this.
@if((bool)ViewBag.Readonly)
{
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })
}
else
{
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control" } })
}
Today I had to deal with this issue as I had to dynamically set a "readonly" attribute to a Html.TextBoxFor
element. I ended up writing the following helper method which allowed me to workaround the issue while keeping a DRY approach:
/// <summary>
/// Gets an object containing a htmlAttributes collection for any Razor HTML helper component,
/// supporting a static set (anonymous object) and/or a dynamic set (Dictionary)
/// </summary>
/// <param name="fixedHtmlAttributes">A fixed set of htmlAttributes (anonymous object)</param>
/// <param name="dynamicHtmlAttributes">A dynamic set of htmlAttributes (Dictionary)</param>
/// <returns>A collection of htmlAttributes including a merge of the given set(s)</returns>
public static IDictionary<string, object> GetHtmlAttributes(
object fixedHtmlAttributes = null,
IDictionary<string, object> dynamicHtmlAttributes = null
)
{
var rvd = (fixedHtmlAttributes == null)
? new RouteValueDictionary()
: HtmlHelper.AnonymousObjectToHtmlAttributes(fixedHtmlAttributes);
if (dynamicHtmlAttributes != null)
{
foreach (KeyValuePair<string, object> kvp in dynamicHtmlAttributes)
rvd[kvp.Key] = kvp.Value;
}
return rvd;
}
It can be used in the following way:
var dic = new Dictionary<string,object>();
if (IsReadOnly()) dic.Add("readonly", "readonly");
Html.TextBoxFor(m => m.Name, GetHtmlAttributes(new { @class="someclass" }, dic))
The code is quite self-explanatory, however I also explained the underlying logic in this post on my blog.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With