I'm new to MVC Razor.
I have this view:
#model SuburbanCustPortal.Models.CustomerModel
#{
ViewBag.Title = "Customer Summary";
}
<h2>Customer Summary Screen</h2>
<p>
Please select an account below or add an existing 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>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.")
<div>
<fieldset>
<legend>Existing Accounts</legend>
#Html.Action("ExistingAccounts2")
<p>
<input type="submit" value="Add an Account" />
</p>
</fieldset>
</div>
}
Which calls this method:
[Authorize]
public ActionResult ExistingAccounts2()
{
return PartialView("ExistingAccounts", _client.RequestCustomersForAccount(User.Identity.Name));
}
Which in turn calls this partial view:
#model IEnumerable<SuburbanCustPortal.SuburbanService.CustomerData >
<br />
<br />
<table>
#if (Model != null)
{
foreach (var usr in Model)
{
<tr>
<td>
<input id="btnShowCustomer" name="btnShowCustomer2" type="submit" value="View"/>
</td>
<td>
#usr.AccountId
</td>
<td>
#usr.Name
</td>
#* <td>
#usr.DeliveryStreet
</td>*#
</tr>
}
}
</table>
<br />
Which ends up displaying this:
This works up to this point.
What I want to so is be able to click on the button next to the customer's name and it pull up the customer's account.
How do I tie that customer to the button to know who to pull up and how do have the button click pull it up?
You need to pass the Customer Number back once the button is clicked:
If you have the customer number as a property in the Model you could do something like:
<input id="btnShowCustomer" data-customerNumber="#usr.CustomerNumber" />
You could then POST this data to the Server using an #Html.ActionLink, #Ajax.ActionLink, or jQuery:
Action Link
#Html.ActionLink("LoadInfo", "Info", new {customerId=#usr.CustomerNumber})
jQuery
$("#btnShowCustomer").click(function() {
var customerId = $("#btnShowCustomer").attr("data-customerNumber");
$.ajax({
type: "POST",
data: "customerId=" + customerId,
url: '#Url.Action("MyAction", "MyController")',
success: function (result) {
}
});
I think this would do the trick ! oid would be the id of the customer (i dont think the path is ok :) )
#Ajax.RawActionLink("Action", "Controller", new { oid = '#Model.customerID'}, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "the view you want to show" }, new { id = "btnNewB", #class = "your btn class" })
good luck ;)
Related
I had made a project in ASP.NET to which you can upload, download, delete, and preview files. Whenever I upload them (as an admin) I upload them by category, so that whenever the user is on the site and wants to view a specific file that should be placed in a specific category, he should click that category first to have the specific file displayed. Problem is: when you log in to the site as a normal user, at first, ALL files are displayed, and then, you can choose the category and only the files from that category is displayed. What can I do in case if I want to have all the files displayed back, like in the first instance? For example, to have a "show all" button to press so you can re-see what is displayed at the very beginning, before clicking on any other category.
#model IEnumerable<Proiect2PracticaClona.Models.Files>
<center>
<h1>Suntem fericiti</h1>
<h2>Ca ne merge proiectu</h2>
<hr />
#if (User.IsInRole("Admin"))
{
<form methord="post" enctype="multipart/form-data" asp-controller="Home" asp-action="Index">
<input type="file" name="fifile" />
#Html.RadioButton("category", "incepator")
#Html.RadioButton("category", "intermediar")
#Html.RadioButton("category", "admin")
<input type="submit" value="Upload" />
<hr />
</form>}
<div>
File Name:<input id="search" onkeyup="search()" placeholder="cauta"/>
</div>
<table class="table">
<ul>
<li class="active">#Html.ActionLink("Incepator", "Index", "Home", new { id = "incepator" })</li>
<li class="active">#Html.ActionLink("Intermediar", "Index", "Home", new { id = "intermediar" })</li>
<li class="active">#Html.ActionLink("Admin", "Index", "Home", new { id = "admin" })</li>
</ul>
<tr>
<th>File Name</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.info</td>
<td>Download</td>
#if (User.IsInRole("Admin"))
{
<td>Delete</td>
}
</tr>
}
</table>
#section scripts
{
<script>
function search() {
$("tr").each(function (index, value) {
if (index > 0 && !$(this).find("td")[0].innerText.toLowerCase().includes($("#search").val().toLowerCase())) {
$(this).attr("hidden", true);
} else {
$(this).removeAttr("hidden");
}
console.log(value);
})
}
</script>
}
</center>
I have a view that lists a bunch of items. I'm trying to make it so that when a user clicks on the "Action Event" for one of these items (from a table row), a pop-up will appear. The user can then update same information about this item, and either submit the information or close it. Regardless of which option they choose, I'm trying to get the pop-up window to close.
I'm 90% there, I just can't seem to work out one little detail - closing the popup after the submit button is pressed! A lot of the solutions I have seen don't appear to be working, and I just seem to be having some trouble tweaking them to work with my issue. Given the following code, what changes do I need to do to make this work?
Here is what I have:
View
Index.cshtml
<table>
#foreach (var item in Model)
<tr>
<td colspan="5" align="right">
Action Event
</td>
</tr>
}
</table>
<div id="myModal" class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div id="myModalContent"></div>
</div>
</div>
</div>
<script>
var TeamDetailPostBackURL = '/Database/Edit';
$(function () {
$(".anchorDetail").click(function () {
var $buttonClicked = $(this);
var id = $buttonClicked.attr('data-id');
var options = { "backdrop": "static", keyboard: true };
$.ajax({
type: "GET",
url: TeamDetailPostBackURL,
contentType: "application/json; charset=utf-8",
data: { "Id": id },
datatype: "json",
success: function (data) {
$('#myModalContent').html(data);
$('#myModal').modal(options);
$('#myModal').modal('show');
},
error: function () {
alert("Dynamic content load failed.");
}
});
});
});
</script>
Popup View
Edit.cshtml
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.AID)
<table>
<tr>
<td>#Html.LabelFor(model => model.Comment)</td>
<td>#Html.TextAreaFor(model => model.Comment, new { #class = "form-control", rows = "5" })</td>
</tr>
<tr>
<td><input type="submit" value="Save" class="btn btn-primary" id="btnSave"/></td>
<td><button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button></td>
</tr>
</table>
</div>
}
Controller
DatabaseController.cs
public ActionResult Index()
{
return View(db.ActionableEvents.ToList());
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ActionableEvents actionableEvents = db.ActionableEvents.Find(id);
if (actionableEvents == null)
{
return HttpNotFound();
}
return View(actionableEvents);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "AID,Comment")] ActionableEvents actionableEvents)
{
if (ModelState.IsValid)
{
db.Entry(actionableEvents).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(actionableEvents);
}
I did see this resource here: asp.net submit button close Jquery Ajax, but I'm just not seeing how I would be able to tweak this into what I've got going on right now.
The cancel button I have right now works perfectly. Is there some way to use data-dismiss for my submit button and have it still save the data like I have for the cancel button? I've also seen some solutions use an onClick() parameter in the submit button, but then it would use a window.close() option. I don't want the entire window to close, nor do I want the user to be prompted about it either.
What is a good way I can approach this problem? I want my submit button to work just like my cancel button, only save the data. Thanks in advance for any advice!!!
Can you try the following in your Index.cshtml (make sure you set an id for the form and correct it below):
$("form").submit(function(){
$('#modal').modal('toggle');
});
If you want to make an AJAX request to the server and save the data you can do as follows (just include the code below in a click event on the dismiss button from the modal):
$.ajax({
type: "POST",
url: "SaveData",
content: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(data),
success: function (result) {
// do something
},
error: function (result) {
// do something
}
});
And have a MVC action similiar to:
[HttpPost]
public JsonResult SaveData()
{
// save data
}
Edit:
After a second reading of your question, you need to make Edit.cshtml a partial view, then on Index.cshtml include your partial view in the div for the modal like this:
<div id="myModal" class="modal">
<div class="modal-dialog">
<div class="modal-content">
#Html.Partial("_EditView")
</div>
</div>
</div>
And your JS should look like this:
$("form").submit(function () {
e.preventDefault();
formData = $(this).serialize();
$.ajax({
type: "POST",
url: "SaveData",
content: "application/json; charset=utf-8",
dataType: "json",
data: formData ,
success: function (result) {
// do something
},
error: function (result) {
// do something
}
});
$('#modal').modal('toggle');
});
The JS should be in the Index.cshtml because that's where your partial exists, try it and you'll see.
So, after a lot of playing around, I was able to come up with the following solution:
View
Index.cshtml
<table>
#foreach (var item in Model)
<tr>
<td>
<button class="btn btn-primary" onclick="ActionAway(#item.AID)">Action Event</button>
</td>
</tr>
}
</tbody>
</table>
<div class="modal fade" id="myModal1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
×
<h3 class="modal-title">Action This Event</h3>
</div>
<div class="modal-body" id="myModalBodyDiv1">
</div>
</div>
</div>
</div>
</div>
<script>
var ActionAway = function (theid) {
var url = "/Database/Edit?id=" + theid;
$('#myModalBodyDiv1').load(url, function () {
$('#myModal1').modal("show");
})
}
</script>
Pop-up View
Edit.cshtml
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.AID)
<table>
<tr>
<td>#Html.LabelFor(model => model.Comment)</td>
<td>#Html.TextAreaFor(model => model.Comment, new { #class = "form-control", rows = "5" })</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Save" class="btn btn-primary" id="btnSave"/>
<button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button>
</td>
</tr>
</table>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
<script>
$(document).ready(function () {
$("#btnSave").click(function () {
$.ajax({
success: function () {
$("#myModal").modal("hide");
}
})
})
})
</script>
The controller I was able to leave as it was without making any changes. Thanks again for all the help!
I am working on a MVC website and for my delete function I decided to use jQuery UI Dialog to display a popup style dialog box for the user to confirm that they wish to delete the object. My problem is that it is not displaying as intended, when I select to delete I can see my partial view dialog popup for a split second before I am redirected to another page that displays my confirmation message and the button to delete.
This is my delete controller:
//Deletes a selected club
[HttpGet]
public ActionResult DeletePartialView(int? id) //Original: public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Club club = db.Clubs.Find(id);
if (club == null)
{
return HttpNotFound();
}
return PartialView(club);
}
[HttpPost, ActionName("DeletePartialView")]
public ActionResult DeleteConfirmed(int id) //Original: public ActionResult DeleteConfirmed(int id)
{
Club club = db.Clubs.Find(id);
var MembersToDelete = club.ClubMembers.ToList();
foreach (var item in MembersToDelete)
{
db.ClubMembers.Remove(item);
}
db.Clubs.Remove(club);
db.SaveChanges();
return RedirectToAction("Index");
}
This is the Delete button and the partial view in its div:
#Html.ActionLink("Delete", "Delete", new { id = item.ClubID }, new { #class = "btn btn-danger btn-xs" }) |
#*#Html.ActionLink("Delete Partial", "DeletePartialView", new { id = item.ClubID }, new { #class = "btn btn-danger btn-xs" })*#
#Html.ActionLink(
"Delete Partial",
"DeletePartialView",
new { id = item.ClubID },
new
{
#class = "btn btn-danger btn-xs",
id = "deleteClub-opener" //Button ID
})
#* Delete Club Popup*#
<div id="DelteClub-dialog" title="Delete Club">
#Html.Partial("DeletePartialView", new ultimateorganiser.Models.Club())
</div>
This is the jQuery code:
//Delete Club Dialog Window with effects
$(function () {
$("#DelteClub-dialog").dialog({
autoOpen: false,
height: 500,
width: 600,
show: {
effect: "clip",
duration: 500
},
hide: {
effect: "highlight",
duration: 1000
}
});
//Open Delete Club Dialog Window
$("#deleteClub-opener").click(function () {
$("#DelteClub-dialog").dialog("open");
});
})
;
This is how it is currently displaying:
This is what my DeletePartialView looks like:
#model ultimateorganiser.Models.Club
#{
ViewBag.Title = "Delete";
}
<h3 class="text-warning">Are you sure you want to delete this club?</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-danger" />
#Html.ActionLink("Back to List", "Index")
</div>
}
So far your are good now. To make the delete work add following in your Delete partial view after begin form
<input type="hidden" name="id" value="#Model.Id"/>
please check this code.and tell me another problem for using the dialog box.
only use this library
<html>
<head>
<link href="~/library/jquery-ui.min.css" rel="stylesheet" />
<script src="~/library/jquery.js"></script>
<script src="~/library/jquery-ui.min.js"></script>
</head>
<div>
<button id="btnCreate" class="btn-btn-primary">open the dialog</button>
</div>
<script type="text/javascript">
$(document).ready(function () {
$(function () {
$.noConflict(true);
$("#dialog").dialog({
autoOpen: false,
draggable: true,
resizable: true,
dialogClass: "alert",
modal: true
});
$("#btnCreate").click(function () {
$('#dialog').dialog('open');
});
});
});
<body>
<div id="dialog" style ="display:none" class="form" title="Basic dialog">
<table>
<tr>
<th>Name</th>
</tr>
<tr>
<th>Name</th>
<td><input type ="text" id="txtName" style= "width:200px" />
</tr>
<tr>
<th>Age</th>
<td><input type ="text" id="txtAge" style= "width:200px" />
</tr>
<tr>
<td><input type="submit" value="Create" id="btnCreateId" class="btn btn-Sucess" />
<td><input type="button" value="Cancel" id="txtCancel" class="btn btn-danger"/>
</tr>
</table>
</div>
</body>
<html>
You can use preventDefault in the jQuery binding.
$("#deleteClub-opener").click(function (e) {
e.preventDefault();
$("#DelteClub-dialog").dialog("open");
});
Alternatively, you can also return false in the binding function to prevent event propagation.
I need a little help with this since I am very new to AJAX in general. In a given page that I have (a view) I display a button which brings up a form. What I ultimately want is to pass the data input in that form to a controller inside my application. I know there are plenty of tutorials on how to do it out there...however, I seem to have a problem understanding how this is done; therefore, I want to traverse this step-by-step. I just simply want to display a different view after the user clicks on the "Save" button on the dialog. I hope that is clear. Here is my HTML + jQuery
#model AccommodationEditViewModel
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<table>
<tr>
<td>
#Html.ActionLink("Back to list", "List", "Accommodation")
</td>
</tr>
<tr>
<td>
#if ( Model.Accommodation.LocaleID != Guid.Empty)
{
#Html.DisplayAccommodation(IAccommodationDisplay);
}
</td>
</tr>
</table>
<div class="genericform">
<form id="form" method="post">
#Html.AccommodationEditDisplay()
<table>
<tr>
<td>
#Html.ActionLink("Add New Address", "", "", new { id = "addaddresses" }, null)
</td>
</tr>
#if (Model != null && Model.Accommodation.Addresses.Count() == 0)
{
<tr>
<td>
This Locale Contains No Addresses
</td>
</tr>
}
else
{
foreach (Address address in Model.Accommodation.Addresses)
{
<tr>
<td>
#address.Address1
</td>
</tr>
}
}
</table>
<br /> <br />
<input type="submit" name="command" value="Save" />
<input type="submit" name="command" value="Delete" />
</form>
</div>
<button id="opener">Add Address</button>
<div id="dialog" title="Add Address" style="display:none;">
<label for="Address1">Address: </label><input id="Address1" />
<label for="Address2">Address 2: </label><input id="Address2" />
<label for="City">City: </label><input id="City" />
<label for="State">State: </label><input id="State" />
<label for="PostalCode">Postal Code: </label><input id="PostalCode" />
</div>
<script type="text/javascript" src="~/Scripts/jquery-1.7.1.js"></script>
<script type="text/javascript" src="~/Scripts/jquery-ui-1.8.20.js"></script>
<link type="text/css" href="~/Content/themes/base/jquery.ui.all.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function () {
$("#dialog").dialog({
autoOpen: false,
show: {
effect: "explode",
duration: 250
},
hide: {
effect: "explode",
duration: 250
},
buttons: {
"Save": {
text: "Save",
class: "",
click: function () {
//**redirect here**
$(this).dialog("close");
}},
"Cancel": {
text: "Cancel",
class: "",
click: function () {
$(this).dialog("close");
}
}},
modal: true
});
$("#opener").click(function () {
$("#dialog").dialog("open");
});
});
</script>
I have tried using $.ajax({}) and setting this: Url: "/Areas/Website/Controller/Action
but scripting stops working at that point.
Any and all help is appreciated! Thank you!
EDIT
Do I even need to use AJAX at all? I just want to pass the information in that form (inside the dialog) to a controller.
Ok, try replacing your <form id="form" method="post"> form fields </form> with
#using (Html.BeginForm("NameOfControllerMethod", "NameOfControllerClass"))
{
<!-- fields for gathering data, your input fields essentially -->
}
THEN you need to go to your controller class, and add [HttpPost] above your controller method, like this:
[HttpPost]
public ActionResult MethodName(AccomodationEditViewModel viewModel) {
//do stuff in here with the viewModel, for example viewModel.Location, or viewModel.Name
}
NOTE that the [HttpPost] requires that you add a new "using" insert at the top of your controller class.
The NameOfControllerMethod is the method that has the HttpPost above it. The name of the controller class is like "MyClass", coming from the controller named MyClassController, as an example.
Try this:
window.location = "/Areas/Website/Controller/Action";
inside your click function.
I'm using MVC 4 and Entity Framework to develop an intranet web application. I have a list of persons which can be modify by an edit action. I wanted to make my app more dynamic by using modal forms. So I tried to put my edit view into my Bootstrap modal and I have 2 questions about it :
Should I use a simple or a partial view?
How can I perform the validation (actually it work but it redirects me to my original view so not in the modal form)
I think I have to use AJAX and/or jQuery but I'm new to these technologies. Any help would be appreciated.
EDIT : My Index View :
#model IEnumerable<BuSIMaterial.Models.Person>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<br />
<div class="group">
<input type="button" value="New person" class="btn" onclick="location.href='#Url.Action("Create")';return false;"/>
<input type="button" value="Download report" class="btn" onclick="location.href='#Url.Action("PersonReport")';return false;"/>
</div>
#using (Html.BeginForm("SelectedPersonDetails", "Person"))
{
<form class="form-search">
<input type="text" id="tbPerson" name="tbPerson" placeholder="Find an employee..." class="input-medium search-query">
<button type="submit" class="btn">Search</button>
</form>
}
<table class="table">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Start Date</th>
<th>End Date</th>
<th>Details</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
#foreach (BuSIMaterial.Models.Person item in ViewBag.PageOfPersons)
{
<tr>
<td>#item.FirstName</td>
<td>#item.LastName</td>
<td>#item.StartDate.ToShortDateString()</td>
<td>
#if (item.EndDate.HasValue)
{
#item.EndDate.Value.ToShortDateString()
}
</td>
<td>
<a class="details_link" data-target-id="#item.Id_Person">Details</a>
</td>
<td>
<div>
<button class="btn btn-primary edit-person" data-id="#item.Id_Person">Edit</button>
</div>
</td>
</tr>
<tr>
<td colspan="6">
<table>
<tr>
<th>National Number</th>
<td>#item.NumNat</td>
</tr>
<tr>
<th>Vehicle Category</th>
<td>#item.ProductPackageCategory.Name</td>
</tr>
<tr>
<th>Upgrade</th><td>#item.Upgrade</td>
</tr>
<tr>
<th>House to work</th>
<td>#item.HouseToWorkKilometers.ToString("G29")</td>
</tr>
</table>
<div id="details_#item.Id_Person"></div>
</td>
</tr>
}
</tbody>
</table>
<div class="modal hide fade in" id="edit-member">
<div id="edit-person-container"></div>
</div>
#section Scripts
{
#Scripts.Render("~/bundles/jqueryui")
#Styles.Render("~/Content/themes/base/css")
<script type="text/javascript" language="javascript">
$(document).ready(function () {
$('#tbPerson').autocomplete({
source: '#Url.Action("AutoComplete")'
});
$(".details_link").click(function () {
var id = $(this).data("target-id");
var url = '/ProductAllocation/ListByOwner/' + id;
$("#details_"+ id).load(url);
});
$('.edit-person').click(function () {
var url = "/Person/EditPerson";
var id = $(this).attr('data-id');
$.get(url + '/' + id, function (data) {
$('#edit-person-container').html(data);
$('.edit-person').modal('show');
});
});
});
</script>
}
My Partial View :
#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 = "list-of-people"
}))
{
#Html.ValidationSummary()
#Html.AntiForgeryToken()
<div class="modal-body">
<div class="editor-field">
#Html.TextBoxFor(model => model.FirstName, new { maxlength = 50 })
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.LastName, new { maxlength = 50 })
#Html.ValidationMessageFor(model => model.LastName)
</div>
</div>
<div class="modal-footer">
<button class="btn btn-inverse" type="submit">Save</button>
</div>
}
You should use partial views. I use the following approach:
Use a view model so you're not passing your domain models to your views:
public class EditPersonViewModel
{
public int Id { get; set; } // this is only used to retrieve record from Db
public string Name { get; set; }
public string Age { get; set; }
}
In your PersonController:
[HttpGet] // this action result returns the partial containing the modal
public ActionResult EditPerson(int id)
{
var viewModel = new EditPersonViewModel();
viewModel.Id = id;
return PartialView("_EditPersonPartial", viewModel);
}
[HttpPost] // this action takes the viewModel from the modal
public ActionResult EditPerson(EditPersonViewModel viewModel)
{
if (ModelState.IsValid)
{
var toUpdate = personRepo.Find(viewModel.Id);
toUpdate.Name = viewModel.Name;
toUpdate.Age = viewModel.Age;
personRepo.InsertOrUpdate(toUpdate);
personRepo.Save();
return View("Index");
}
}
Next create a partial view called _EditPersonPartial. This contains the modal header, body and footer. It also contains the Ajax form. It's strongly typed and takes in our view model.
#model Namespace.ViewModels.EditPersonViewModel
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Edit group member</h3>
</div>
<div>
#using (Ajax.BeginForm("EditPerson", "Person", FormMethod.Post,
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "list-of-people"
}))
{
#Html.ValidationSummary()
#Html.AntiForgeryToken()
<div class="modal-body">
#Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Name)
#Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Age)
</div>
<div class="modal-footer">
<button class="btn btn-inverse" type="submit">Save</button>
</div>
}
Now somewhere in your application, say another partial _peoplePartial.cshtml etc:
<div>
#foreach(var person in Model.People)
{
<button class="btn btn-primary edit-person" data-id="#person.PersonId">Edit</button>
}
</div>
// this is the modal definition
<div class="modal hide fade in" id="edit-person">
<div id="edit-person-container"></div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('.edit-person').click(function () {
var url = "/Person/EditPerson"; // the url to the controller
var id = $(this).attr('data-id'); // the id that's given to each button in the list
$.get(url + '/' + id, function (data) {
$('#edit-person-container').html(data);
$('#edit-person').modal('show');
});
});
});
</script>
I prefer to avoid using Ajax.BeginForm helper and do an Ajax call with JQuery. In my experience it is easier to maintain code written like this. So below are the details:
Models
public class ManagePeopleModel
{
public List<PersonModel> People { get; set; }
... any other properties
}
public class PersonModel
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
... any other properties
}
Parent View
This view contains the following things:
records of people to iterate through
an empty div that will be populated with a modal when a Person needs to be edited
some JavaScript handling all ajax calls
#model ManagePeopleModel
<h1>Manage People</h1>
#using(var table = Html.Bootstrap().Begin(new Table()))
{
foreach(var person in Model.People)
{
<tr>
<td>#person.Id</td>
<td>#Person.Name</td>
<td>#person.Age</td>
<td>#html.Bootstrap().Button().Text("Edit Person").Data(new { #id = person.Id }).Class("btn-trigger-modal")</td>
</tr>
}
}
#using (var m = Html.Bootstrap().Begin(new Modal().Id("modal-person")))
{
}
#section Scripts
{
<script type="text/javascript">
// Handle "Edit Person" button click.
// This will make an ajax call, get information for person,
// put it all in the modal and display it
$(document).on('click', '.btn-trigger-modal', function(){
var personId = $(this).data('id');
$.ajax({
url: '/[WhateverControllerName]/GetPersonInfo',
type: 'GET',
data: { id: personId },
success: function(data){
var m = $('#modal-person');
m.find('.modal-content').html(data);
m.modal('show');
}
});
});
// Handle submitting of new information for Person.
// This will attempt to save new info
// If save was successful, it will close the Modal and reload page to see updated info
// Otherwise it will only reload contents of the Modal
$(document).on('click', '#btn-person-submit', function() {
var self = $(this);
$.ajax({
url: '/[WhateverControllerName]/UpdatePersonInfo',
type: 'POST',
data: self.closest('form').serialize(),
success: function(data) {
if(data.success == true) {
$('#modal-person').modal('hide');
location.reload(false)
} else {
$('#modal-person').html(data);
}
}
});
});
</script>
}
Partial View
This view contains a modal that will be populated with information about person.
#model PersonModel
#{
// get modal helper
var modal = Html.Bootstrap().Misc().GetBuilderFor(new Modal());
}
#modal.Header("Edit Person")
#using (var f = Html.Bootstrap.Begin(new Form()))
{
using (modal.BeginBody())
{
#Html.HiddenFor(x => x.Id)
#f.ControlGroup().TextBoxFor(x => x.Name)
#f.ControlGroup().TextBoxFor(x => x.Age)
}
using (modal.BeginFooter())
{
// if needed, add here #Html.Bootstrap().ValidationSummary()
#:#Html.Bootstrap().Button().Text("Save").Id("btn-person-submit")
#Html.Bootstrap().Button().Text("Close").Data(new { dismiss = "modal" })
}
}
Controller Actions
public ActionResult GetPersonInfo(int id)
{
var model = db.GetPerson(id); // get your person however you need
return PartialView("[Partial View Name]", model)
}
public ActionResult UpdatePersonInfo(PersonModel model)
{
if(ModelState.IsValid)
{
db.UpdatePerson(model); // update person however you need
return Json(new { success = true });
}
// else
return PartialView("[Partial View Name]", model);
}
In reply to Dimitrys answer but using Ajax.BeginForm the following works at least with MVC >5 (4 not tested).
write a model as shown in the other answers,
In the "parent view" you will probably use a table to show the data.
Model should be an ienumerable. I assume, the model has an id-property. Howeverm below the template, a placeholder for the modal and corresponding javascript
<table>
#foreach (var item in Model)
{
<tr> <td id="editor-success-#item.Id">
#Html.Partial("dataRowView", item)
</td> </tr>
}
</table>
<div class="modal fade" id="editor-container" tabindex="-1"
role="dialog" aria-labelledby="editor-title">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content" id="editor-content-container"></div>
</div>
</div>
<script type="text/javascript">
$(function () {
$('.editor-container').click(function () {
var url = "/area/controller/MyEditAction";
var id = $(this).attr('data-id');
$.get(url + '/' + id, function (data) {
$('#editor-content-container').html(data);
$('#editor-container').modal('show');
});
});
});
function success(data,status,xhr) {
$('#editor-container').modal('hide');
$('#editor-content-container').html("");
}
function failure(xhr,status,error) {
$('#editor-content-container').html(xhr.responseText);
$('#editor-container').modal('show');
}
</script>
note the "editor-success-id" in data table rows.
The dataRowView is a partial containing the presentation of an model's item.
#model ModelView
#{
var item = Model;
}
<div class="row">
// some data
<button type="button" class="btn btn-danger editor-container" data-id="#item.Id">Edit</button>
</div>
Write the partial view that is called by clicking on row's button (via JS $('.editor-container').click(function () ... ).
#model Model
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="editor-title">Title</h4>
</div>
#using (Ajax.BeginForm("MyEditAction", "Controller", FormMethod.Post,
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "editor-success-" + #Model.Id,
OnSuccess = "success",
OnFailure = "failure",
}))
{
#Html.ValidationSummary()
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.Id)
<div class="modal-body">
<div class="form-horizontal">
// Models input fields
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
}
This is where magic happens: in AjaxOptions, UpdateTargetId will replace the data row after editing, onfailure and onsuccess will control the modal.
This is, the modal will only close when editing was successful and there have been no errors, otherwise the modal will be displayed after the ajax-posting to display error messages, e.g. the validation summary.
But how to get ajaxform to know if there is an error? This is the controller part, just change response.statuscode as below in step 5:
the corresponding controller action method for the partial edit modal
[HttpGet]
public async Task<ActionResult> EditPartData(Guid? id)
{
// Find the data row and return the edit form
Model input = await db.Models.FindAsync(id);
return PartialView("EditModel", input);
}
[HttpPost, ValidateAntiForgeryToken]
public async Task<ActionResult> MyEditAction([Bind(Include =
"Id,Fields,...")] ModelView input)
{
if (TryValidateModel(input))
{
// save changes, return new data row
// status code is something in 200-range
db.Entry(input).State = EntityState.Modified;
await db.SaveChangesAsync();
return PartialView("dataRowView", (ModelView)input);
}
// set the "error status code" that will redisplay the modal
Response.StatusCode = 400;
// and return the edit form, that will be displayed as a
// modal again - including the modelstate errors!
return PartialView("EditModel", (Model)input);
}
This way, if an error occurs while editing Model data in a modal window, the error will be displayed in the modal with validationsummary methods of MVC; but if changes were committed successfully, the modified data table will be displayed and the modal window disappears.
Note: you get ajaxoptions working, you need to tell your bundles configuration to bind jquery.unobtrusive-ajax.js (may be installed by NuGet):
bundles.Add(new ScriptBundle("~/bundles/jqueryajax").Include(
"~/Scripts/jquery.unobtrusive-ajax.js"));
In $('.editor-container').click(function (){}), shouldn't var url = "/area/controller/MyEditAction"; be var url = "/area/controller/EditPartData";?