I have a strange problem where the unobtrusive validations inside a partial view (which is being rendered by a Ajax.ActionLink) does not work.
This is the Partial View:
#model MyWeb.Models.PersonSkill
#using (Ajax.BeginForm("EditSkill", null, new AjaxOptions { UpdateTargetId = "skills" }, new { id = "EditSkillForm" }))
{
#Html.HiddenFor(model => model.Id)
<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>
<div class="editor-label">
#Html.LabelFor(model => model.YearsOfExperience)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.YearsOfExperience)
#Html.ValidationMessageFor(model => model.YearsOfExperience)
</div>
<p>
<input type="submit" value="Save"/>
</p>
}
And this is called by:
#Ajax.ActionLink("Edit", "LoadEditSkill", new { id = item.Id }, new AjaxOptions() { UpdateTargetId = "editSkillDialog" }, new { #class = "editSkill" })
The view is rendered fine. It posts back data to the server, but it just doesn't validate.
Many thanks to Joe Tuskan for pointing me at the right direction.
I fixed the issue by adding an OnSuccess subscriber to my call:
#Ajax.ActionLink("Edit", "LoadEditSkill", new { id = item.Id }, new AjaxOptions() { UpdateTargetId = "editSkillDialog", OnSuccess = "onSuccess" }, new { #class = "editSkill" })
and adding calling parse() like explained here:
var onSuccess = function () {
// enable unobtrusive validation for the contents
// that was injected into the <div id="result"></div> node
$.validator.unobtrusive.parse($("#editSkillDialog"));
};
Always make sure you included the necessary references to
jquery.validate.min.js and jquery.validate.unobtrusive.min.js and of course the main jquery library, this is usually the most common problem, and as i can see in your cshtml they are not present in your page either.
Related
I use the following code for the Editing Button, but clicking on the Edit button does not post it
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "PageID,GroupID,Title,ShortDescription,Text,Autor,Tags,Visit,ImageName,ShowInSlider,CreatDateTime")] Page page,HttpPostedFileBase imgUp)
{
if (ModelState.IsValid)
{
if (imgUp != null)
{
if (page.ImageName != null)
{
System.IO.File.Delete(Server.MapPath("/PageImages/" + page.ImageName));
}
page.ImageName = Guid.NewGuid() + Path.GetExtension(imgUp.FileName);
imgUp.SaveAs(Server.MapPath("/PageImages/" + page.ImageName));
}
pageRepository.UpdatePage(page);
pageRepository.save();
return RedirectToAction("Index");
}
....
I have separate data layer and repository and I use the following code for the Editing Pages Controller, but with clicking on the Edit button does not post form. Though it works well for creation and delete btn. my view code is:
<div class="form-horizontal">
<h4>Page</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.PageID)
#Html.HiddenFor(model => model.Visit)
#Html.HiddenFor(model => model.CreatDateTime)
#Html.HiddenFor(model => model.ImageName)
<div class="form-group">
#Html.LabelFor(model => model.GroupID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("GroupID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.GroupID, "", new { #class = "text-danger" })
</div>
</div>
....
<div class="form-group">
#Html.LabelFor(model => model.ImageName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="file" name="imgUp" id="imgUp"/>
#Html.ValidationMessageFor(model => model.ImageName, "", new { #class = "text-danger" })
#if (Model.ImageName != null)
{
<img src="/PageImages/#Model.ImageName" class="thumbnail" style="max-width:150px" />
}
.....
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
i trace my code and find this eror:
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Request","time":"2018-04-25T08:10:44.3663705Z","tags":{"ai.internal.sdkVersion":"web: 2.0.0.25000","ai.device.roleInstance":"Laptop-erfan","ai.operation.name":"GET PageGroup
above horizontal form tag is this code:
#model DataLayer.Page
#{
ViewBag.Title = "Edit";}<h2>Edit</h2>#using (Html.BeginForm("Edit", "Pages", FormMethod.Post, new { enctype = "multipart/form-data" })){ #Html.AntiForgeryToken()
As mentioned in the comments it doesn't look like you have a form in your view. You can add one using:
#using (Html.BeginForm()) {
<!-- form contentshere -->
}
BeingForm has several overloads as well that you can use to change where it goes to, form method (GET/PUT) and set html attributes.
You need to add the complete form page into a Form tag.
please Use
#using (Html.BeginForm()) {
//Put your complete code inside this form...
}
It will create the Form tag with specified actions and type.
You can also specific the custom action method and type of the method as well.
The current situation:
For the essence of this problem, I have two database tables/models. I'm using an AJAX form to update the displayed model data in list form from each table when a new model is created and added. In effect, the page never has to reload to display any changes to the lists.
I'm displaying the create form statically for each model above the list of items. This works fine for a model that has no foreign key dependencies. However, one of my models also has a select list in the create form that is tied to the other model list on the page.
The problem:
When I add a record for the simpler model, the select list for the create form of the model with the foreign key dependency does not update to include the changes. I know why it doesn't update and I think that I need to use AJAX to either recreate the create form in-place entirely or update just the select list.
Is there a way to use the AJAX form to not only update the list of the model that I'm adding an item to but also update the div that contains the create form at the same time?
I believe I have included all the relevant code to hopefully give a clearer picture of what I'm asking
Sample Create form for the simpler model:
#using (Ajax.BeginForm("_CreateCategory", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "list-categories"
}))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<label class="control-label col-md-2">Name: </label>
<div class="col-md-5">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
<div class="col-md-5">
<input type="submit" value="Add" class="btn btn-success" />
</div>
</div>
</div>
}
Sample model with foreign key dependency
#using (Ajax.BeginForm("_CreateType", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "list-types"
}))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<label class="control-label col-md-2">Name: </label>
<div class="col-md-offset-1 col-md-6">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Category: </label>
<div class="col-md-6">
#Html.DropDownList("CategoryID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CategoryID, "", new { #class = "text-danger" })
</div>
<div class="col-md-3">
<input type="submit" value="Add" class="btn btn-success" />
</div>
</div>
</div>
}
Sample list partial view for the model with the foreign key
<div id="list-types">
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Category.Name)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Category.Name)
</td>
<td>
#using (Ajax.BeginForm("DeleteType", new { id = item.ID }, new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "list-types"
}))
{
#Html.AntiForgeryToken()
<button type="submit" class="no-default">
<span class="glyphicon glyphicon-remove"></span>
</button>
}
</td>
</tr>
}
</table>
</div>
Controller action for adding simpler model
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _CreateCategory([Bind(Include = "ID, Name")] Category category)
{
if (ModelState.IsValid)
{
db.Categories.Add(category);
db.SaveChanges();
}
var categories = db.Categories;
return PartialView("_ListCategories", categories.ToList());
}
Sample Index page code that displays the lists and create forms
<div class="col-lg-4 block">
<h3>Categories</h3>
#Html.Action("_CreateCategory")
#Html.Action("_ListCategories")
</div>
<div class="col-lg-4 block">
<h3>Types</h3>
#Html.Action("_CreateType")
#Html.Action("_ListTypes")
</div>
You wont be able to do this easily using the Ajax.BeginForm() method, and in any case, its unnecessary extra overhead to be returning the whole table again when your only adding one row to it.
Replace Ajax.BeginForm() with just <form id="createcategory"> and use $.ajax() to submit the form to create a new Category, and return its ID. In the success callback, you can then add a new row to the table and add a new <option> element to the <select> in the 2nd form
var url = '#Url.Action("_CreateCategory")'
var categorySelect = $('#CategoryID');
$('#createcategory').submit(function() {
if (!$(this).valid()) {
return; // exit and display validation errors
}
var category = $(this).find('input[name="Name"]').val(); // see notes below
var formdata = $(this).serialize();
$.post(url, formdata, function(result) {
if (result.success) {
// Add option
categorySelect.append($('<option></option>').val(result.id).text(category));
// Add new table row
.... // You have not shown the view for _ListCategories but it might be somethng like
var cell = $('<td></td>').text(category);
var row = $('<tr></tr>').append(cell);
$('#yourTableID').append(row);
} else {
.... // check for errors, update the associated placeholder generated by ValidationMessageFor()
}
}).fail(function (result) {
// Oops something went wrong
});
}
$('#createtype').submit(function() {
// similar to above, but just add new table row based on the values of the form controls
});
and the controller method would be
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult _CreateCategory(Category category)
{
if (ModelState.IsValid)
{
db.Categories.Add(category);
db.SaveChanges();
// Get the new ID
int id = category.ID;
return Json(new { success = true, id = id });
}
// Get the validation errors
var errors = ModelState.Keys.Where(k => ModelState[k].Errors.Count > 0).Select(k => new { propertyName = k, errorMessage = ModelState[k].Errors[0].ErrorMessage });
return Json(new { success = false, errors = errors });
});
A few side notes:
Your view includes 2 form controls for Name so your generating
duplicate id attributes which is invalid html. Consider removing
the id attribute (using new { id = "" } or giving one of them a
different id attribute.
You do not need the [Bind] attribute, and in any case you not
sending a value for ID so that should be excluded if your do keep
it.
Your editing data so you should be using a view model, and in the
case of the 2nd model, it will contain properties int
SelectedCategory and IEnumerable<SelectListItem> CategoryList and
use DropDownListFor(m => m.SelectedCategory, Model.CategoryList,
"Please select", new { ... }) in the view
Use #Html.LabelFor(m => m.yourProperty) to correctly generate your
<label> elements (a <label> is an accessibility element and
clicking on it sets focus to the associated control which does not
happen with your current code)
I stumbled across a better way to display my comment form within the post window with <p id="createPostButton">#Html.Action("Create", "Comment", new { id = Model.PostId })</p> (I was originally just trying to create a button to take you to the comment page sending the post id). However, I now get an error when I try to pass back the post/details/{id} view in the CommentController. It keeps trying to look in comment or shared folders passing either post OR details/{id} instead of post/details/{id}.
Post/Details Razor HTML file:
#model FantaC.Models.Post
#{
ViewBag.Title = #Html.DisplayFor(model => model.PostName);
}
<h2>#Html.DisplayFor(model => model.PostName)</h2>
<div class="row">
<div class="col-md-8 whiteBorder scroll">
<div class="postName">
<h4>Written by: #Html.DisplayFor(model => model.UserName)</h4>
<img src="#Html.DisplayFor(model => model.PostImage)" />
</div>
<div class="postContent">
<p>#Html.DisplayFor(model => model.PostContent)</p>
</div>
</div>
<div class="col-md-4 whiteBorder scroll">
<h4>Comments</h4>
#foreach (var comment in Model.PostComments)
{
<h5>#Html.DisplayFor(modelItem => comment.UserName)</h5>
<h5>#Html.DisplayFor(modelItem => comment.CommentSubject)</h5>
<p>#Html.DisplayFor(modelItem => comment.CommentContent)</p>
<p>
#Html.ActionLink("Edit", "../Comment/Edit", new { id = comment.CommentId }) |
#Html.ActionLink("Details", "../Comment/Details", new { id = comment.CommentId }) |
#Html.ActionLink("Delete", "../Comment/Delete", new { id = comment.CommentId })
</p>
}
<p id="createPostButton">#Html.Action("Create", "Comment", new { id = Model.PostId })</p> <!--**********This is the line that is important-->
#*#=Html.RenderAction("Create", "Comments", new { postId = Model.PostId });*#
#*#Html.Partial("Comments")*#
</div>
</div>
<p>
#*#Html.ActionLink("Add a Comment", "Create", "Comment")*#
#Html.ActionLink("Comment", "Create", "Comment", new { id = Model.PostId }, null) |
#Html.ActionLink("Back to List", "Index")
The Comment/Create Razor HTML file that is getting pulled in by the Html.Action:
#model FantaC.Models.Comment
#{
Layout = null;
}
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Comment</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.CommentSubject, htmlAttributes: new { #class = "control-label col-md-10 displayBlock" })
<div class="col-md-12">
#Html.EditorFor(model => model.CommentSubject, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CommentSubject, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CommentContent, htmlAttributes: new { #class = "control-label col-md-10 displayBlock" })
<div class="col-md-12">
#Html.EditorFor(model => model.CommentContent, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CommentContent, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
#*<div>
#Html.ActionLink("Back to List", "Index")
</div>*#
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The important section from the CommentController:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(string id, [Bind(Include = "CommentSubject,CommentContent")] Comment model)
{
if (ModelState.IsValid)
{
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());
var commentId = (23817 + db.Comment.Count()).ToString().PadLeft(10, '0');
var comment = new Comment
{
CommentId = commentId,
PostId = id,
UserName = user.UserName,
PostTime = DateTime.Now,
CommentSubject = model.CommentSubject,
CommentContent = model.CommentContent
};
db.Comment.Add(comment);
db.SaveChanges();
return View("Details/" + id, "Post");
}
return View(model);
}
I also tried return View("../post/details/" + id); to no avail. How can I get back up to the post view url (post/details/{id} from the CommentController?
As a side note, I had it almost working by taking out the returns and making the method void, but after clicking the submit comment button the whole comment/create form would disappear. I would be fine going back to that way of doing things if anyone knows a way to make the form stay after clicking the create comment button.
Thanks for any help! :)
Edit:
I forgot to mention that I tried this too. It returns an error that looks like this:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Child actions are not allowed to perform redirect actions.
Source Error:
Line 32: }
Line 33:
Line 34: #Html.Action("Create", "Comment", new { id = Model.PostId })
Line 35:
You should follow the PRG (POST-REDIRECT-GET) pattern. After saving the comment, you should redirect to the post details page.
You may use the RedirectToAction method to return a RedirectResponse back to the browser which will make a new GET request to the post details action method.
So replace
return View("Details/" + id, "Post");
with
return RedirectToAction("Details" , "Post", new {id=id});
I have a popup dialog inside the partial view. When a user clicks "Create" button, a popup dialog is shown, inside the popup dialog is a form where user types information and the information is then save into the database. I got everything working and didn't get any errors but the data I typed didn't get saved into the database.
Please help, I am new to programming, Thank you.
Index page:
<li>#Html.Partial("_Create")</li>
In my _Create partial view, I scaffolded the partial view using the Create template
#model test.Models.Question
<li>Create</li>
<div class="dialog-form-create-question" title="Create a question">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-11">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-8">
<input type="submit" value="Submit" class="btn btn-primary"/>
</div>
</div>
</div>
}
</div>
My JQuery scripts for the form dialog nested inside the partial view:
$(document).ready(function () {
$(".dialog-form-create-question").dialog({
autoOpen: false,
height: 510,
width: 800,
modal: true,
draggable: false,
resizable: false
});
$('.create-question').click(function () {
$('.dialog-form-create-question').dialog("open");
});
$('.cancel-button').click(function () {
$('.dialog-form-create-question').dialog("close");
});
});
In my Home controller, I changed the ActionResult Create(from scaffolding) to _Create:
// GET: Home/Create
public ActionResult _Create()
{
return View();
}
// POST: Home/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _Create([Bind(Include = "Id,Title")] Question question)
{
if (ModelState.IsValid)
{
db.Questions.Add(question);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(question);
}
please try changing
#using (Html.BeginForm())
{
}
to
#using (Html.BeginForm("_Create","Home",FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-11">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
<input type="submit" value="submit"/>
</div>
</div>
</div>
}
and see that your debugger strikes to _Create (post) method in your home controller with the values
I'm using MVC 4 and Entity Framework to develop an web app. I have a table which contains persons. There is also an Edit button which invokes a modal window and thanks to it, the user can edit a person. I'm using a partial view to do so.
My question is : in my action, I return a View but I just want that when I click on the Save button, the modal window disappear and my table is updated. Any idea?
The actions :
[HttpGet]
public ActionResult EditPerson(long id)
{
var person = db.Persons.Single(p => p.Id_Person == id);
ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name", person.Id_ProductPackageCategory);
return PartialView("_EditPerson", person);
}
[HttpPost]
public ActionResult EditPerson(Person person)
{
ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name", person.Id_ProductPackageCategory);
if (ModelState.IsValid)
{
ModelStateDictionary errorDictionary = Validator.isValid(person);
if (errorDictionary.Count > 0)
{
ModelState.Merge(errorDictionary);
return View(person);
}
db.Persons.Attach(person);
db.ObjectStateManager.ChangeObjectState(person, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
The partial view (actually, the modal window) :
#model BuSIMaterial.Models.Person
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Edit</h3>
</div>
<div>
#using (Ajax.BeginForm("EditPerson", "Person", FormMethod.Post,
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "table"
}))
{
#Html.ValidationSummary()
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.Id_Person)
<div class="modal-body">
<div class="editor-label">
First name :
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.FirstName, new { maxlength = 50 })
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
Last name :
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.LastName, new { maxlength = 50 })
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
National number :
</div>
<div class="editor-field">
#Html.EditorFor(model => model.NumNat, new { maxlength = 11 })
#Html.ValidationMessageFor(model => model.NumNat)
</div>
<div class="editor-label">
Start date :
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.StartDate, new { #class = "datepicker", #Value = Model.StartDate.ToString("yyyy/MM/dd") })
#Html.ValidationMessageFor(model => model.StartDate)
</div>
<div class="editor-label">
End date :
</div>
<div class="editor-field">
#if (Model.EndDate.HasValue)
{
#Html.TextBoxFor(model => model.EndDate, new { #class = "datepicker", #Value = Model.EndDate.Value.ToString("yyyy/MM/dd") })
#Html.ValidationMessageFor(model => model.EndDate)
}
else
{
#Html.TextBoxFor(model => model.EndDate, new { #class = "datepicker" })
#Html.ValidationMessageFor(model => model.EndDate)
}
</div>
<div class="editor-label">
Distance House - Work (km) :
</div>
<div class="editor-field">
#Html.EditorFor(model => model.HouseToWorkKilometers)
#Html.ValidationMessageFor(model => model.HouseToWorkKilometers)
</div>
<div class="editor-label">
Category :
</div>
<div class="editor-field">
#Html.DropDownList("Id_ProductPackageCategory", "Choose one ...")
#Html.ValidationMessageFor(model => model.Id_ProductPackageCategory) <a href="../ProductPackageCategory/Create">
Add a new category?</a>
</div>
<div class="editor-label">
Upgrade? :
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Upgrade)
#Html.ValidationMessageFor(model => model.Upgrade)
</div>
</div>
<div class="modal-footer">
<button class="btn btn-inverse" type="submit">Save</button>
</div>
}
</div>
And my script which invokes the modal :
$(document).ready(function () {
$('.edit-person').click(function () {
var id = $(this).data("id");
var url = '/Person/EditPerson/'+id;
$.get(url, function(data) {
$('#edit-person-container').html(data);
$('#edit-person').modal('show');
});
});
});
a couple of changes would need to be made but here is what I would do this case
1) change the EditPerson post method from an actionresult to a JsonResult
[HttpPost]
public JsonResult EditPerson(Person person)
{
// code here to save person
bool success = true; // somehow determine if the save was successful
string msg = ""; // error message is needed?
return JsonResult(new {success,msg, person});
}
2) Add a javascript function to close the modal
function closeModal(response){
// the response is the Json Result sent back from the action
if (response.success === true){
// actually got a true response back
}
$('#edit-person').modal('show'); // or similar code
}
3) Then Update your Ajax call to perform code on when its successful
#using (Ajax.BeginForm("EditPerson", "Person", FormMethod.Post,
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "table",
OnSuccess = "closeModal(response);" // or javascript code to close the modal, you can also
}))
{ ...
a couple of tips
I don't like the MVC ajax helpers. I think they are bloated and I feel there are other frameworks better at it. Thats my opinion. To each their own though. I would prefer to use the jQuery ajax library myself. I think its easier to use but again, its up to you.
The OnSuccess means on "Server Success" not save success. so be careful.
Disclaimer: I wrote this while tired and so it might not be 100% let me know of any issues.
Good luck
In your POST action you could return the following:
return Json(new { error = false, message = "Person edited." });
In the AjaxOptions in Ajax.BeginForm add this:
OnSuccess = "Modal.onAjaxSuccess"
Then somewhere, say in script.js:
function onAjaxSuccess(data, status, xhr) {
if (data.error) {
$.notify({
type: "error",
text: data.message
});
}
else {
$('.modal').modal('hide');
}
}
This will close the window, but I'm still unable to get the darkened screen associated with Bootstrap modals to go away, it also won't update the DIV using AJAX - maybe Darin can shed some light?
If you're still wondering how to do this, this is how:
You have a GET action that returns the list of people:
[HttpGet]
public ActionResult People()
{
return PartialView("_ListOfPeoplePartial");
}
Then have a JS function that fires when you click save (i.e. btn-save-new-person) on the modal that allows you to create new people:
$(function () {
$(document.body).on('click', '#btn-save-new-person', function (e) {
$('#create-new-person-modal').modal('hide');
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
var url = "/Home/People";
$.get(url, function (data){
$('#list-of-people').html(data);
});
});
});
in my action, I return a View but I just want that when I click on the Save button, the modal window disappear and my table is updated. Any idea?
Instead of returning a view from this controller action you could return a partial view containing the table. And then in the success callback of the AJAX call simply update the corresponding container.