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.
Related
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!
Screen is not redirected to Index view and data is not refreshed after save button click on create view. But data is saved successfully. How can I redirect and refresh index view after data is saved.
TestController
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using CRUDMVCAngularJS.Models;
namespace CRUDMVCAngularJS.Controllers
{
public class TestController : Controller
{
private SchoolEntities db = new SchoolEntities();
// GET: Test
public ActionResult Index()
{
return View();
}
// GET: All Students
public JsonResult GetAllStudent()
{
var studentList = db.Students.ToList();
return Json(studentList, JsonRequestBehavior.AllowGet);
}
//GET: Student by Id
public JsonResult GetStudentById(string id)
{
var studentId = Convert.ToInt32(id);
var getStudentById = db.Students.Find(studentId);
return Json(getStudentById, JsonRequestBehavior.AllowGet);
}
// Add Student
public string AddStudent(Student student)
{
if (student != null)
{
using (SchoolEntities contextObj = new SchoolEntities())
{
contextObj.Students.Add(student);
contextObj.SaveChanges();
return "Student record added successfully";
}
}
else
{
return "Invalid student record";
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Index View
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div ng-controller="mvcCRUDCtrl">
<p>
<input type="button" class="btn btn-default" value="Add" ng-click="AddStudentDiv()" />
</p>
<div class="divList">
<p><b><i>Employee List</i></b></p>
<table class="table table-hover">
<tr>
<td><b>ID</b></td>
<td><b>FirstName</b></td>
<td><b>LastName</b></td>
<td><b>Age</b></td>
</tr>
<tr ng-repeat="student in students">
<td>
{{student.Id}}
</td>
<td>
{{student.FirstName}}
</td>
<td>
{{student.LastName}}
</td>
<td>
{{student.Age}}
</td>
<td>
<span ng-click="editBook(book)" class="btn btn-primary">Edit</span>
<span ng-click="deleteBook(book)" class="btn btn-danger">Delete</span>
</td>
</tr>
</table>
</div>
</div>
Create View
<div ng-controller="mvcCRUDCtrl">
<p class="divHead"></p>
<table class="table">
<tr>
<td><b>FirstName</b></td>
<td>
<input type="text" ng-model="FirstName" />
</td>
</tr>
<tr>
<td><b>LastName</b></td>
<td>
<input type="text" ng-model="LastName" />
</td>
</tr>
<tr>
<td><b>Age</b></td>
<td>
<input type="text" ng-model="Age" />
</td>
</tr>
<tr>
<td></td>
<td>
<input type="button" class="btn btn-default" value="Save" ng-click="AddUpdateStudent()" />
<input type="button" class="btn btn-danger" value="Cancel" ng-click="Cancel()" />
</td>
</tr>
</table>
</div>
Layout.cshtml
<!DOCTYPE html>
<html ng-app="mvcCRUDApp">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - My ASP.NET Application</title>
#Scripts.Render("~/Scripts/angular.min.js")
#Scripts.Render("~/Scripts/StudentScripts/Module.js")
#Scripts.Render("~/Scripts/StudentScripts/Controller.js")
#Scripts.Render("~/Scripts/StudentScripts/Service.js")
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
#Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { #class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
<li>#Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
#Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
#RenderBody()
<hr />
<footer>
<p>© #DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
</body>
</html>
AngularJS Module
var app = angular.module("mvcCRUDApp", []);
AngularJS Service
app.service("crudAJService", function ($http) {
//get All Students
this.getStudents = function () {
return $http.get("../Test/GetAllStudent");
};
// get Student by studentId
this.getStudent = function (studentId) {
debugger;
var response = $http({
method: "post",
url: "../Test/GetStudentById",
params: {
id: JSON.stringify(studentId)
}
});
return response;
}
// Add Student
this.AddStudent = function (student) {
debugger;
var response = $http({
method: "post",
url: "../Test/AddStudent",
data: JSON.stringify(student),
dataType: "json"
});
return response;
}
});
AngularJS Controller
app.controller("mvcCRUDCtrl", function ($scope, crudAJService) {
GetAllStudents();
//To Get all student records
function GetAllStudents() {
var getStudentData = crudAJService.getStudents();
getStudentData.then(function (student) {
$scope.students = student.data;
}, function () {
alert('Error in getting student records');
});
}
$scope.AddUpdateStudent = function () {
$scope.Action = "Add";
debugger;
var Student = {
FirstName: $scope.FirstName,
LastName: $scope.LastName,
Age: $scope.Age
};
var getAction = $scope.Action;
if (getAction == "Update") {
Student.Id = $scope.Id;
var getData = crudAJService.updateStudent(Student);
getData.then(function (msg) {
GetAllStudents();
alert(msg.data);
}, function () {
alert('Error in updating record');
});
} else {
var getData = crudAJService.AddStudent(Student);
getData.then(function (msg) {
GetAllStudents();
alert(msg.data);
}, function () {
alert('Error in adding record');
});
}
}
$scope.AddStudentDiv = function () {
ClearFields();
window.location = "../Test/Create";
}
function ClearFields() {
$scope.Id = "";
$scope.FirstName = "";
$scope.LastName = "";
$scope.Age = "";
}
$scope.Cancel = function () {
window.location = "../Test/Index";
};
});
Are you talking about view not binding two-way when new students are added, did you call the get all students and reassign to scope after successfully adding students so that it will render the change on UI
To redirect after adding a student record, put window.location = "/Test/Index"; on AddUpdateStudent if success :
$scope.AddUpdateStudent = function () {
$scope.Action = "Add";
debugger;
var Student = {
FirstName: $scope.FirstName,
LastName: $scope.LastName,
Age: $scope.Age
};
var getAction = $scope.Action;
if (getAction == "Update") {
Student.Id = $scope.Id;
var getData = crudAJService.updateStudent(Student);
getData.then(function (msg) {
alert(msg.data);
window.location = "/Test/Index"; // redirect
}, function () {
alert('Error in updating record');
});
} else {
var getData = crudAJService.AddStudent(Student);
getData.then(function (msg) {
alert(msg.data);
}, function () {
alert('Error in adding record');
});
}
}
To display refreshed student data I think you need to get student data at first hand and bind it through ng-repeat
In Index view I would use ng-init to initialize getting data :
<div ng-controller="mvcCRUDCtrl" ng-init = "GetAllStudents()">
And in controller :
app.controller("mvcCRUDCtrl", function ($scope, crudAJService) {
$scope.GetAllStudents = function() {
var getStudentData = crudAJService.getStudents();
getStudentData.then(function (student) {
$scope.students = student.data;
}, function () {
alert('Error in getting student records');
});
}
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";?
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 ;)