I have a file in my view folder Users called UserViewControl.cshtml.
My code in the actual view (Users.cshtml) is:
#Html.RenderPartial("RegisterViewControl")
Error:The best overloaded method match for 'System.Web.WebPages.WebPageExecutingBase.Write(System.Web.WebPages.HelperResult)' has some invalid arguments
I do not want to type the path fully like this as the whole view folders might move in the future:
#Html.RenderPartial("~/Views/Users/RegisterViewControl.cshtml")
Code in RegisterViewControl.cshtml:
#model SampleMVC.Web.ViewModels.RegisterModel
#using (Html.BeginForm("Register", "Auth", FormMethod.Post, new { Id = "ERForm" }))
{
#Html.TextBoxFor(model => model.Name)
#Html.TextBoxFor(model => model.Email)
#Html.PasswordFor(model => model.Password)
}
This is a form that will be submitted by ajax, but I want all the validation from the viewmodel.
It should be like this:
#{Html.RenderPartial("RegisterViewControl");}
And that's because the RenderPartial extension method doesn't return anything. It writes directly to the output. In aspx you use it like this:
<% Html.RenderPartial("RegisterViewControl"); %>
instead of:
<%= Html.RenderPartial("RegisterViewControl") %>
So the same rules apply for razor.
You could alternatively use
#Html.Partial("RegisterViewControl")
I had this issue as well and got this directly from Scott Guthrie's blog post:
using #Html.RenderPartial() from a Razor view doesnt work.
Rather than call Html.RenderPartial() use just
#Html.Partial("partialname")
That returns a string and will work.
Alternatively, if you really want to use the void return method you
can use this syntax:
#{Html.RenderPartial("partialName")}
But #Html.Partial() is the cleanest.
The link for this is: http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx
Related
Am new to MVC, am am trying to apply CSS styles to Html.DisplayFor helper inside my template file: Shared>>EditorTemplate>>Contacts.cshtml. Below is my code:
#model People.Contacts
<div>
#Html.DisplayNameFor(m => m.Name) <span class="myclass">#Html.DisplayFor(m => m.FirstName) #Html.DisplayFor(m => m.LastName)</span></div>
and my css class outside this template looks like this:
.myclass{font:italic bold;}
Html.DisplayFor does not support passing HTML attributes, including class/style. At it's most basic it merely renders the value, without any HTML, and with editor/display templates, it just renders whatever's in the template.
First, if you have EditorTemplates\Contacts.cshtml, that will actually never be used by DisplayFor. For DisplayFor you need a separate template in Views\Shared\DisplayTemplates. As its name implies EditorTemplates is used by EditorFor.
Either DisplayFor or EditorFor are basically the same as calling Html.Partial. There's just some additional logic to deal with a specific model property and look by default in DisplayTemplates/EditorTemplates for the view. That said, you can pass additional data to them the same as you would with a partial, via ViewData.
For example, if you were to call #Html.DisplayFor(m => m.FirstName, new { #class = "myclass" }), then nothing would happen by default, but you would have a value of "myclass" in ViewData["class"]. You could then use that to modify a part of your template. For example:
Views\Shared\DisplayTemplates\Contacts.cshtml
<span #(ViewData["class"] != null ? "class='" + ViewData["class"] + "'" : string.Empty)>
#ViewData.TemplateInfo.FormattedModelValue
</span>
That checks to see if ViewData["class"] has a value, and if so, adds a class attribute with that value to the span.
As a different solutions you can use Html.DisplayFor in <Label> tag
<label class="control-label"> #Html.DisplayNameFor(p => p.HeadLine)</label>
With the help of several SO questions, I've figured out how to use two models on the same view, using the tuple form. At the top of my file is this:
#using Project.Models;
#{
ViewBag.Title = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
#model Tuple<Foo, Bar>
}
For the Foo stuff, it uses jQuery like this:
#Html.DisplayFor(tuple => tuple.Item1.ID)
and works fine. However, for my second model, it isn't displaying info, but is a submission form. Currently, this is what I have:
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "createFoo", #action = "/api/Foo" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="editor-field">
#Html.TextAreaFor(tuple => tuple.Item2.Text)
#Html.ValidationMessageFor(tuple => tuple.Item2.Text)<br />
</div>
<input type="submit" value="Post Response" />
}
Mind you, this is mostly copy paste from other views since I'm new to MVC and it worked fine with other forms. For my FooController, I have this:
public void Post([FromBody] Foo foo)
{
Foo existingFoo = this.fooRepository.GetFoo(foo.ID);
if (existingFoo != null)
{
// throw error
}
else
{
System.Diagnostics.Debug.WriteLine("MESSAGE POSTING: " + foo.Text);
}
}
When submitting from the view, the received foo isn't null (checked in other tests), but the foo.text is empty. I've tried lots of different inputs and such, but I'm just so unfamiliar with the #Html.* functions and ASP.net-MVC in general that I'm not sure where I could be going wrong.
If you need to see my repository code let me know, but I doubt it'd have an effect on this. Thanks in advance for any help.
There are 2 issues I can see with your code above:
The way the Html helper will output your fields and how that feeds into your api post
Not having your ID in the controller.
1: Outputting a field like this (#Html.TextAreaFor(tuple => tuple.Item2.Text)) will give the field the name "Item2.Text". This is an issue as that is what gets passed on the post. You will get form data with Item2.Text:dfsdsgdfg. This won't match when your API controller tries to bind. So, try outputting the text field with a set name:
#Html.TextArea("Text", #Model.Item2.Text)
2: Your Id field is not in the form... thus it won't be sent. Try using a hidden field:
#Html.Hidden("ID", #Model.Item1.ID)
Also, just a clarification, this (#Html.DisplayFor(tuple => tuple.Item1.ID)) is not jQuery.
Am using MVC 4 and want to maintain some values on postback, so they're going into hidden fields. In essence:
#using (Html.BeginForm())
{
Html.HiddenFor(model => model.EventId);
Html.HiddenFor(model => model.paymentMethodId);
}
But the hidden fields are not appearing in the rendered markup and are therefore - obviously - missing on postback.
You need to add a #, #Html.HiddenFor(). Otherwise you're just executing the helper method, but not actually doing anything with the output.
As dombenoit says, missing the "#" directive, and also need to remove the ";" from the end of each line for some reason, so the corrected code sample looks like:
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.EventId)
#Html.HiddenFor(model => model.paymentMethodId)
}
Now renders the hidden fields as expected.
I would like to do something like this:
<!--#include file="../stuff/foo/box.aspx"-->
But doing this in an ASP.Net MVC application it just feels wrong. Is there a better way of achieving the same thing in a ASP.Net MVC project ?
<%: Html.Partial("~/Views/foo/box.ascx") %>
or:
<% Html.RenderPartial("~/Views/foo/box.ascx"); %>
or the best of them all use an editor template (if this partial contains inputs for editing the view model property):
<%: Html.EditorFor(x => x.MyModelProperty) %>
or a display template (if this partial contains only display of view model property):
<%: Html.DisplayFor(x => x.MyModelProperty) %>
and their Razor equivalence
#Html.Partial("~/Views/foo/box.ascx")
#{Html.RenderPartial("~/Views/foo/box.ascx");}
#Html.EditorFor(x => x.MyModelProperty)
#Html.DisplayFor(x => x.MyModelProperty)
You should make a partial view.
You can use
Html.RenderPartial('~/Views/Login/Box.ascx');
RenderPartial allows to render part of the page using the same context. If you want to render using new context, use
Html.RenderAction("Box","Login"); //Box - Action, Login - Controller
After so many years using ASP.Net, I’m still trying to figure out how to achieve the same results using MVC.
I have a materpage with a control that is strongly type to something. When I navigate to a view of a different strongly type model ...and click on the button to execute something, I get "The model item passed into the dictionary is of type Site.Models.RegisterModel', but this dictionary requires a model item of type Site.Models.LogOnModel'".
For the sake of this example, we can take the Default MVC app that is provided with VS 2010, let’s imagine I want to change the “LogonUserControl.ascx” so that it either tells me the logged user (as it works currently) OR allow me to login from there, showing me the text boxes for username and password (therefore in this case from the home page).
So I take the control and strongly type it as:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Gioby.Models.LogOnModel>" %>
<%
if (Request.IsAuthenticated) {
%>
Welcome <b><%: Page.User.Identity.Name %></b>
[ <%: Html.ActionLink("Log Off", "LogOff", "Account")%> ]
<%
}
else {
%>
<% using (Html.BeginForm()) { %>
<div id="logon">
<div class="editor-label">
<%: Html.LabelFor(m => m.UserName)%>
<%: Html.TextBoxFor(m => m.UserName)%>
<%: Html.ValidationMessageFor(m => m.UserName, "*") %>
<%: Html.LabelFor(m => m.Password)%>
<%: Html.PasswordFor(m => m.Password)%>
<%: Html.ValidationMessageFor(m => m.Password, "*") %>
<input type="submit" value="Log On" />
</div>
<div class="editor-label">
<%: Html.ActionLink("Register here", "Register", "Account")%>
<%: Html.CheckBoxFor(m => m.RememberMe, new { #class = "pad-left" })%>
<%: Html.LabelFor(m => m.RememberMe) %>
</div>
</div>
<% } %>
<%
}
%>
Then on the HomeController, I add a procedure as:
[HttpPost]
public ActionResult Index(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
// ==>> Check Login against your DB
// Now check if param returnUrl is empty
if (!String.IsNullOrEmpty(returnUrl))
return Redirect(returnUrl);
return RedirectToAction("Index", "Home");
}
// If we got this far, something failed, redisplay form
return View(model);
}
I tested it from the home page … it works !!!
BUT when I navigate to the “Register” view (remember that the “LogonUserControl.ascx” is located inside the “MasterPage”, therefore visible from the Register view).
So when I click on the Register button, I get the error:
The model item passed into the dictionary is of type Site.Models.RegisterModel', but this dictionary requires a model item of type Site.Models.LogOnModel'.
QUESTION:
Does that mean that I will never be able to different pieces together into one view?
Let’s say I want to write an eCommerce site and on the home page I want to see “Most used Tags”, “Most bought products”, “Product of the Month”, “List of Categories” …all within the same view and each one with his own HTTP POST action.
If this is possible using MVC?
If I'm understanding the problem correctly, you have two Views that use the same MasterPage, but which are strongly typed against different ViewModels. The master page is able to include a Partial View that is also strongly typed, as long as its expected ViewModel is the same as that of the parent view. However, if you're using a view with a different ViewModel type, it doesn't know what to do.
Consider the following:
<% Html.RenderPartial("LogOn") %>
The above code implicitly includes the model data for the current view being rendered. It's exactly the same as if you had said:
<% Html.RenderPartial("LogOn", Model) %>
So this will only work if Model is a LogOnModel. Remember that the MasterPage is really a part of whatever View inherits it, so even if you're putting this in the MasterPage, it's as if you'd put the same code in every view that inherits it. So if your View's Model is not the same as the PartialView's Model, this won't work. One alternative is to use inheritance to ensure that every ViewModel will include all the information required by the Master Page. This approach is described in detail here.
But that approach means that you have to always use a factory to produce your view model, and every view model has to be somewhat aware of which master page it will use. In our product, we can use a different master page on the same view depending on what mode the user is viewing the site in, so it doesn't make sense to tie the ViewModel to that of the Master Page. We accomplish what you're describing using the RenderAction method, which allows you to render an entire controller action as if it were just a part of the larger view. Some of the advantages of this approach are discussed here.
So now you can have your MasterPage include whatever little partial views you want, but you separate the logic for building the ViewModel of each of these Views into an individual controller action that's responsible for that particular Partial View:
<% Html.RenderAction("LogOnBox") %>
The Action:
public ActionResult LogOnBox()
{
LogOnModel model = GetLogOnModel();
return PartialView("LogOnUserControl", model);
}
Now, regardless of what model your current view uses, your Master Page can include “Most used Tags”, “Most bought products”, “Product of the Month”, “List of Categories”, etc. Better still, these portions of the page can leverage output caching so they don't have to be regenerated with every page load if they don't change very often.