binding inside html helper - asp.net-mvc

i want to bind to the display style property of my Html.TextBox
<%= Html.TextBox("RunDates", Model.RunDates, new { style = "display: none" })%>
is this possible? i want to do something like the following that i know works for me:
<input id="btnBack" class="btnAction" type="button" value="Back" style="display: <%= Model.IsEnabledProductSetupBack?"inline":"none" %>;" />
or is there a way to post <input type="text" ... in mvc?

You could write a custom Html helper for this. There are 2 possibilities:
You replace this weakly typed TextBox helper with strongly typed TextBoxFor by taking advantage of a view model (which is what I would recommend) in which case you will be able to write your textbox like this:
<%= Html.MyTextBoxFor(x => x.RunDates) %>
You stick with weak typing in which case the best you could get is this:
<%= Html.TextBox("RunDates", Model.RunDates, Html.SelectStyle(Model.IsEnabledProductSetupBack)) %>
Now since I recommend the first solution, it is the one I would provide same code for:
public static class HtmlExtensions
{
public static IHtmlString MyTextBoxFor<TProperty>(
this HtmlHelper<MyViewModel> helper,
Expression<Func<MyViewModel, TProperty>> ex
)
{
var model = helper.ViewData.Model;
var htmlAttributes = new RouteValueDictionary();
htmlAttributes["style"] = "display: none;";
if (model.IsEnabledProductSetupBack)
{
htmlAttributes["style"] = "display: inline;";
}
return helper.TextBoxFor(ex, htmlAttributes);
}
}

Related

Asp.Net Razor View Passing Expression To Partial

I find myself writing this a whole lot in my views:
<div class="form-group">
#Html.LabelFor(x => x.City)
#Html.EditorFor(x => x.City)
#Html.ValidationMessageFor(x => x.City)
</div>
I'd really like to put this in a Partial _Field.cshtml, something like this:
#model //what model type???
<div class="form-group">
#Html.LabelFor(Model)
#Html.EditorFor(Model)
#Html.ValidationMessageFor(Model)
</div>
That could then be called by:
#Html.Partial("_Field", x => x.City)
What would the #model type in my partial be if I wanted to accomplish something like this?
UPDATE This works, but I'd rather use a partial for ease of changing the template:
public static MvcHtmlString Field<TModel, TItem>(this HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr)
{
var h = "<div class='form-group'>";
h += $"{html.LabelFor(expr)}{html.EditorFor(expr)}{html.ValidationMessageFor(expr)}";
h += "</div>";
return MvcHtmlString.Create(h);
}
That's not possible. However, what you want is very similar to editor templates. Essentially, you just create a view in Views/Shared/EditorTemplates named after one of the following conventions:
A system or custom type (String.cshtml, Int32.cshtml, MyAwesomeClass.cshtml, etc.)
One of the members of the DataType enum (EmailAddress.cshtml, Html.cshtml, PhoneNumber.cshtml, etc.). You would then apply the appropriate DataType attributes to your properties:
[DataType(DataType.EmailAdress)]
public string Email { get; set; }
Any thing you want, in conjunction with the UIHint attribute:
[UIHint("Foo")]
public string Foo { get; set; }
Which would then correspond to a Foo.cshtml editor template
In your views, then, you simply use Html.EditorFor:
#Html.EditorFor(x => x.City)
Then, for example, you could have Views/Shared/EditorTemplates/String.cshtml as:
<div class="form-group">
#Html.Label("", new { #class = "control-label" })
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { #class = "form-control" })
#Html.ValidationMessage("")
</div>
(The empty quotes are placeholders. Razor will automatically fill in the appropriate property name, thankfully.)
Calling EditorFor, then, will print all of this, rather than just the default text input. You can take this much further, as well. I have some articles on my blog that goes into greater detail, if you're interested.
UPDATE
It's worth mentioning a few features of EditorFor:
You can pass a template directly to the call, meaning you can customize what template is used on the fly and per instance:
#Html.EditorFor(x => x.City, "MyCustomEditorTemplate")
You can pass additionalViewData. The members of this anonymous object are added to the ViewData dynamic dictionary. Potentially, you could use this to branch within your editor template to cover additional scenarios. For example:
#Html.EditorFor(x => x.City, new { formGroup = false })
Then in your editor template:
#{ var formGroup = ViewData["formGroup"] as bool? ?? true; }
#if (formGroup)
{
<!-- Bootstrap form group -->
}
else
{
<!-- Just the input -->
}

ASP.NET MVC 3 diplay label + data in readonly scenario using templated HtmlHelpers

I need to display short description like label and near it data associated with this description.
For editing data it looks like
<div class="field">
#Html.LabelFor(m => m.CustomerTaxId)
#Html.EditorFor(m => m.CustomerTaxId)
</div>
Now I want to do the same thing for readonly data. I've written next code
<div>
#Html.LabelFor(m => m.TotalAmount)
#Html.DisplayFor(m => m.TotalAmount)
</div>
It seems working but it breaks semantic meaning of label tag which must be used for input tags only.
Is there a way in MVC 3 to get something like
<div>
<span class="label">Total amount</span>
<span class="value">1500.00 $</span>
</div>
with minimal efforts (think it can be done with heavy template usage)
It seems like I can overwrite template for Html.DisplayFor how to deal with Html.LabelFor?
You can create custom html helper as below,
public static MvcHtmlString Span<TModel, TValue>(this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression, object htmlAttributes)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData, null);
string spanInnerText = metadata.DisplayName ?? metadata.PropertyName;
TagBuilder tag = new TagBuilder("span");
tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
tag.SetInnerText(spanInnerText);
return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
}
You could use in a view as,
#Html.Span(m => m.Name, new { #class = "label" })

MVC : Set disabled or no for a textbox in HTMLAttribute

In my HTML file, I have a textbox which must be disabled or enable, depending on my controller value.
No problem to set it in disabled mode, but to set it enable...
this is my code :
<%= Html.TextBoxFor(model => model.test, new Dictionary<string, object> { { "disabled", ViewContext.RouteData.Values["controller"].ToString() == "MyTest" ? "" : "disabled"}}
I have seen some ideas on this question : here
mvccontrib.FluentHtml or InputExtensions are the single solutions, to answer to my question ???
Im using "disabled" but I can use "read-only" attribute... the goal of this code is not to allow the user to fill the text box...
Thanks for your advices on the subject.
Just break the line apart into something like this:
<%
if (MyConditionIsTrue)
Response.Write(Html.TextBoxFor(model => model.test, new { disabled = "true" }));
else
Response.Write(Html.TextBoxFor(model => model.test));
%>
That's a good candidate for a custom HTML helper:
public static class HtmlExtensions
{
public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> ex)
{
var controller = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");
var htmlAttributes = new Dictionary<string, object>();
if (string.Equals(controller, "MyTest", StringComparison.OrdinalIgnoreCase))
{
htmlAttributes["disabled"] = "disabled";
}
return htmlHelper.TextBoxFor(ex, htmlAttributes);
}
}
and then:
<%= Html.CustomTextBoxFor(model => model.test) %>
People love Html helpers, but you don't have to use them.
#if (MyConditionIsTrue) {
<input id="test" name="test" value="#Model.test" disabled="disabled" />
}
else {
<input id="test" name="test" value="#Model.test" />
}
If you have to reuse this logic many times, a html helper is probably a good idea. If you're just doing it once, it might not be.
disabled
or
disabled = disabled
or
disabled = true
or
disabled = false
or
disabled = enable
all of the above means disabled.
remove disabled from the element to enable that.
if(condition)
<input .... disabled/>
else
<input ..... />

asp.net mvc Ajax.BeginForm clone

I'm using asp.net mvc ajax.
The partial view is using Ajax.BeginForm (just an example):
<div id="divPlaceholder">
<% using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "divPlaceholder" })) { %>
... asp.net mvc controls and validation messages
<input type="submit" value="Save" />
<% } %>
</div>
After update, if validation fails, the html is:
<div id="divPlaceholder">
<div id="divPlaceholder">
...form
</div>
</div>
I don't like that the returned html is inserted, instead it should replace original div.
Probably on POST I should not render <div> around form in partial view or render the div without id.
What else can I do in this situation?
I was thinking that maybe I should write a helper, something like Ajax.DivBeginForm, which will render form inside div on GET and hide the div on POST.
Can somebody provide a good advice how to write such helper (Ajax.DivBeginForm)?
I'd like it to work with using keyword:
<% using (Ajax.DivBeginForm(new AjaxOptions { UpdateTargetId = "myId" })) { ... }%>
My solution. Please comment if something is wrong.
public class DivMvcForm : MvcForm
{
private bool _disposed;
private MvcForm mvcForm;
private ViewContext viewContext;
public DivMvcForm(MvcForm mvcForm, ViewContext viewContext) : base(viewContext)
{
this.mvcForm = mvcForm;
this.viewContext = viewContext;
}
protected override void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
mvcForm.EndForm();
viewContext.Writer.Write("</div>");
}
}
}
Helper
public static class AjaxHelperExtensions
{
public static MvcForm DivBeginForm(this AjaxHelper ajaxHelper, AjaxOptions ajaxOptions)
{
var tagBuilder = new TagBuilder("div");
if (ajaxHelper.ViewContext.HttpContext.Request.RequestType == "GET"
&& string.IsNullOrWhiteSpace(ajaxOptions.UpdateTargetId) != true)
{
tagBuilder.MergeAttribute("id", ajaxOptions.UpdateTargetId);
}
ajaxHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
var theForm = ajaxHelper.BeginForm(ajaxOptions);
return new DivMvcForm(theForm, ajaxHelper.ViewContext);
}
}
And how it works
<% using (Ajax.DivBeginForm(new AjaxOptions { UpdateTargetId = "divPlaceholder" })) { %>
... controls
<% } %>
Result - when ModelState is invalid the partial view returns div without id.
I'm going to take a little different approach here, rather than getting your original solution to work, I'd recommend using the pattern normally followed in this scenario and not using a helper. I realize this is a bit later than the original post, but for future use by anyone : )
If your partial view has a form, then you will keep posting, and returning a form in a form in a form in a form, etc. so you want to have your PARENT contain BeginForm, the div, and renderpartial
using (Ajax.BeginForm("Index", "ProjectManager", new AjaxOptions() ....
<div id="divPlaceholder">
Html.RenderPartial(....)
</div>
If you want to encapsulate this logic in say, an "Order" partial view that is displayed on a Customer screen, then you have two options.
1. Include the BeginForm on the parent Customer view (which reduces code reusability as any view that wants to include the "Order" partial view must include the ajax wiring.
Or
2. You have two partial views for order. One is OrderIndex.ascx (or cshtml if razor) and one is OrderIndexDetail.ascx (or whatever naming convention you decide)
OrderIndex contains your Ajax.beginform and OrderIndexDetail has no form, only the partial view details.
Option 2 is more code (ok, literally about 30 more seconds of coding to move the ajax.beginform into another view) but increases code reusability.
You can handle submit form yourself:
<div id="divPlaceholder">
<% using (Html.BeginForm("action", "controller", FormMethod.Post, new { id = "submitForm"})) { %>
... asp.net mvc controls and validation messages
<input type="submit" value="Save" />
<% } %>
</div>
and write some javascript as:
$('#submitForm').submit(function() {
$.post('post-to-this-url',
data: { foo: formvalue1, bar: formvalue2},
function(data) {
// update html here
});
return false;
})

PartialView Dynamic BeginForm Parameters

If I have the below PartialView
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.Photo>" %>
<% using (Html.BeginForm("MyAction", "MyController", FormMethod.Post, new { enctype = "multipart/form-data" })) { %>
<%= Html.EditorFor( c => c.Caption ) %>
<div class="editField">
<label for="file" class="label">Select photo:</label>
<input type="file" id="file" name="file" class="field" style="width:300px;"/>
</div>
<input type="submit" value="Add photo"/>
<%} %>
As you can see, the Action and the Controller are hard coded. Is there a way I can make them dynamic?
My goal is to have this partial view generic enough that I can use it in many places and have it submit to the Action and Controller it is sitting within.
I know I can use ViewData but really don't want to and likewise with passing a VormViewModel to the view and using the model properties.
Is there a nicer way than the two I listed above?
I Checked the source code of MVC and dig into the System.Web.Mvc --> Mvc --> Html --> FormExtensions so I find you can write some code like :
public static class FormHelpers
{
public static MvcForm BeginFormImage(this HtmlHelper htmlHelper, IDictionary<string, object> htmlAttributes)
{
string formAction = htmlHelper.ViewContext.HttpContext.Request.RawUrl;
return FormHelper(htmlHelper, formAction, FormMethod.Post, htmlAttributes);
}
public static MvcForm FormHelper(this HtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes)
{
TagBuilder tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttributes(htmlAttributes);
// action is implicitly generated, so htmlAttributes take precedence.
tagBuilder.MergeAttribute("action", formAction);
tagBuilder.MergeAttribute("enctype", "multipart/form-data");
// method is an explicit parameter, so it takes precedence over the htmlAttributes.
tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
MvcForm theForm = new MvcForm(htmlHelper.ViewContext);
if (htmlHelper.ViewContext.ClientValidationEnabled)
{
htmlHelper.ViewContext.FormContext.FormId = tagBuilder.Attributes["id"];
}
return theForm;
}
}
I'm not sure this is exactly what you really want to get but I'm sure you can get it if you change this lines in way satisfies your needs.
Hope this helps.

Resources