ASP.NET MVC html helper code used to convert model to PropertyName - asp.net-mvc

This code:
#Html.HiddenFor(model => model.Country.CountryId)
gives this output:
<input type="hidden" id="Country_CountryId" name="Country.CountryId" />
Is there a way to get the id of the above code by using just the model? For eg.
#Html.TestBoxFor(model => model.Country.CountryName, new { data_HiddenId= model.Country.CountryId.GetHtmlRenderOrSomething())
which should give this:
<input type="text" id="Country_CountryName" name="Country.CountryName" data-HiddenId="Country_CountryId" />
My main concern is data-HiddenId. I want it to be equal to the id generated for the hidden input above.

You could try this:
#Html.TestBoxFor(
model => model.Country.CountryName,
new {
data_hiddenid = ExpressionHelper.GetExpressionText((Expression<Func<ModelType, int>>)(x => x.Country.CountryId))
}
)
and to reduce the ugliness you could write a custom HTML helper:
public static class HtmlExtensions
{
public static MvcHtmlString TextBoxWithIdFor<TModel, TProperty, TId>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
Expression<Func<TModel, TId>> idExpression
)
{
var id = ExpressionHelper.GetExpressionText(idExpression);
return htmlHelper.TextBoxFor(expression, new { data_hiddenid = id });
}
}
and then simply:
#Html.TestBoxWithIdFor(
model => model.Country.CountryName,
model => model.Country.CountryId
)

Related

How can I use an #HtmlHelper inside a custom #HtmlHelper?

I am trying to create a custom Html helper with ASP.NET MVC. I have the following code:
#helper DefaultRenderer(Models.Control control)
{
<div class="form-group">
<label class="control-label" for="#control.Name">#control.Label</label>
#Html.TextBoxFor(m => control.Value, new { #class = "form-control" })
</div>
}
Apparently #Html.TextBoxFor cannot be found inside a Helper .cshtml class. I can use it in a partial view which is also a .cshtml class.
I can use #HtmlTextBox but then I will lose the strong model binding...
Why is this happening and is there a way to get it to work?
No, this is not possible. You could not write a normal HTML helper with #Html.TextBoxFor because that your view is strongly typed.
So you need something like:
public class HelperExtentions{
public static MvcHtmlString DefaultRenderer<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Control control , object htmlAttributes)
{
var sb = new StringBuilder();
var dtp = htmlHelper.TextBoxFor(expression, htmlAttributes).ToHtmlString();
sb.AppendFormat("<div class='form-group'><label class='control-label' for='{1}'>{2}</label>{0}</div>", dtp,control.Name,control.Label);
return MvcHtmlString.Create(sb.ToString());
}
}
Then you can use :
#html.DefaultRenderer(m => m.Control.Value, Models.Control,new { #class = "form-control" }

ASP.NET MVC - Using Model in Custom HTML Helper [duplicate]

This question already has answers here:
Refactor similar CHTML that renders varying properties using EditorFor and LabelFor
(2 answers)
Closed 6 years ago.
I am building an app with ASP.NET MVC and Bootstrap. In my app, I have a view with a Model that looks like this:
public class EntryModel
{
[Required(ErrorMessage="Please enter the name.")]
[Display(Name="Name")]
public string Name { get; set; }
[Required (ErrorMessage="Please enter the description.")]
[Display(Name = "Description")]
public string Description { get; set; }
}
In this app, I've also defined a custom html helper that looks like this:
public static class MyHelpers
{
public static MvcHtmlString MyTextBox(this HtmlHelper helper)
{
var sb = new StringBuilder();
sb.Append("<div class=\"form-group\">");
sb.Append("<label class=\"control-label\" for=\"[controlId]\">[labelValue]</label>");
sb.Append("<input class=\"form-control\" id=\"[controlId]\" name=\"controlId\" type=\"text\" value=\"[propertyValue]\">");
sb.Append("</div>");
return MvcHtmlString.Create(sb.ToString());
}
}
I'm using this helper and model in my Razor view, like this:
#model EntryModel
<h2>Hello</h2>
#using (Html.BeginForm("Add", "Entry", new {}, FormMethod.Post, new { role="form" }))
{
#Html.MyTextBox()
}
I am trying to generate the labelValue, controlId, and propertyValue values in the helper from the properties of the Model. For example, I'd like to use #Html.MyTextBoxFor(m => m.Name) and have the helper generate something like this:
<div class="form-group">
<label class="control-label" for="Name">Name</label>");
<input class="form-control" id="Name" name="Name" type="text" value="Jon">
</div>
Essentially, I'm not sure how to get my model information into my html helper.
Use this example as reference:
public static MvcHtmlString AutoSizedTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
{
var attributes = new Dictionary<string, Object>();
var memberAccessExpression = (MemberExpression)expression.Body;
var stringLengthAttribs = memberAccessExpression.Member.GetCustomAttributes(
typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute), true);
if (stringLengthAttribs.Length > 0)
{
var length = ((StringLengthAttribute)stringLengthAttribs[0]).MaximumLength;
if (length > 0)
{
attributes.Add("size", length);
attributes.Add("maxlength", length);
}
}
return helper.TextBoxFor(expression, attributes);
}
And you can call it in the view like this:
#Html.AutoSizedTextBoxFor(x => x.Address2)

My FormMethod.Get request is sending multiple values how do I fix this in ASP.net MVC?

I have a mvc5 webpage that has a form method that when the checkbox is checked submits the form and sends the get request. The request header submits the CarNumber and CarId as expected but the checkbox value is sent twice in the header why is this happening? How can I fix the issue.
Header value repeated like this
ShowAllDesignReviews=true&ShowAllDesignReviews=false
#using (Html.BeginForm("Index", "DesignReview", FormMethod.Get))
{
#Html.Hidden("CarNumber", "CarNumber")
#Html.Hidden("CarId", "CarId")
#Html.CheckBoxFor(model => Model.ShowAllDesignReviews, new { #onchange = "this.form.submit()" })
}
This is how CheckBoxFor helper in MVC generates the html, for easy model binding
<input name="ShowAllDesignReviews" type="checkbox" value="true" />
<input name="ShowAllDesignReviews" type="hidden" value="false" />
If you dont select check box, the field will not be posted. To make the value(false) to be passed they used Hidden.
Refer asp.net mvc: why is Html.CheckBox generating an additional hidden input
Better to have your controller that accepts the model
public ActionResult Save(Design model)
{
var boolSet=model.ShowAllDesignReviews;
}
See Murali's answer as to why this happens.
I had some similar scenarios where I wanted to have a "standard" checkbox, so I wrote the following HtmlHelper:
public static class StandardCheckboxForHelper
{
public static MvcHtmlString StandardCheckboxFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> propertyExpression)
{
return html.StandardCheckboxFor(propertyExpression, null);
}
public static MvcHtmlString StandardCheckboxFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> propertyExpression, object htmlAttributes)
{
return html.StandardCheckboxFor(propertyExpression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static MvcHtmlString StandardCheckboxFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> propertyExpression, IDictionary<string, object> htmlAttributes)
{
var propertyName = html.NameFor(propertyExpression).ToString();
var propertyId = html.IdFor(propertyExpression).ToString();
var propertyValueString = html.ValueFor(propertyExpression).ToString();
var propertyValue = ModelMetadata.FromLambdaExpression(propertyExpression, html.ViewData).Model;
var unobtrusiveValidationAttributes = html.GetUnobtrusiveValidationAttributes(propertyName, ModelMetadata.FromLambdaExpression(propertyExpression, html.ViewData));
var checkbox = new TagBuilder("input");
checkbox.MergeAttribute("type", "checkbox");
checkbox.MergeAttribute("id", propertyId);
checkbox.MergeAttribute("name", propertyName);
checkbox.MergeAttributes(unobtrusiveValidationAttributes);
checkbox.MergeAttributes(htmlAttributes);
bool propertyValueConverted;
if ((propertyValue is bool) && (bool) propertyValue)
checkbox.MergeAttribute("checked", "checked");
else if ((propertyValue is bool?) && ((bool?)propertyValue).GetValueOrDefault(false))
checkbox.MergeAttribute("checked", "checked");
else if (bool.TryParse(propertyValueString, out propertyValueConverted) && propertyValueConverted)
checkbox.MergeAttribute("checked", "checked");
return checkbox.ToHtml();
}
}
Usage is the same as the CheckboxFor helper, and it will only render one simple checkbox.

passing html to a function asp.net mvc

I have Html helper method, creating a check box along with some text, I pass.
#Html.CheckBoxFor(x => x.SomeProperty,#<text> <ul> <li> </li> </ul> </text>}))
public static MvcHtmlString CheckBoxFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, bool>> expression, ?? )
{
var chkBox = helper.CheckBoxFor(expression).ToString();
return MvcHtmlString.Create(string.Format("<li>{0}</li><div>{1}</div>", chkBox, ??);
}
What would be the signature of my method then. Some lambda/expression or something.
Help will be appreciated.
Regards
Parminder
I would recommend you looking at templated razor delegates. So in your case the helper might look something along the lines of:
public static MvcHtmlString CheckBoxFor<TModel>(
this HtmlHelper<TModel> helper,
Expression<Func<TModel, bool>> expression,
Func<object, HelperResult> template)
{
var chkBox = helper.CheckBoxFor(expression).ToHtmlString();
return MvcHtmlString.Create(
string.Format("<li>{0}</li><div>{1}</div>", chkBox, template(null))
);
}
and in the view:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.CheckBoxFor(
x => x.SomeProperty,
#<text><ul><li></li></ul></text>
)
<input type="submit" value="OK" />
}
Just string. It's going into string.Format, so that gives you a hint.

get the generated clientid for a form field

Is there a way to get the client id generated for a field generated with a html helper?
i have several components that sometimes are inside another forms, and i wan't to attach javascript events to them.
so, for sample, i would like to have:
#Html.TextBoxFor(model => model.client.email)
<script>
$('##getmyusercontrolid(model=>model.client.email)').val("put your mail here");
</script>
I use this helper:
public static partial class HtmlExtensions
{
public static MvcHtmlString ClientIdFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
return MvcHtmlString.Create(htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(ExpressionHelper.GetExpressionText(expression)));
}
}
Use it just as you would any other helper: #Html.ClientIdFor(model=>model.client.email)
MVC 5 has NameFor, so your example using it is:
#Html.TextBoxFor(model => model.client.email)
<script>
$('##Html.NameFor(model => model.client.email)').val("put your mail here");
</script>
EDIT
IdFor is also available, which may be more appropriate in this situation than NameFor.
Use #Html.IdFor(model => model.client.email) as this functionality already exists like so:
#Html.TextBoxFor(model => model.client.email)
<script>
$('##Html.IdFor(model => model.client.email)').val("put your mail here");
</script>
You can read more about it at the following page:
https://msdn.microsoft.com/en-us/library/hh833709%28v=vs.118%29.aspx
You could try specifying the id in the HtmlAttributes argument when you generate the input field, e.g.
#Html.TextBoxFor(model => model.client.email, new { id = "emailTextBox" })
Then you can use this in your javaScript
var email = $('#emailTextBox').val();

Resources