C# MVC property name to HTML id - c#

I know that I could do this manually, but is there a built in function to convert a C# MVC Razor property name to the value that Razor will use as the HTML id?
To expand on this question:
I am trying to access the HTML element using JavaScript in a partial view. (The partial view means that I do not have access to the parameter name directly.)
The following two partial solutions double up the ID, giving you ParameterName_ParameterName:
string name = ViewData.TemplateInfo.HtmlFieldPrefix
#Html.Id(name)
#ViewData.TemplateInfo.GetFullHtmlFieldId(name)
The solution I'm going with at the moment:
Regex.Replace(name, #"[\.\[\]]", "_");
I guess you could add parentheses.

As per your comments:
IMHO you should not be using your model in that fashion. If you need access to children objects, create a new model and bind to it that exposes that directly. Then in your controller piece back together your original model as needed. In the case of a Registration Form, if its highly complex, try breaking it up in to smaller pieces (seperate views), otherwise use a flat model that combines all the fields like Username, Password, etc then assign values to the appropriate objects.
Remember that the least amount of complexity is the better solution, as it improves maintainability.

When you define a moldel
something like this
public class AnnonymousModel
{
[Required]
[StringLength(20, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 3)]
[Display(Name = "User name")]
[RegularExpression(#"^[A-Za-z\n\r\0-9_ ]+$")]
public String RegisterUsername {get; set;}
}
and then use it in mvc view page
For Razor
#Html.TextBoxFor(m => m.RegisterUsername, new { #class = "inp-form", #placeholder = "User name" })
For asp
<%Html.TextBoxFor(m => m.RegisterUsername, new { #class = "inp-form", #placeholder = "User name" })%>
the in the Html renderd is like this
<input type="text" value="" placeholder="User name" name="RegisterUsername"
id="RegisterUsername" data-val-required="The User name field is required." data-val-regex-
pattern="^[A-Za-z\n\r\0-9_ ]+$" data-val-regex="The field User name must match the regular
expression '^[A-Za-z\n\r\0-9_ ]+$'." data-val-length-min="3" data-val-length-max="20"
data-val-length="The User name must be at least 3 characters long." data-val="true"
class="inp-form">
So the Id is automatically generated as the property name specified.

Related

Working with password field in mvc

Whenever I am trying to insert records it gives me error message for password field as '
The value 'SomePassword' is not valid for password
Model
public byte[] Password { get; set; }
View
<label class="input">
<i class="icon-append fa fa-tag"></i>
#Html.PasswordFor(model => model.Class.Password, new { #class = "form-control", #id = "txtPassword" })
<span asp-validation-for="Class.Password" class="text-danger"></span>
</label>
When checked in controller the ModelState is invalid and error message is coming why is it so ?. I have tried with DataType.Password on Password field, but still no success
The Password column has datatype 'Varbinary' in sql server.
Any help on this appreciated !
A password is never entered by the user as a byte arrray, it is converted into one before hashing.
The mvc model binder has no built in capability to convert any input to a byte array, and even though you could write a custom model binder I don't see why you would want to, as a plain string is much easier to type.
Even though the SQL type may be varbinary, you do not want the user to enter this representation in your model.
You should set the Class.Password property to be a string, and then in your server side code, you should be hashing the password.
Encoding.UTF8.GetBytes(password); will convert the string password into a byte[] but it on it's own it is not sufficient for secure password storage.
I strongly recommend you take a look at https://www.asp.net/identity if you have the option to upgrade your password requriements.
why dont you start with the Password model of the Default Account, and modify it to fit your actual need? or you have a very unusal password requirement which need byte[]? otherwise you should just convert it when you actually needed to...
Model
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
View
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
What you wrote would only work if class Model has a property called Class, and the property Class has a property Password.
Try using this instead:
#Html.PasswordFor(model => model.Password, ...
Also, the Password property in your ViewModel needs to be a string. Both the Web and MVC cannot use byte[] for text input controls.
You can store a byte[] - hashed and encrypted, the best approach! - but it first comes in as a string.

Concatenate string to Display Culture Value MVC 4+

Hi I've followed the following post in order to localize labels for a form.
http://afana.me/post/aspnet-mvc-internationalization.aspx
I works perfectly but I'm trying to find a way to concatenate ":" on to the display value (i.e. Address:)?
View:
<div class="col-sm-5">
#Html.LabelFor(model => model.Address)
</div>
Model:
[Required]
[Display(Name = "Address", ResourceType = typeof(Resources.Resources))]
public string Name { get; set; }
key in resx file
Name :Address
Value:Address
My attempts are:
Change the model
[Display(Name = "Address" + ":", ResourceType = typeof(Resources.Resources))]
Change the view
#Html.LabelFor(model => model.Address, Name + ":")
Anyone with any ideas if it's possible? Is there away to get the Name property and manipulate it in the view?
https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.displayattribute%28v=vs.110%29.aspx
I would prefer to keep it simple and see the View changed by adding, for example, :.
The text "Address" is bound to be used somewhere else where a colon or dash isn't required.

Razor #Html.ValidationMessageFor() not displaying "validation error message"

#Html.RequiredLabelFor(x => x.FirstName)
#Html.TextBoxFor(model => model.FirstName, new { Name = "1.first_name", tabindex = "1" })
#Html.ValidationMessageFor(model => model.FirstName)
Is there a reason why when passing second parameter to #Html.TextBoxFor the field is being validated but "validation message" does not appear?
#Html.RequiredLabelFor(x => x.FirstName)
#Html.TextBoxFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
When using an overload that accepts only one argument (lambda expression) "validation message" is being displayed correctly.
In my understanding the actual property is not being recognized?
Backing property:
[StringLength(100, ErrorMessage = "Max length 100 characters")]
[Required(ErrorMessage = "This field is required")]
[Display(Name = "First name")]
public string FirstName { get; set; }
The unobtrusive validation library identifies 'things to display validation for' using the name attribute. It's not that specifying extra properties stops it from working, but you have changed the name property and not reflected the new name in your validation helper.
You can either stop changing the name attribute in your textbox helper (necessary if you use the default model binder to return your view), or you can use
#Html.ValidationMessage("1.first_name")
The above method is not a good idea unless you're using JS/JQuery to validate and submit your form data (via AJAX), for the reasons given by Stephen in comment to this answer.
You have changed the name attribute, so not only will it not post back and bind to your model, jquery.validate.unobtrusive can now no longer match up the controls since the input has a different name than the associated validation message
<input name="1.first_name" ... />
<span .. data-valmsg-for="FirstName" ..></span> // There is no control named FirstName

how to update the name attribute of a HTML helper

I am using MVC4, just wondering, is it possible to update the name attribute of a html helper. I am updating this as the action method is expecting a particular name. I know I can just write raw html, but just want to know if there is an overide in the html helper
I tried this
#Html.TextAreaFor(m => m.noteDetail.NotesDetails, new { #class = "k-textbox", #cols = 100, #rows = 5, id="NotesDetails", name= "NotesDetails" })
but when I look at the generated html
<textarea class="k-textbox" cols="100" data-val="true" data-val-required="The details are required" id="NotesDetails" name="noteDetail.NotesDetails" rows="5"></textarea>
Thanks
You just need a # symbol in front of your name property.
One technique I've found when a submodel is the model that your POST action accepts is to put the HTML that renders the submodel in a partial view that's included in the main view. Have this partial by strongly typed by the submodel and pass the value of the submodel into it. This way, the prefixes won't be generated on the submodel.
#Html.Partial("_NoteDetails", Model.noteDetail)
Then in _NoteDetails.cshtml
#model NoteDetail
#Html.TextAreaFor(m => m.NoteDetails,
new { #class = "k-textbox", cols = 100, rows = 5 });
Hi I think as you pass a viewModel as it contains maybe 2 models that is why you have this name. It does like this for the Binder to construct objects from your Post or Get.
If you change the name then you will maybe perform some custom codes for your binder if you want to pass it again to the controller.

MVC 4 : Postback returns a array for property of type object in my model

I have a model with one of the property of type object . This property is a dynamic property and could sometime contain a string or a date or a Boolean.
I have a editor template for each type i.e boolean , string , date etc .
The problem I have is when the page is posted , the postback contains a array instead of the actual value. The first element of the array contains the actual value.
Why is the value being returned as a array ?
My model
public string Description;
public string Name { get; set; }
public Type Type{ get; set; }
object _value;
public object Value { get;set;}
statement in the view
#Html.EditorFor( m => m.Value)
Edit : Corrected the object name from _value to Value. It was a wrong Ctrl V operation.
Edit : The HTML rendered in the browser
When the object contain a boolean value (checkbox):
<div>
<input checked="checked" data-val="true" data-val-required="The BoolJPY field is required." id="FurtherInformationFieldObject_Properties_1__Value" name="FurtherInformationFieldObject.Properties[1].Value" type="checkbox" value="true"><input name="FurtherInformationFieldObject.Properties[1].Value" type="hidden" value="false">
When the object contains a string(Textbox) :
<div id="divStringField"><input class="text-box single-line valid" data-val="true" data-val-required="The String Field field is required." id="FurtherInformationFieldObject_Properties_2__Value" name="FurtherInformationFieldObject.Properties[2].Value" type="text" value=""> </div>
Edit 2 : Posting the complete model and view code.
Controller code :
public ActionResult Edit(string name ="field1" )
{
Models.DynamicData data1 = new Models.DynamicData();
//all this comes from the database table. I am putting the value directly in field just for simplicity
// this is exactly how I convert the value from the entity to the model
data1.Description = "Field1 Description";
data1.Name = "field1";
data1.Type = typeof(string);
data1.Value = Convert.ChangeType("MyStringValue", data1.Type);
//similarly add few more fields to the model collection
return View(data1);
}
[HttpPost]
public ActionResult Edit(Models.DynamicData model)
{
// break point here : model.Value shows a array of string instead of the edited value.
return View(model);
}
View :
#model SampleDynamicDataProject.Models.DynamicData
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>DynamicData</legend>
<div class="editor-label">
#Model.Description
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Value)
#Html.ValidationMessageFor(model => model.Value)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
I should explain I used object as type for Value property because the value could be string or bool or date ex data1 in above controller could look like below
data1.Description = "Field2 Description";
data1.Name = "field2";
data1.Type = typeof(bool);
data1.Value = Convert.ChangeType("true", data1.Type); // database stores "true" as string which is converted into a boolean and stored in the object.
As shown in the code , my problem is in the post action for Edit , I get Value as an array even for a simple string.
The sample project code here https://drive.google.com/file/d/0B3xCaeRk2IQZSTM0aHdoWEtNYW8/edit?usp=sharing
I got a answer to my question at one of the other forums.
Basically the reason MVC binder is returning a array is because it does not understand what type of data/control is used in the html and the model binder fails.
I got around my issue by modifying the model to have two different property a
public String StringValue
public Bool BooleanValue
I use the StringValue field when the Type is String , Date , Number etc.
I use the BooleanValue for field with Type as Boolean.
Its not the cleanest approach but it will have to do till the point I write my own custom model binder.
Thanks to bruce who answered my question here http://forums.asp.net/p/1961776/5605374.aspx?Re+MVC+4+Postback+returns+a+array+for+property+of+type+object+in+my+model
I now understand why the model binder fails.
Pasting his answer here for the benefit of others
you need to understand how browser postback is done. on form submit a collection of name/value pairs is sent. the name is the form element name, the value is the elements value. standard url encoding is done. so for:
the postdata is
foo=1&bar=true
note the post data is just a string with no type data. the brwser allows duplicate name, so
the post data is:
foo=1&foo=true
when asp.net load the post data into the form collection (which is just a dictionary), it can not add the key "foo" twice, but concats the values seperated by a "," ("1,true"). the binder just treats it as a string array named foo with 2 values.
now we get to another browser behavior. form elements that support checked (radio and checkbox) are only include the post data if checked. this causes a problem for the mvc binder with checkbox, becuase it can not tell from the postback data if the element was not checked or not included. this is important if you are using tryupdate to apply only a subset of the model properties, becuase only a subset was rendered. to get around this, the checkbox helper renders two fields with the same name, a hidden with the value "false" and a checkbox with the value "true".

Categories

Resources