Html.RenderPartial and Ajax.BeginForm -> Submit is called twice - asp.net-mvc-3

I have the following index view:
#model BoringStore.ViewModels.ProductIndexViewModel
#{
ViewBag.Title = "Index";
}
<h2>Produkte</h2>
<div id='addProduct'>
#{ Html.RenderPartial("Create", new BoringStore.Models.Product()); }
</div>
<div id='productList'>
#{ Html.RenderPartial("ProductListControl", Model.Products); }
</div>
The "productList" is just a list of all products.
The addProduct renders my Create View:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<div id="dialog-confirm" title="Produkt hinzufügen" style="display:none">
#using (Ajax.BeginForm("Index_AddItem", new AjaxOptions { UpdateTargetId = "productList" }))
{
#Html.Raw(DateTime.Now.ToString());
<div>
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
</div>
<br />
<div>
#Html.LabelFor(model => model.Price)
#Html.EditorFor(model => model.Price)
</div>
<br /><br />
<div>
<input type="submit" value="Produkt hinzufügen" />
</div>
}
When submitting the form, the Index_AddItem-method in my controller is called. Unfortunately the form always calls the method twice. :(
Can someone help me out?

Don't include scripts inside your partial views! They should go the your "main" views or your _layout.cshtml.
Your problem is that you have included the jquery.unobtrusive-ajax.min.js twice in your page. Once in your Create partial and once somewhere else. Because if you include that script multiple times it will subscribe on the submit event multiple times so you will get multiple submit with a single click.
So make sure that you have include that script only once in a page. So move the jquery.unobtrusive-ajax.min.js reference into your index view.

insure that you dont have jquery.unobtrusive-ajax.min.js file duplicated in the layout
as mentioned above, and you can check this using browser Inspectors
Another problem which may cause this error that i have encountered is resting a form using jquery in the ajax request as following
$("form").trigger("reset"); //just remove this line

Related

CodeEffects RuleEditor not rendering in MVC dialog

Currently we have a full page that renders the RuleEditor without issue in the view. I've ran into an issue in getting this to render properly on a dialog.
I'm using the same exact logic to load the objects between the full view and the dialog view.
Here is what the RuleEditor looks like in the full view with an example rule:
RuleEditor Full view
Here is the RuleEditor display (bad rendering) for the same rule
RuleEditor within dialog
The div content within this dialog is:
<div id="ruleModel" name="ruleModel">
<input type="hidden" id="ruleModelData" name="ruleModel">
.
</div>
There are no html/javascript console errors. Any thoughts on why this is happening?
Thanks!
*******UPDATE*****
Here is the .cshtml content for the dialog:
#model RuleViewModel
<link href="#Url.Content("~/Content/Common.css")" rel="stylesheet"
type="text/css" />
#{
ViewBag.Title = "Edit Rule1";
Layout = null;
Html.CodeEffects().Styles()
.SetTheme(ThemeType.Gray)
.Render();
}
#using (Html.BeginSecureForm("Save", "Rule"))
{
#Html.ValidationSummary(true)
<br />
<b>Rule Name:</b> #Html.TextBoxFor(m => m.RuleName, new { id =
"RuleName", #class = "form-control" })
<fieldset>
<div class="main">
<div class="area">
<div style="margin-top:10px;">
#{
Html.CodeEffects().RuleEditor()
.Id("ruleModel")
.ShowToolBar(false)
.Mode(RuleType.Evaluation)
.Rule(ViewBag.Rule)
.DataSources(Model.DataSources)
.ContextMenuRules(Model.Rules)
.Render();
}
#{
Html.CodeEffects().Scripts().Render();
}
</div>
<div class="modal-footer">
<input class="btn btn-default" submit" type="submit"
value="Save" />
<button type="button" class="btn btn-
default">Cancel</button>
</div>
</div>
</div>
</fieldset>
}
UPDATE #2
I took from the AJAX example and did all the RuleEditor settings via the AJAX post/controller methods. That seems to work better, but now the context menu seems disconnected. (See area in Red Circle)RuleEditor In Dialog, Context Menu behind
Most likely your dialog is "disconnected" from the main editor's script and all json settings it receives from the server on load. Another possibility is that your dialog tries to render the editor before those json setting values gets to the client.

How can I get the result of a form post within a partial view to stay within its enclosing div?

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" }))
{
...
}

How to return a view from a partial view post to a Controller?

So I have a partial view "_Customer "with a text box and a save button. Currently, the partial view code, I have this:
#model CompositeViews.Models.Customer
#using (Ajax.BeginForm("Edit", "Customer", new AjaxOptions { HttpMethod = "Post", InsertionMode = InsertionMode.Replace, UpdateTargetId = "customerDiv" }))
{
<div id="customerDiv">
#Html.ValidationSummary(true)
<fieldset>
<legend>Customer</legend>
#Html.HiddenFor(model => model.CustomerId)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<p><input type="submit" value="Save" /></p>
</fieldset>
</div>
}
the view lives withing a parent view called index (which also provides the model the partial view is dependent upon):
#model CompositeViews.ViewModels.CompositeViewModel
<h2>Index</h2>
#Html.Partial("_Customer", Model.Customer)
The parent view is named Index.cshtml and is fed by a simple controller action. When I click on the Save button in the partial view, it goes to the appropriate action on the appropriate controller, but I'm not too sure how to return the updated model data BACK into the partial view.
In all the examples out there, it's a form that does an async post, but the UpdateTargetId targets a that is then filled with some type of updated content. That seems pretty straight-forward and simple.
What I'm struggling with is how to return the same form, with the updated model information using the existing view (_Customer). Basically, it's a BeginForm which targets itself with the result from the controller action, not some other div that is not part of the form.
I'd like to NOT have to rebuild all the HTML by hand that the _Customer view does for me via the MVC framework and return that for rendering. I guess I'm stuck with the form in the partial view submitting the data to the controller, and then needing a way for that same view to re-draw itself on returning from the action method.
Any ideas?
I hope I got you right and you want to show your updated on post back.
In that case you can try this:
<div id="customerDiv">
#Html.RenderAction("Edit", "Customer", Model)
</div>
and put your #using (Ajax.BeginForm()) in Edit result.

form tag doesn't render in partial view with jquery dialog. mvc3 asp.net

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.

The model item passed into the dictionary is of type... ut this dictionary requires a model item of type

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

Resources