I'm trying to check if the combination of typeId & supplementId already exists in my database. So I've added a remoteattribute to my supplementId which does this. My problem is that the validation should trigger on changing either dropdownlist. I kinda fixed this clientside with the javascript on the ddl onchange. But now I'm not able to post my form. When I click the button, it focuses the last dropdownlist but doesn't show any errors and my Post method in the controller doesn't get fired. If I execute a form.submit() in chrome console the method gets called but validation is ignored. Anyone had this issue before?
BTW this code is cleaned to a minimum so labels, errormessages, etc could be missing,
these shouldn't be the issue.
Partial view:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SupplementTypeClass>" %>
<script src="<%: Url.Content("~/Scripts/jquery-1.5.1.min.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.validate.min.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js") %>"
type="text/javascript"></script>
<% using (Html.BeginForm("AddEditSupplementType", "Supplement"))
{ %>
<%: Html.ValidationSummary(true)%>
<fieldset>
<legend>
Add type
</legend>
<div class="editor-content">
<div class="editor-label">
<%: Html.LabelFor(model => model.SupplementId)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.SupplementId, new SelectList(ViewBag.Supplements, "SupplementId", "Name", Model.SupplementId), "Select supplement", new { onchange = "$('#ddl').removeData('previousValue');$('#ddl').valid();" })%>
<%: Html.ValidationMessageFor(model => model.SupplementId)%>
</div>
</div>
<div class="editor-content">
<div class="editor-label">
<%: Html.LabelFor(model => model.TypeId)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.TypeId, new SelectList(ViewBag.Types, "TypeId", "Name", Model.TypeId), "Select type", new { id ="ddl" })%>
<%: Html.ValidationMessageFor(model => model.TypeId)%>
</div>
</div>
<div class="editor-buttons">
<input type="submit" value="Save" />
</div>
</fieldset>
<% } %>
Controller:
[HttpPost]
public ActionResult AddEditSupplementType(SupplementTypeClass sup)
{
if (ModelState.IsValid)
{
//code to insert to DB
}
return RedirectToAction("FicheAddEditSupplementType", new { supplementTypeId = sup.supplementTypeId});
}
Class:
public class SupplementTypeClass
{
#region Members
public int SupplementId { get; set; }
[RemoteAttribute("SupplementTypeCheck", "Supplement", AdditionalFields = "SupplementId")]
public int TypeId { get; set; }
#endregion
}
The Remote attribute does Ajax calls using the GET method by default, not POST.
Make your you specificy the POST method in your model
[RemoteAttribute("SupplementTypeCheck", "Supplement", AdditionalFields = "SupplementId", HttpMethod="POST")]
Related
I have a partial view with a form in it that I place on to my page using an #ajax.ActionLinK
#Ajax.ActionLink("Update File", "CreateFileVersion", new AjaxOptions() { UpdateTargetId = "CreateFileVersion", InsertionMode = InsertionMode.Replace })
and here is my partial view
#model CasWeb.Models.DataContext.FileVersion
#{
Layout = null;
}
<h4>Create File Version</h4>
#using (Html.BeginForm())
{
#Html.ValidationSummary()
<fieldset>
<legend>File Version</legend>
<div class="editor-label">
#Html.LabelFor(model => model.VersionNumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.VersionNumber)
#Html.ValidationMessageFor(model => model.VersionNumber)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ActivationTime)
</div>
<div class="editor-field">
#Html.EditorFor(m => m.ActivationTime)
#Html.ValidationMessageFor(model => model.ActivationTime)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
This all works great, the user clicks on the link and the form appears with the "CreateFileVersion" div.
The problem comes with validation. When the user submits the form it goes to my controller which checks the data and returns the partial view back if it invalid. This partial view is no longer within the "CreateFileVersion" div, it now takes over the entire page.
How can I keep the partial view returned from my contoller within the "CreateFileVersion" div after validation.
Thanks
You should use an Ajax.BeginForm inside your partial instead of Html.BeginForm. This would allow you to submit the form using an AJAX call and specify the same update target id:
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "CreateFileVersion" }))
{
...
}
i have a partial view "CreateJobLine.cshtml" that contains a form. this form when rendered using #Html.Action method creates the form fields without the form tag. i used the Html.BeginForm as well as hard coded the form (below), but in both situation its not generating the tag. I am also using jqueryui's dialog widget to display the form.
---Partial View ---
//filename: CreateJobLine.cshtml
#model Recruitment.Models.JobLine
#if(false){
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
}
<div id="addnewjoblinediv">
<form id="createjoblineform" action="#Url.Action("CreateJobLine")" method="post">
#Html.ValidationSummary(true)
<fieldset>
<legend>JobLine</legend>
#Html.Hidden("job_id", Model.JobId)
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TimeSpent)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TimeSpent)
#Html.ValidationMessageFor(model => model.TimeSpent)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.JobId)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.JobId)
#Html.ValidationMessageFor(model => model.JobId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</form>
</div>
In the edit view, I have Html.Action call to load the partial view.
---Edit View---
//filename Edit.cshtml
...
#Html.Action("CreateJobLine", "Job", new { job_id = Model.Job.JobId})
<a id="addnewjoblinelink" href="#">Add New JobLine</a>
</fieldset>
}
<script type="text/javascript">
$(document).ready(function () {
$("div#addnewjoblinediv").dialog({ autoOpen: false, modal:true, width:550, title:"Add New JobLine"});
$("a#addnewjoblinelink").click(function () {
$("div#addnewjoblinediv").dialog("open");
}
);
}
);
</script>
Here is the controller
---Job Controller---
//JobController.cs
...
[HttpGet]
public PartialViewResult CreateJobLine(int job_id)
{
var jobline = new JobLine();
jobline.JobId = job_id;
jobline.TimeSpent = 0;
return PartialView(jobline);
}
[HttpPost]
public ActionResult CreateJobLine(JobLine jobline)
{
if (ModelState.IsValid)
{
db.JobLines.Add(jobline);
db.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Edit", new { id = jobline.JobId });
}
...
call to /Job/CreateJobLine/5 gets the form content with all the form elements, but the form tag itself is missing. I want to get that form action be set to /Job/CreateJobLine post method so that I can create a JobLine.
Thank you.
I think your problem is #Html.Action. I believe it's simpler and closer to what you want to just render a partial view like this:
#{ Html.RenderPartial("CreateJobLine", new MvcApplication1.Models.JobLine { JobId = 10 }); }
I say that because when I use RenderPartial like I would normally do, the form is rendered correctly inside the dialog (all the rest of the code is how you posted it). I can't use Html.Action with the code you posted (probably because you omitted something else), so that indicates to me your problem is around that method. Good luck.
I have the following class:
public class NewCommentClass
{
public string ActionName { get; set; }
public object RouteValues { get; set; }
[Required(ErrorMessage = "Comment Required")]
public string Comment { get; set; }
public int? CommentParentID { get; set; }
}
following code in view:
NewCommentClass newCommentClass = new NewCommentClass() { ActionName = "PostComment", RouteValues = new { id = ideaItem.Ideas.IdeaID } };
Html.RenderPartial("~/Views/Shared/NewComment.ascx", newCommentClass);
and NewComment.ascx:
<% # Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NEOGOV_Ideas.Models.NewCommentClass>" %>
....
<div class="comment-new-container">
<div class="grid_1 alpha item-sidebar">
<p style="padding-top: 0.5em">
<a href="#">
<img src="<% = userAvatar %>" class="profile-photo" alt="Your Profile Picture" width="48"
height="48" /></a>
</p>
</div>
<div class="grid_8 omega">
<div class="comment-body">
<% using (Html.BeginForm(Model.ActionName, "Home", Model.RouteValues, FormMethod.Post, new { id = "FormAddComment", name = "FormAddComment" }))
{ %>
<fieldset>
<% = Html.TextAreaFor(model => model.Comment, htmlAttributes)%>
<% = Html.ValidationMessageFor(model=>model.Comment) %>
<input type="submit" value="<% = postButtonTitle %>" class="small blue awesome noborder" />
</fieldset>
<%} %>
</div>
</div>
<div class="clear">
</div>
</div>
and following post method in controller:
public ActionResult PostComment(int id, string Comment, int? CommentParentID, string referrerUrl)
{
...
}
but this validation does not work correctly.
If I enter data to textarea and click on "Submit" - all ok
But If I just click on "Submit" without data inside - got error message (it's correct), but when I enter data to textarea after this action - error message is hidden, but form is not submited!. If I add Html.ValidationSummary(true) - I one label is hidden, but second is shown.
Why so strange behaviour?
In your Html.BeginForm() command, you create an HtmlAttribute object, and you use it to set the name and id of your textarea to FormAddComment. Because this is the only field in the form, you would need to change your method signature as follows:
[HttpPost]
public ActionResult PostComment(string FormAddComment)
Your current signature doesn't receive anything from the posted form. If you use Fiddler or a similar tool to inspect what is being posted, you will see FormAddComment=[whatever was typed into the textarea] as the body of the POST sent from your browser.
I'm new to exploring MVC3 and came up with a problem.
I'm editing my Master view and want the login boxes to be visible on every page when a user isn't logged in. I've done this by using this code:
#if (Request.IsAuthenticated)
{
<text>Welcome <strong>#User.Identity.Name</strong>!
[ #Html.ActionLink("Log Off", "LogOff", "Account") ]</text>
}
else
{
Html.RenderPartial("../Account/LogOn");
}
This works when going to my normal Index method of the HomeController.
However, when going to the Index method of my NewsController I get the following error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[LeagueSite.Models.News]', but this dictionary requires a model item of type 'LeagueSite.Models.LogOnModel'.
I understand what the problem is but don't really know a sollution for it.
The view LogOn looks like this (standard MVC3 logon view):
#model LeagueSite.Models.LogOnModel
#{
ViewBag.Title = "Log On";
}
<h2>Login</h2>
<p>
Please enter your user name and password. #Html.ActionLink("Register", "Register") if you don't have an account.
</p>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.")
#using (Html.BeginForm()) {
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
#Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="editor-label">
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe)
</div>
<p>
<input type="submit" value="Log On" />
</p>
</fieldset>
</div>
}
`
Any tips/ideas?
Quick and dirty: instead of Html.RenderPartial use Html.RenderAction:
Html.RenderAction("LogOn", "Account");
and in the LogOn action of the Account controller ensure to return a PartialView or you will get a stack overflow and Cassini will crash:
public ActionResult LogOn()
{
return PartialView();
}
I think your "news" view has already a model associated to it.
maybe it starts like this?:
#model LeagueSite.Models.News
well, if so, if you are not passing a model to your partial view, then the framework assumes by default that the model for that partial is "LeagueSite.Models.News", which of course isn't what you want. You must pass the LogOnModel to your LogOn partial view like this:
Html.RenderPartial("../Account/LogOn", Model.ObjLogonModel);
this assumes that you have an instance of LogonModel into your "News" model. then you'll be able to handle the Logon action
regards
I have 2 Actions in my controller:
// GET: /Directory/
public ActionResult Index()
{
ViewModels.DirectoryIndex model = new ViewModels.DirectoryIndex();
return View(model);
}
// POST: /Directory/Filter/[viewModel]
[HttpPost]
public ActionResult Filter(ViewModels.DirectoryIndex viewModel)
{
int distance = 0;
string state = string.Empty;
if (viewModel.SelectedDistance > 0)
distance = viewModel.SelectedDistance;
else if (viewModel.SelectedState > 0)
state = viewModel.States.Where(a => a.Value == viewModel.SelectedState.ToString()).FirstOrDefault().Text;
// TODO: Add filter activities here...
return PartialView("IndexPartial", viewModel);
}
I have a View and a PartialView (NOTE: I am not using Razor!)
The view looks like:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<RainWorx.FrameWorx.MVC.ViewModels.DirectoryIndex>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<div class="Column12">
<div class="Shadow"></div>
<h2 class="h2row"><%= Model.PageTitle %></h2>
<% using (Ajax.BeginForm("Filter", new AjaxOptions { UpdateTargetId = "filteredList" })) { %>
<div class="searchDirectory">
<label title="State">State: </label>
<%= Html.DropDownListFor(a => a.SelectedState, Model.States, "-- Select One --", new { #id = "ddlStates" })%>
-or-
<label title="ZipCode">Zip Code within: </label>
<%= Html.DropDownListFor(a => a.SelectedDistance, Model.Distance, "-- Select One --", new { #id = "ddlDistance" })%>
<input type="text" id="myZip" name="myZip" />
<input type="submit" value="Filter" />
</div>
<% } %>
<div id="filteredList" class="businessCard">
<% { Html.RenderPartial("IndexPartial", Model); } %>
</div>
<div style="height: 200px;"></div>
</div>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="head" runat="server">
<link type="text/css" href="Content/css/directory.css" rel="Stylesheet" />
<script src="Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript" />
<title><%= Model.PageTitle %></title>
</asp:Content>
The PartialView looks like:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<RainWorx.FrameWorx.MVC.ViewModels.DirectoryIndex>" %>
<% foreach (var d in Model.Dealers) { %>
<div class="businessCard Outline">
<div class="businessCard Logo">
<img src="<%= Url.Content("~/Content/Images/Directory/logo01_150wide.png") %>" alt="Logo" />
</div>
<div class="businessCard Info">
<div class="businessCard Name"><%= d.Name %></div>
<div class="businessCard Address"><%= d.Address %></div>
<div class="businessCard City"><%= d.City %>, <%= d.State %> <%= d.ZipCode %></div>
<div class="businessCard Phone"><%= d.Phone %></div>
</div>
</div>
<% } %>
Now, for some reason, when I select a filter to use and submit the form it does call into the second action correctly. However, it does not refresh the PartialView, instead I get the PartailView rendered as a full view. In URL terms:
I start at http://mysite.com/Directory - select my filter, click submit.
I end at http://mysite.com/Directory/Filter when I expect to end at http://mysite.com/Directory !!
I am obviously missing something simple. I've done this before in Razor (love Razor over this mess BTW) and it all works there.
NOTE: This is a 3rd party product I am extending so don't have the luxury of converting everything to Razor.
You need to have both the following files referenced in your html. I think there is a jQuery alternative... but referencing both of these JavaScript files (which are probably already in your MVC solution) should solve your problem.
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>