passing html to a function asp.net mvc - 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.

Related

How to disable #html.Editor() so that it's read only

I'm trying to make some fields editable and some fields read-only based on user permissions (MVC version 5.2.3). I can see a whole bunch of answers on this subject for the #html.EditorFor(), but not plain old #html.Editor(). I've tried the following, none of which have yielded read-only fields:
#Html.Editor(property.Name, new { #disabled = "true" })
#Html.Editor(property.Name, new { #disabled = "disabled" })
Can anyone help me? Thanks very much.
You can write your own extension to receive your boolean property "disabled" as a parameter :
public static class HtmlExtensions
{
public static MvcHtmlString EditorDisabled<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, bool disabled, object htmlAttributes = null)
{
return EditorDisabled(htmlHelper, expression, disabled, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static MvcHtmlString EditorDisabled<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, bool disabled, IDictionary<string, object> htmlAttributes)
{
if (htmlAttributes == null)
htmlAttributes = new Dictionary<string, object>();
if (disabled)
htmlAttributes["disabled"] = "disabled";
return htmlHelper.Editor(expression, htmlAttributes);
}
}
You could just change it from Editor to:
#Html.DisplayFor(model => model.Title)
And it will just pull the value from your model. From there you will just need to implement logic in razor regarding who can see what. EX:
if(Request.IsAuthenticated){
if (isAdmin){
#Html.Editor(model => model.Title)
}
if (isUser){
#Html.DisplayFor(model => model.Title)
}
}
I hope this helps put you on the right path!

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" }

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.

ASP.NET MVC html helper code used to convert model to PropertyName

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
)

Is it possible to create a generic #helper method with Razor?

I am trying to write a helper in Razor that looks like the following:
#helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class
Unfortunately, the parser thinks that <T is the beginning of an HTML element and I end up with a syntax error. Is it possible to create a helper with Razor that is a generic method? If so, what is the syntax?
This is possible to achieve inside a helper file with the #functions syntax but if you want the razor-style readability you are referring to you will also need to call a regular helper to do the HTML fit and finish.
Note that functions in a Helper file are static so you would still need to pass in the HtmlHelper instance from the page if you were intending to use its methods.
e.g.
Views\MyView.cshtml:
#MyHelper.DoSomething(Html, m=>m.Property1)
#MyHelper.DoSomething(Html, m=>m.Property2)
#MyHelper.DoSomething(Html, m=>m.Property3)
App_Code\MyHelper.cshtml:
#using System.Web.Mvc;
#using System.Web.Mvc.Html;
#using System.Linq.Expressions;
#functions
{
public static HelperResult DoSomething<TModel, TItem>(HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr)
{
return TheThingToDo(html.LabelFor(expr), html.EditorFor(expr), html.ValidationMessageFor(expr));
}
}
#helper TheThingToDo(MvcHtmlString label, MvcHtmlString textbox, MvcHtmlString validationMessage)
{
<p>
#label
<br />
#textbox
#validationMessage
</p>
}
...
No, this is not currently possible. You could write a normal HTML helper instead.
public static MvcHtmlString DoSomething<T, U>(
this HtmlHelper htmlHelper,
Expression<Func<T, U>> expr
) where T : class
{
...
}
and then:
#(Html.DoSomething<SomeModel, string>(x => x.SomeProperty))
or if you are targeting the model as first generic argument:
public static MvcHtmlString DoSomething<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expr
) where TModel : class
{
...
}
which will allow you to invoke it like this (assuming of course that your view is strongly typed, but that's a safe assumption because all views should be strongly typed anyways :-)):
#Html.DoSomething(x => x.SomeProperty)
In all cases the TModel will be the same (the model declared for the view), and in my case, the TValue was going to be the same, so I was able to declare the Expression argument type:
#helper FormRow(Expression<Func<MyViewModel, MyClass>> expression) {
<div class="form-group">
#(Html.LabelFor(expression, new { #class = "control-label col-sm-6 text-right" }))
<div class="col-sm-6">
#Html.EnumDropDownListFor(expression, new { #class = "form-control" })
</div>
#Html.ValidationMessageFor(expression)
</div>
}
If your model fields are all string, then you can replace MyClass with string.
It might not be bad to define two or three helpers with the TValue defined, but if you have any more that would generate some ugly code, I didn't really find a good solution. I tried wrapping the #helper from a function I put inside the #functions {} block, but I never got it to work down that path.
if your main problem is to get name attribute value for binding using lambda expression seems like the #Html.TextBoxFor(x => x.MyPoperty), and if your component having very complex html tags and should be implemented on razor helper, then why don't just create an extension method of HtmlHelper<TModel> to resolve the binding name:
namespace System.Web.Mvc
{
public static class MyHelpers
{
public static string GetNameForBinding<TModel, TProperty>
(this HtmlHelper<TModel> model,
Expression<Func<TModel, TProperty>> property)
{
return ExpressionHelper.GetExpressionText(property);
}
}
}
your razor helper should be like usual:
#helper MyComponent(string name)
{
<input name="#name" type="text"/>
}
then here you can use it
#TheHelper.MyComponent(Html.GetNameForBinding(x => x.MyProperty))

Resources