I am looking for best practices for design razor view with MVC.
which would be better option:
HtmlHelper extension methods
#Html.TextBox("txtName")
or
write the html directly
<input type"text" id="txtName" name="txtName" />
I found 2 diferent links.
The first one http://blogs.msdn.com/b/aspnetue/archive/2010/09/17/second_2d00_post.aspx says DO use HTMLHelper extension methods.
and the second one http://codeclimber.net.nz/archive/2009/10/27/12-asp.net-mvc-best-practices.aspx says 10 – Write HTML each time you can
so i am a little cofused
Even the name HtmlHelper should already give you a hint whether you should use it or not. Do you want help? If not, just write html from the scratch. It does not really matter how the html was generated: from the scratch or using html helper. What matter is that it was generated with correct names of the inputs so that model binder can bind these inputs to the model.
For example, suppose you have the following Model that will be passed to the view and that will be received on the POST:
public class SomeModel
{
public Customer Customer { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
In order to make sure that your inputs will be binded to the model you need three inputs on your page:
<input type="hidden" id="whatever" name="Customer.Id" />
<input type="text" id="whatever" name="Customer.FirstName" />
<input type="text" id="whatever" name="Customer.LastName" />
Having this html markup will assure proper model minding. However, you can achieve this markup by using HtmlHelpers, which is a lot easier:
#Html.HiddenFor(m => m.Customer.Id)
#Html.TextBoxFor(m => m.Customer.FirstName)
#Html.TextBoxFor(m => m.Customer.LastName)
This will not only give you proper name attributes on every input, but also assign id attributes accordingly so you don't have to do that all by your self.
It appears that the author from the second article suggests to never use HtmlHelpers for two reasons:
the learning purposes: I assume by saying "web developers have to be
comfortable writing HTML" he means that developer should know
exactly what html markup is required for proper model binding.
the fear of black box: It seem that author is afraid that improper html
markup will be generated by using HtmlHelpers or he just does not
know what html will be generated.
I disagree with his phrase: "HtmlHelpers whose only reason of living is hiding the HTML away". I'd rather say "HtmlHelpers whose only reason of living is helping writing Html markup"
Summary:
HtmlHelpers help you write proper html markup, which is why I suggest you using it.
Since you're using Razor, I would make the most of what it has to offer, and the HtmlHelper extensions allow you to write html quicker and easier in a lot of places.
There may be times when you have to use Html instead, where you might want to include tags in an anchor and cannot use #Html.ActionLink, for example.
But where you can achieve the same result with either approach, I'd recommend you go with Razor.
Html helpers are not cosmetic code snippets that just save time. Consider choosing the appropriate editor based on model property types, and - what is also very important - they help in client validation, provided you include jquery.unobtrusive-ajax.js and jquery.validate.js.
The last cannot be achieved by simply writing HTML.
From what I said it can be easily derived that Html helpers "know" about the model, while plain markup does not.
At the end it is up to you to decide what to use, but knowing more about Html helpers is better when making a decision.
Related
I have the following model class which contains a bool value:-
Public class Server
{
public bool IsIPUnique { get; set; }
}
Currently i am using the following to display the check box inside my Razor view:-
<input type="CheckBox" name="IsIPUnique" value="true" #(Html.Raw(Model.IsIPUnique ? "checked=\"checked\"" : ""))/> IP Unique.
but i read about the EditorFor template, and it can automatically create the check box and check/uncheck it based on the model values so i tried the following :-
#Html.EditorFor(model=>model.IsIPUnique)<span>test</span>
so my question is if i can replace my old code with the new one that uses the EditorFor ?, or asp.net mvc might deal with these values differently ?
Thanks
Basically you have 3 possibilities:
Write HTML manually (as you have done)
I would avoid writing the HTML manually if there is a HTML helper available.
Manually written HTML is prone to errors which can cause problems with model binding.
Use the specific HTML helpers (Html.CheckBoxFor)
The specific HTML helpers add a layer of abstraction to all controls.
It's easy to modify the template of all controls that use the same HTML helper and it makes your views more readable.
Use the general EditorFor
The EditorFor HTML helper is great if your model datatypes change often.
The EditorFor will adjust the input fields automatically to the new datatype and won't throw an error (as with the specific HTML helpers).
It is also a bit harder to add HTML attributes to the EditorFor while the specific HTML helpers often have overloads for them.
However, this is fixed in MVC 5.1: http://weblogs.asp.net/jongalloway/looking-at-asp-net-mvc-5-1-and-web-api-2-1-part-3-bootstrap-and-javascript-enhancements
Conclusion: in your case I would use the CheckBoxFor HTML helper because the datatype won't change likely and it will make the view cleaner
Could someone provide a good tutorial on how may I validate my html fields with unobtrusive,
but without using MVC helpers.
Is it possible at all?
I would like to keep the plain html and use input type="text" field instead of mvc helpers <%= Html.TextBox("Name") %> but still using the model validation..
public class Employee
{
[Required]
public string Name { get; set; }
}
Also is it possible with jquery Ajax?
Thanks
While it is possible to perform unobtrusive validation in MVC without using helpers, it will be painfully for you as developer to do it manually without usage of mvc helpers. Saying strictly, it will kill your performance and make your code unreadable.
Basically, unobtrusive validation consists of two parts: server side, via data-attributes to your model fields and MVC Helpers, which generate necessary markup, and client side library, jquery.validate.unobtrusive.js, which parses those markup to meaningful parts for jquery validate plugin.
So, in general, you can manually write necessary markup, as long as validation js library will be loaded, validation will work. For example, field, which is subject of validation, must be marked with data-val='true' attribute. If you want to make your field required, you should write additionally something like data-val-required="error message". For length validation - data-val-length-min="5" (obviously, minimum) data-val-length-max="50" (maximum length), data-val-length="Min 5 max 50 chars required".
While, when using normal mvc approach, it is just a question of model attribute:
[Required]
[StringLength(50, MinimumLength = 5)]
public string Name { get; set; }
and one line of code in markup:
#Html.TextBoxFor(o=>o.Name)
Nice, shiny, separates View and Model, and helps KISS.
And for second part of your question. If I understood your problem correctly, you want to validate dynamic forms. Probably it will be answer:
jquery.validate.unobtrusive not working with dynamic injected elements
I am experimenting with custom HtmlHelpers, but can't get even a basic one to work correctly. My code (just for testing sake) looks like this -
My class -
namespace HtmlHelpers.Extensions
{
public static class Helpers
{
public static string MySubmitButton(this HtmlHelper helper)
{
return String.Format("<input type=\"submit\" value=\"Submit This\">");
}
}
}
In my view -
#using HtmlHelpers.Extensions;
#Html.MySubmitButton()
This I believe should generate a simple submit button, but instead, it justs writes the following text to the screen -
<input type="submit" value="Submit">
I inspected the element, and for some reason the entire input element is being surrounded with double quotes.
Anyone know why? Thanks!
I believe you should be returning a MvcHtmlString class. Try
public static MvcHtmlString MySubmitButton(this HtmlHelper helper)
{
return MvcHtmlString.Create("<input type=\"submit\" value=\"Submit This\">");
}
although there's probably better ways to do this using a TagBuilder if you look at examples online, or the MVC source code since it's open source, you can look at their html helpers(although they are pretty complicated due to the way they layer them).
To directly answer your question of "why" it was displaying that as if it were a string, is Razor tries to be safe and convert anything you display as text instead of HTML/script. For example, #Model.PeronName will escape any characters in the peron's name with HTML character codes. Consider if there was no protection like this, and one of your users changed their name to be <script>someDangerousJavascriptThatWouldChangeCurrentUsersPassword()</script>, then posted on your forum or anywhere their name would appear, then other users visit the page, and that javascript runs and POSTS a change password form for that current user's password to some password that the hacker chose in the script. There are a wide variety of complicated attacks like this, or users might accidentally enter angle brackets(and while fairly harmless if treated as HTML they will mess up your page display).
For that reason MVC will assume just about any string is not HTML and thus replace things like <script> with <script> which basically is a way of saying "this is not html/script, I want you to display the less-than symbol and greater than symbol". If you wanted to display something as HTML, there is a #Html.Raw() helper for that, and it won't clean output, and thus should never be used with a string that you concatenated together from any data that a user my supply.
I know similar questions have been asked regarding complex model binding in ASP.NET MVC, but I am having a problem binding because of a lack of a sufficient prefix coming back on the POST and wondered if there were an easy solution.
I have a view Model that looks something like this:
public class ViewModel<Survey, Contact>
{
public Survey Model { get; set; }
public Contact Model2 { get; set; }
}
I then have an action method like this that accepts the POSTed
public ActionResult Survey(
string id, string id2, SurveyViewModel<Survey, Contact> model)
{
// code goes here...
}
In my form, the first two id's are from the URL route and I then have form code (using #Html.EditorFor(x => x.Model.SurveyName) or similar), generated with names like this:
<input class="text-box single-line" id="Model_Email"
name="Model.Email" type="text" value="" />
A post works if I change the name from Model.Email to model.Model.Email, but I am trying to avoid having to create a custom model binder.
Is there
A setting I can make in the view to change the name for all fields rendered in a view using the #Html.EditorFor typed view helpers?
Something I can change using the Bind attribute on the action that would allow it to default binding to that object?
The answer may be "build a custom binder", but I just wanted to pose the question before biting that off.
Thanks for the help. Best Regards,
Hal
You can pass custom viewdata with custom HtmlFieldPrefix to view. Every control rendered with helper will have that prefix.
ViewData.TemplateInfo.HtmlFieldPrefix = "prefix here";
Take a look at this: Forcing EditorFor to prefix input items on view with Class Name?
I am trying to find me feet with MVC4 Razor and I'm stuck with this simple problem.
When I use #Html.DisplayFor the model is always sent back as NULL, but when I use #Html.TextBoxFor this model is fully populated, what am I missing?
Thanks in advance
This is a common issue that many people miss in the asp.net mvc framework. Not just the difference in the helpers such as HiddenFor, DisplayFor, TextBoxFor - but how exactly the framework sets up automatically collecting and validating these inputs. The magic is all done with HTML5's data-* attributes. You will notice when looking at the input tag generated that there are going to be some extra properties in the form of data-val, data-val-required, and perhaps some additional data properties for types, for example numerics would be data-val-number.
These data attributes allow the jQuery extension jquery.validate.unobtrusive.js to parse the DOM and then decide which fields to validate or generate error messages.
The actual collection of posted data is reflected from the name property. This is what should map up to the model that is in the c# or vb [HttpPost] method.
Use HiddenFor when you want to provide posted data that the user does not need to be aware of.
Use DisplayFor when you want to show records but not allow them to be editted.
Use TextBoxFor when you want to allow user input or allow the user to edit a field.
EDIT
"the purpose of this view is to enable the user to view the data before submitting it to the database. Any ideas how I can achieve this?"
You could accomplish this with a duo of HiddenFor and DisplayFor. Use HiddenFor to have the values ready to be posted, and DisplayFor to show those values.
DisplayFor will not do the Model binding. TextBoxFor will do because it creates a input element in the form and the form can handle it when it is being posted. If you want to get some data in the HttpPost action and you dont want to use the TextBoxFor, you can keep that pirticulare model proeprty in a hidden variable inside the form using the HiddenFor HTML helper method like this.
#using(Html.BeginForm())
{
<p>The Type Name is</p> #Html.DisplayFor(x=>x.TypeName)
#Html.HiddenFor(x=>x.TypeName)
<input type="submit" value="Save" />
}
Use both DisplayFor and HiddenFor. DisplayFor simply displays the text and is not an input field, thus, it is not posted back. HiddenFor actually creates <input type="hidden" value="xxxx"/>
DisplayFor builds out a HTML label, not an input. Labels are not POSTed to the server, but inputs are.
I know this is a bit of an old question but you can roll your own, custom combined display control as shown below. This renders the model value followed by a hidden field for that value
#Html.DisplayExFor(model => Model.ItemCode)
Simply use what the framework already has in place
public static MvcHtmlString DisplayExFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> ex)
{
var sb = new StringBuilder();
sb.Append(htmlHelper.DisplayFor(ex));
sb.Append(htmlHelper.HiddenFor(ex));
return MvcHtmlString.Create(sb.ToString());
}
Do you mean during a form post? If you use DisplayFor, this creates a element which does not contain any form values. Typically you use these in conjunction with each other to create a label for your textbox, then using the Html.TextBoxFor to allow users to modify the data element.
Example:
#Html.DisplayFor(x=>x.Item)
#Html.TextBoxFor(x=>x.Item)
Will Render
Item <a text input field following>
Or in HTML
<label for="Item">Item</label><input type="Text" id="Item" name="Item"/>