How to create html helper in mvc - asp.net-mvc

The code I'm currently using is this:
#Html.LabelFor(model => model.MaxExecutions)
<div class="input-append">
#Html.TextBoxFor(model => model.MaxExecutions, new { #class = "input-xxlarge", placeholder="Enter Max Executions" })
<span class="add-on">?</span>
#Html.ValidationMessageFor(model => model.MaxExecutions)
</div>
I repeat this over & over in my code. I'd love to pass this off to an HtmlHelper. The type of Model I pass in can change, and I'd like to have the Display attribute available from the model (or I'd just generate an htmlstring).

You can implement an extension method or a helper (static) class but there's times where I like the declarative version (CSHTML). Either way works and can be passed around from controller, etc.
~/App_Code/Blah.cshtml
#helper ExecuteHelper() {
#Html.LabelFor(model => model.MaxExecutions)
<div class="input-append">
#Html.TextBoxFor(model => model.MaxExecutions, new { #class = "input-xxlarge", placeholder="Enter Max Executions" })
<span class="add-on">?</span>
#Html.ValidationMessageFor(model => model.MaxExecutions)
</div>
}
Then call it in view like:
#Blah.ExecuteHelper()
I've noticed the amount of HTML you have it in which is why I opted for the #helper syntax solution. Here's an article by Scott Guthrie that outlines this MVC feature:
Article

Related

How do you create a MVC view for navigation properties (one to many, many to many)

I have two ASP.NET MVC EF entities sharing an association:
When I am editing or creating the User, I'd like to be able to attach one or more UserRoles. So, my User Create view looks like this:
#model MyModels.UserViewModel
#{ ViewBag.Title = "Create"; }
#using (Html.BeginForm())
{
<fieldset>
<legend>User</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Username)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Username)
#Html.ValidationMessageFor(model => model.Username)
</div>
<!-- how to create an editor to add/remove roles -->
<div class="editor-label">
#Html.LabelFor(model => model.UserRoles)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserRoles)
#Html.ValidationMessageFor(model => model.UserRoles)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Since Model.UserRoles is initially empty, I get nothing in this line #Html.EditorFor(model => model.UserRoles). I tried adding a drop-down where I can select existing roles using JavaScript (I guess retrieved as partial view?), but I don't know how to append a selected role to the fieldset so that it gets submitted.
How is this usually done in ASP.NET? I have been searching SO for a while but cannot find the appropriate solution.
To clarify, what I don't understand is how to add/append a new role to the client side, so that the submit button actually sends this inside the UserRoles list.
(edit) Ok, I've found this: How to add an item to a list in a ViewModel using Razor and .NET Core. It says that I should fetch a partial view which is written to look like the inputs which would be generated by #Html.EditorFor (with the next array index), and then append it using JavaScript.
That looks quite weird, is that really the correct approach?

How can I refer to a property of a model within a partial view?

In MVC4, with the Razor view engine, we have a group of items that we wish to group in a partial view, so that we can reuse the code. Currently our main views we have something along the lines of:
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Description, new { #id = "Common" })
<div class="FormValidationText">
#Html.ValidationMessageFor(model => model.Description)
</div>
</div>
We want to be able to use this logic but with a wide variety of models, not all of which will want to use the model.Description.
For example, we would like to use model Foo, and create the above for the Foo.Bar property, but we also want to be able to use the Hello model's Hello.World property. These are all of type string, as you would expect since we want to handle the text input from the textarea.
What edits do we need to make in the partial view to say "Use some specified property of any given model, and understand it to be a property of that model, to generate these items". How, subsequently, do we work with the #{Html.RenderPartial(...)} method to ensure that we have passed the models property?
Please forgive me if this seems a little confused, I am still learning MVC and Razor views.
These are all of type string, as you would expect since we want to
handle the text input from the textarea.
You could write an editor template: ~/Views/Shared/EditorTemplates/MyTemplate.cshtml:
#model string
<div class="editor-label">
#Html.LabelFor(model => model)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model, new { #id = "Common" })
<div class="FormValidationText">
#Html.ValidationMessageFor(model => model)
</div>
</div>
and then your views you could use like that:
#model Foo
...
#Html.EditorFor(x => x.Description, "MyTemplate")
or:
#model Hello
...
#Html.EditorFor(x => x.World, "MyTemplate")
and if you name your template ~/Views/Shared/EditorTemplates/string.cshtml you don't even need to specify its name when calling the EditorFor helper:
#model Hello
...
#Html.EditorFor(x => x.World)
By convention all properties of type string will use your template.

How can I programmatically trigger client side validation set up by a Razor view?

I have a little Ajax application where I use Razor views to initially generated HTML form segments that I later read and write from with knockout.js. Although I am doing no non-Ajax action requests, I use Razor to generate the HTML so I enjoy automatic generation of jQuery Validation attributes. E.g. in my single page, I render a hidden form like this:
<section id="person-detail">
#Html.Action("EditPartial", "Person")
</section>
The EditPartial action returns a partial view that looks a lot like this:
#using (Html.BeginForm())
{
<fieldset>
#Html.HiddenFor(model => model.Id, new { data_bind = "value: id" })
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.FirstName, new { data_bind = "value: firstName" })
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<p>
Update
Delete
</p>
</fieldset>
}
Because I'm never actually posting the form, and due to some unknowns, despite all properties on my Person model being marked with the Required attribute, I see no sign of client side validation. What must I do to trigger this validation when my save button is clicked?
suppose your form has a class 'main':
$('form').submit(function() {
var $form = $('form.main');
$form.valid();
});

How to iterate through all properties in a ViewModel

I have a lot of repeated code in my asp.net MVC views
<div class="editor-label">
#Html.LabelFor(model => model.MyProperty)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MyProperty)
#Html.ValidationMessageFor(model => model.MyProperty)
</div>
I want to wrap this in something like:
foreach (System.Reflection.PropertyInfo item in Model.GetType().GetProperties())
and reuse the same partial view throughout. But I can't get the syntax quite right.
How can I make this more generic?
This is what Display and EditorTemplates are for.
You need only do #Html.EditorForModel() and then define a generic template for your model.

Is there a way to avoid me repeating my code in MVC Razor view?

I need to do something like this:
<div class="editor-field">
#Html.EditorFor(model => model.A1)
#Html.ValidationMessageFor(model => model.A1)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.A2)
#Html.ValidationMessageFor(model => model.A2)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.A3)
#Html.ValidationMessageFor(model => model.A3)
</div>
I'm using MVC3 and the razor view engine which is new to me. What I would like to do is to avoid having to repeat the same block of four lines with A1,A2,A3,A4 ... A20. Is there some way I can use a helper, template or some other feature to make it so I don't have to repeat many lines of code.
One option is to use a partial view like #Ufuk mentions.
A better way IMO is to use an editor template, making use of MVC's built in conventions.
Instead of having single properties for A1, A2, etc. Put them in a IEnumerable<Something> Somethings.
Then do this in your View:
#Html.EditorFor(model => model.Somethings)
Then create an editor template called Something.cshtml and place it in Shared\EditorTemplates, and MVC will do an "implicit" for each loop and render out whatever is in the editor template for the model:
<div class="editor-field">
#Html.EditorForModel()
#Html.ValidationMessageForModel()
</div>
Do not use a foreach loop - it's unnecessary and avoidable code soup.
Editor template HTML is identical to partial, strongly-typed and all. The difference is the convention to look for the file, whereas partial views need the explicit partial view name.
What this means is if you change the type of the model, it will look for that template based on the model type, allowing for a very powerful convention-based approach - which is what MVC is all about.
Create a partial view that's strongly typed to that class.
A_Partial.ascx
<div class="editor-field">
#Html.EditorFor(model)
#Html.ValidationMessageFor(model)
</div>
Then render them for each object.
#Html.Partial("A_Partial", model.A1)
#Html.Partial("A_Partial", model.A2)
#Html.Partial("A_Partial", model.A3)
You could put them in an array:
#foreach(var item in new object[] { Model.A1, Model.A2 /* ... */ }) {
<div class="editor-field">
#Html.EditorFor(item)
#* ... *#
</div>
}
If possible, try putting all of them in a single array/dictionary and then use foreach.

Resources