html helper - how do I get rid of the name attribute? - asp.net-mvc

I have a strongly typed partial view. The model has a property that is a list of users in Active Directory represented by a class called ADUser.
I have a partial view that represents a drop down list for this property. While I use the value of this drop list for some other things, I have no need to submit its value, so I thought I would remove the name attribute. However, once the Html loads, the name attribute is always set to what the Html helper wants to assign it. Is there a way I can remove that attribute so that the drop down's value doesn't submit?
In my main partial view (_adusers is the name of the list):
<%: Html.Partial("ADUserDropDown", Model._adusers)%>
In my drop down's partial view:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<MyProject.Models.ADUser>>" %>
<%= Html.DropDownList("", new SelectList(Model, "ValueText", "DisplayText"), new { name = "", size = "12" })%>
<input type=button value="Search..." />
<input type=button value="Close" />
This results in:
<select name="_master" size="12">
_master being the name of the parent model. If I add something to the first parameter of Html.DropDownList, it results in:
<select name="_master.WhateverINamedIt" size="12">
I want to achieve:
<select size="12">

There is no point of using the HTML helper then. You can change the code of the partial view to:
<select size="12">
#foreach(var item in Model)
{
<option value="#item.ValueText">#Html.DisplayFor(m => item.DisplayText)</option>
}
</select>
However if you want to stick with the DropDownList helper the name parameter in the html attributes has to be specified with the capital letter:
<%= Html.DropDownList("", new SelectList(Model, "ValueText", "DisplayText"),
new { Name = string.Empty, size = "12" })%>
As an alternative you can remove the name with jQuery:
$('[name="_master.WhateverINamedIt"]').removeAttr('name');
Don't like or use jQuery, the plain javascript will do the job:
document.getElementsByName('_master.WhateverINamedIt')[0].removeAttribute('name');

Related

Build list of data validation attributes for a given element

When using any of the Input Extension Helper Methods, like #Html.TextboxFor, any Validation Attributes from your model are automatically generated by the Razor engine (via ClientValidationEnabled/UnobtrusiveJavaScriptEnabled).
For example, take the following case which works fine
Model:
[Required]
public string QuestionOne { get; set; }
View:
#Html.TextBoxFor(model => model.QuestionOne)
#Html.ValidationMessageFor(model => model.QuestionOne)
Generated Markup:
<input type="text" id="QuestionOne" name="QuestionOne" value=""
data-val="true" data-val-required="The QuestionOne field is required." >
<span class="field-validation-valid" data-valmsg-for="QuestionOne" data-valmsg-replace="true"></span>
In this case the attributes data-val="true" & data-val-required="The QuestionOne field is required." are picked up by Unobtrusive validation and the form element is successfully validated.
However, for extensibility reasons, I want to be able to generate the <input> element myself instead of using TextBoxFor. So my view would now look like this:
<input type="textbox"
id="#Html.IdFor(m => m.QuestionTwo)"
name="#Html.NameFor(m => m.QuestionTwo)"
value="#Model.QuestionTwo"
data-val="true" data-val-required="Selection is Required" />
#Html.ValidationMessageFor(model => model.QuestionTwo)
In this case, I'm faking the validation attribute output by just re-writing data-val="true" (etc) by hand, but this would have to be expanded to cover every single case.
Here's a running Demo in .NET Fiddle
Q: Can I build /return a list of data-val-* attributes for a given element?
You can use the GetUnobtrusiveValidationAttributes() method of HtmlHelper to get the validation attributes associated with a specific property.
For example in the view
#{ var attributes = Html.GetUnobtrusiveValidationAttributes("QuestionTwo"); }
<input
type="textbox"
#foreach(var attr in attributes)
{
#:#attr.Key="#attr.Value"
}
id="#Html.IdFor(m => m.QuestionTwo)"
....
/>
Note the #:#attr.Key="#attr.Value" line will give a warning (Missing attribute name) but will run correctly
Alternatively, you could use javaScript/jQuery to add the attributes
<script type="text/javascript">
var attributes = #Html.Raw(Json.Encode(attributes));
var input = $('#QuestionTwo');
for(var i in attributes) {
input.attr(i, attributes[i]);
}
</script>
I have forked the DotNetFiddle here to show the working code for both options.
While the above code shows how it can be done, you should not be doing that. The HtmlHelper methods execute a lot of code your ignoring to ensure correct 2-way model binding, for example, the value attribute is determined by first checking for a value in ModelState, then in the ViewDataDictionary, and only if the previous values do not exist, does it use the value of the property (the second part of TextBoxFor displaying initial value, not the value updated from code explains the behavior).
Except for the incorrect value attribute, the code you have shown for the <input> is the same as will be generated by simply using #Html.TextBoxFor(m => m.Question2). I assume your real case is different, but if you cannot make use of TextBoxFor() and using an overload that accepts htmlAttributes to generate the html you need, then the correct approach is to create your own HtmlHelper method (and making use of existing methods in the HtmlHelper class and System.Web.Mvc.Html namespace)

How to assign a dynamic value to the label helper in asp.net MVC

I am working on a Asp.net MVC 2.0 web application. In my form , i have non editable fields , so i wanted to display them as labels rather than textboxes.
I am strongly binding my model with view. So, i need to associate this label with one of the fields in model.
This is what i am trying to do:
<%=html.LabelFor(model=>model.changedby)%>
<%=html.DisplayFor(model=>model.changedby,XYZ)%>
But, it is displaying nothing..Please help
Updated2:
What basically i am trying to do is a add operation. i have a create view and that view has a form.
I am strongly binding this view with model.So , that i can directly associate form fields with the model Properties.
Ex:
<label> Name</label> <%=Html.TextBoxFor(m=>m.name)
So, what ever i type into the textbox , it will be stored in m.name in the model.
If the text entered is "Avinash" , then m.name gives value "Avinash"
I think i am correct upto this extent:
Similarly..
I have a field which is readonly , the user can not change the value of it.
<label>Changed On</label> <label> DateTime.Now </label>
How to bind m.ChangedOn with the labels values(DateTme.Now)
so that it will result in m.Changedon as DateTime.now
Updated3:
This is what i am writing..
<td >
<%=Html.LabelFor(Model=>Model.CreatedOn) %>:
</td>
<td>
<%=Html.HiddenFor(Model=>Model.CreatedOn) %>
</td>
You no need to wrap with <label>, since MVC LabelFor will automatically create those html tags for you
So change this
<label>
<%=html.LabelFor(model=>model.changedby)%>
</label>
to
<%= Html.LabelFor(model=>model.changedby) %>
Update:
If you want to send the data to the server while you post your form, make sure you have a data in a form fields. Only form fields like input,select,textarea are posted to server and not display tag value like label, span, div, etc
Still if you need to post the label value, you can use hidden with it
<%= Html.LabelFor(model=>model.changedby) %>
<%= Html.HiddenFor(model=>model.changedby) %>
If you have both, your hidden field will posted to server, which contains the same value
Controller code
public ActionResult Index()
{
MyviewModel model=new MyviewModel();
model.ChangedOn=DateTime.Now;
return View(model);
}
For Save
public ActionResult Save(MyviewModel model)
{
model.ChangedOn; // this property will show you hidden value
//If you need current time, since the rendered time was old. Its good to assign like below
//model.ChangedOn=DateTime.Now
}
use this
<%= Html.DisplayFor(model => model.changedby) %>

DropDownListFor not selecting the selected item in the SelectList

I am working on an ASP.NET MVC3 application and I cannot get a DropDownListFor to work with my property in a particular editor view.
My model is a Person and a person has a property that specifies it's "Person Type". PersonType is a class that contains a name/description and an ID. I can access the available PersonTypes within the application through my static/shared class called ApplicationSettings.
In the Edit Template view for my Person I have created a SelectList for debugging purposes:
#ModelType MyNamespace.Person
#Code
Dim pTypesSelectList As New SelectList(MyNamespace.ApplicationSettings.PersonTypes, "ID", "Name", Model.PersonType.ID)
End Code
I am then providing this SelectList as a parameter to the DropDownListFor that is bound to the PersonType property of my Person.
I am also printing the Selected property of each item in the SelectList for debugging purposes:
<div style="text-align: center; margin: 5px 0 0 0;">
<div>
#Html.LabelFor(Function(model) model.PersonType)
</div>
<div>
#Html.DropDownListFor(Function(model) model.PersonType, pTypesSelectList)
#Html.ValidationMessageFor(Function(model) model.PersonType)
<br />
<br />
<!-- The following is debugging code that shows the actual value-->
#Model.Type.Name
<br />
#Model.Type.ID
<br />
<br />
<!--This section is to show that the select list has properly selected the value-->
#For Each pitem In pTypesSelectList
#<div>
#pitem.Text selected: #pitem.Selected
</div>
Next
</div>
</div>
The view is bound to a Person whose PersonType property is "Person Type # 2" and I expect this to be selected; however the HTML output of this code looks like this:
<div style="text-align: center; margin: 5px 0 0 0;">
<div>
<label for="PersonType">PersonType</label>
</div>
<div>
<select id="PersonType" name="PersonType">
<option value="7e750688-7e00-eeee-0000-007e7506887e">Default Person Type</option>
<option value="87e5f686-990e-5151-0151-65fa7506887e">Person Type # 1</option>
<option value="a7b91cb6-2048-4b5b-8b60-a1456ba4134a">Person Type # 2</option>
<option value="8a147405-8725-4b53-b4b8-3541c2391ca9">Person Type # 3</option>
</select>
<span class="field-validation-valid" data-valmsg-for="PersonType" data-valmsg-replace="true"></span>
<br />
<br />
<!-- The following is debugging code that shows the actual value-->
Person Type # 2
<br />
a7b91cb6-2048-4b5b-8b60-a1456ba4134a
<br />
<br />
<!--This section is to show that the select list has properly selected the value-->
<div>
Default Person Type selected: False
</div>
<div>
Person Type # 1 selected: False
</div>
<div>
Person Type # 2 selected: True
</div>
<div>
Person Type # 3 selected: False
</div>
</div>
</div>
As you can see the printed Selected properties for the items in the SelectList shows that the 3rd item is "Selected". But what is driving me crazy is that the option that corresponds with this is Not Selected.
Generally, the Selected property in SelectList will be totally ignored by the HTML helpers unless there's no other option. If DropDownListFor can find the value by other means, it will insist on using that value.
In this case, it will use the value of model.PersonType(.ToString()) - but that's not what you want, judging by the model.PersonType.ID you pass to the SelectList.
More info in the answer here.
Workaround
One easy workaround that should work would be to set:
ViewData["PersonType"] = model.PersonType.Id.
The helper looks in ModelState first if it exists - i.e. on POST. This should work already, since ModelState["PersonType"] will be populated with the actual selected value that was posted.
After ModelState it will look in ViewData - with ViewData["PersonType"] first, and only then ViewData.Model.PersonType. In other words, you can "override" the value on your model with a value set directly on ViewData.
Better (IMO) solution
The more general, "better practice", way to solve it (which also avoids having a custom model binder in order to translate the POST'ed ID back to PersonType) is to use a ViewModel instead of working with full models in your view:
Have a PersonTypeID property - instead of PersonType.
Populate it with PersonType.ID
use this in your view
VB.NET: Html.DropDownListFor(Function(model) model.PersonTypeID), or
C#: Html.DropDownListFor(model => model.PersonTypeID)
When form is POST'ed, translate the ViewModel (including PersonTypeID => PersonType) back into the actual model in your POST Action.
This may seem like more work, but generally there tend to be many occasions in a project where you need more view-specific representations of your data to avoid too much inline Razor code - so translating from business objects to view models, while it may seem redundant and anti-DRY at times, tends to spare you of a lot of headaches.
Are you sure that your ModelState for "PersonType" key before rendering the view is empty? As JimmiTh commented is going to search for the value in the ModelState first. It happened to me too, you can try
#Html.DropDownList("PersonTypeFake", Function(model) model.PersonType, pTypesSelectList) and it should select the right option.

Using EditorFor in ASP.NET MVC 2.0 to render a span

I have a complex object that if I render in this way:
<%=Html.EditorFor(x => x.ContactRoleDto.Competencies[0].Name) %>
The above generates the following element which has the name and id tags that I want:
<input Size="40" id="ContactRoleDto_Name" maxlength="100" name="ContactRoleDto.Name" type="text" value="" />
I would like to render a tag with the correct id and name attributes that are in the same form as above, i.e. ContactRoleDto.Competencies[0].Name".
How is the best way to achieve this?
All I really want is the ability to pull out the correct id and name fields that will help me model bind a table that is dynamically generated or rendered.
Is ModelMetaData the best way to go, I do not want to go the UIHint route.
You could use the ExpressionHelper.GetExpressionText method. For example:
Expression<Func<string, YourModel>> expression = x => x.ContactRoleDto.Competencies[0].Name;
string id = ExpressionHelper.GetExpressionText(expression);

Rendering the field name in an EditorTemplate (rendered through EditorFor())

I'm currently building the Admin back-end for a website in ASP.NET MVC.
In an ASP.NET MVC application, I've started using the 'EditorFor' helper method like so:
<div id="content-edit" class="data-form">
<p>
<%= Html.LabelFor(c => c.Title) %>
<%= Html.TextBoxFor(c => c.Title)%>
</p>
<p>
<%= Html.LabelFor(c => c.Biography) %>
<%= Html.EditorFor(c => c. Biography)%>
</p>
</div>
In the model, the 'Biography' field has been decorated with: [UIHelper("Html")].
I have an 'Html' partial view (under Views/Shared/EditorTemplates):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.XML.Linq.XElement>" %>
<textarea class="html">
<%= Model.ToString() %>
</textarea>
Now I'd like to have the 'ID' attribute of the 'textarea' set to the name of the field, like this:
<textarea id="Biography" class="html">
...
</textarea>
But I can't see a way to do that with the current set up.
All I can think of is creating an 'Html' ViewModel that contains a 'Value' property and a 'ControlID' property.
But if I based the view off that, rather than 'System.XML.Linq.XElement', it would no longer be compatible with the 'EditorFor' helper method and I'd have to do everything manually.
Has anyone had a similar problem yet?
You should be able to pull out the desired ID from the ViewData.TemplateInfo.HtmlFieldPrefix property of the view. Like this:
<%# Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<System.XML.Linq.XElement>" %>
<textarea id="<%= ViewData.TemplateInfo.HtmlFieldPrefix %>" class="html">
<%= Model.ToString() %>
</textarea>
To show why this works, here's the place in TemplateHelpers.cs (of MVC2 Preview 1 source) where ViewData is initialized for the Editor template control:
ViewDataDictionary viewData = new ViewDataDictionary(html.ViewDataContainer.ViewData) {
Model = modelValue,
TemplateInfo = new TemplateInfo {
FormattedModelValue = formattedModelValue,
ModelType = modelType,
HtmlFieldPrefix = html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(expression),
IsNullableValueType = (underlyingNullableType != null),
}
};
In the call above, "expression" is initialized (further up the call stack) with the name of the property being edited.
BTW, #Sperling below caught a detail I originally missed: if you're using (or might use) a non-default HtmlHelper.IdAttributeDotReplacement, then you'll want to replace the dots in the HtmlPrefix property with HtmlHelper.IdAttributeDotReplacement.
Have been using this to generate id(with model prefix). Skip the .Replace() part if
you want the name attribute.
<%=Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(String.Empty).Replace(".", HtmlHelper.IdAttributeDotReplacement) %>
In our case we had to use Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName with ExpressionHelper.GetExpressionText
which in razor was used like this:
// hiddenFor was caching the value of this html input, and the value alone, nothing else on the page!
Expression<Func<Web.ViewModels.ApiSettingsViewModel, int>> expression = (m => m.OrgApiLoginCredentials[i].OrgApiLoginId);
}
<input type="hidden" value="#Model.OrgApiLoginCredentials[i].OrgApiLoginId" name="#Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText(expression))" class="data-org-api-login-id"/>

Resources