why ajax.actionlink not refresh the page? - ajax

First,sorry to my bad english.
I don't understand why my page not refresh when i click on the delete user...
After the click i check in database and the user is delete but my page with table not refresh, i dont't understand.
My views is:
#model IEnumerable<SiteWebEmpty.Models.User.UserDisplay>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcAjax.debug.js")" type="text/javascript"></script>
<h2>Display User</h2>
<div id="deleteUser">
#using (Html.BeginForm())
{
<table class="tabledisplayUser" border="1">
<tr>
<th>Name FirstName</th>
<th>UserName</th>
<th>Roles</th>
<th>Choice</th>
</tr>
<tr>
<th>#Html.Editor("name")</th>
<th>#Html.Editor("username")</th>
<th>#Html.Editor("roles")</th>
<th>#Html.Editor("choice")</th>
</tr>
#foreach (var user in Model)
{
<tr>
<td class="action nameFirstName">#Html.DisplayFor(u => user.NameFirstName)</td>
<td class="action userName">#Html.DisplayFor(u => user.UserName)</td>
#if (user.Roles.Roles.Count.Equals(0))
{
<td>Nobody Role</td>
}
else
{
<td>#Html.DropDownList("Roles", user.Roles.Roles)</td>
}
<td>#Html.ActionLink("Edit", "Edit", new { UserName = user.UserName }) | #Ajax.ActionLink("Delete", "Delete", new { UserName = user.UserName },
new AjaxOptions()
{
HttpMethod = "POST",
Confirm = "Do you want delete this user?",
UpdateTargetId = "deleteUser"
})</td>
</tr>
}
</table>
}
</div>
My controller is:
public ActionResult DisplayUser()
{
List<UserDisplay> users=getAllUserInDB();
GetAllNameFirstNameLDAP(users);
return View(users);
}
public ActionResult Delete(String userName)
{
DeleteDB(userName);
if (!Request.IsAjaxRequest())
return RedirectToAction("DisplayUser");
else
{
List<UserDisplay> users = getAllUserInDB();
GetAllNameFirstNameLDAP(users);
return PartialView("DisplayUser",users);
}
}
I don't understand why it not working, thank you for your help !

UpdateTargetId = "deleteUser" means to refresh a DOM element with id="deleteUser". You don't have such element.
You have:
<div class="deleteUser">
which is not the same as:
<div id="deleteUser">
So replace the class with id and your table should refresh normally.

Related

Ajax.ActionLink does not call controller action and its view

Here, the actionlink 'Get Students' in TeacherIndex view of TeacherController must call StudentController and action method StudentList and then go to the view StudentIndex.
TeacherIndex.cshtml in TeacherController:
#model IEnumerable<StudentMVC.Models.TeacherEntity>
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.TeacherId)
</th>
...
</tr>
#if (Model != null)
{
foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.TeacherId)
</td>
...
<td>
#Ajax.ActionLink("Get Students", "StudentList", "Student", new { id = item.TeacherId }, new AjaxOptions { HttpMethod = "POST" })
</td>
</tr>
}
}
StudentController:
[HttpPost]
public ActionResult StudentList(int TeacherId)
{
List<StudentEntity> studentList = new List<StudentEntity>();
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["Moviedb"].ConnectionString);
SqlCommand cmd = new SqlCommand("SP_Student", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#TeacherId", TeacherId);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
StudentEntity student = new StudentEntity();
student.StudentId = Convert.ToInt32(dr["StudentId"]);
//...
studentList.Add(student);
}
con.Close();
return View("StudentIndex", studentList);
}
But here, instead of that, shows
Server Error in '/' Application. The resource cannot be found.
Requested URL: /Student/StudentList/1
the name of parameter should be same. use this :
#Ajax.ActionLink("Get Students", "StudentList", "Student", new { #TeacherId = item.TeacherId }, new AjaxOptions { HttpMethod = "POST" })

MVC3 partial view does not return ajax post

The idea of the problem is that i have a "CreateINF" view then i display a pop up with that calls a partial view. In this pop up there is a grid, then when i select one of the elements of this grid i want to fill some textbox on the "CreateINF" view with the information of the element selected in the popup but this last action does not work and I dont know where is the error
this is the pop up "PopTrabajador"
#model PagedList.IPagedList<Sistema_GEC_v3.Models.TrabajadorExterno>
#{
ViewBag.Title = "Buscar Reserva";
}
<h1><strong>Resultado Búsqueda</strong></h1>
<br />
<table id="MainContent_Table2" rules="all" style="border-color: Black; width: 900px; margin-bottom: 0px;" border="1">
<tr>
<th style="font-weight: bold; width: 150px;" align="center">
</th>
<th style="font-weight: bold; width: 150px;" align="center">
#Html.LabelFor(modelItem => Model.First().vcNombre)
</th>
<th style="font-weight: bold; width: 150px;" align="center">
#Html.LabelFor(modelItem => Model.First().vcApellidoPaterno)
</th>
<th style="font-weight: bold; width: 150px;" align="center">
#Html.LabelFor(modelItem => Model.First().vcApellidoMaterno)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td align="center">
#using (Ajax.BeginForm("DevolverTrabajador", "Infracciones",
null
, new AjaxOptions
{
UpdateTargetId = "update-message",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnSuccess = "searchSuccess"
}, new { #id = "searchForm"+#item.idTrabajadorExterno}))
{
<div id="update-message" class="error invisible"></div>
<input data-val="true" data-val-number="The field idTrabajadorExterno must be a number." data-val-required="El campo idTrabajadorExterno es obligatorio." id="idTrabajadorExterno" name="idTrabajadorExterno" type="hidden" value="#item.idTrabajadorExterno" />
#Html.HiddenFor(model => item.idTrabajadorExterno, new { id = "idTrabajadorExterno" + #item.idTrabajadorExterno })
#Html.HiddenFor(model => item.vcNombre, new { id = "vcNombre" + #item.idTrabajadorExterno })
<input type="submit" value="Seleccionar" />
}
</td>
<td style="font-weight: normal; width: 150px;" align="center">
#Html.DisplayFor(modelItem => item.vcNombre)
</td>
<td style="font-weight: normal; width: 150px;" align="center">
#Html.DisplayFor(modelItem => item.vcApellidoPaterno)
</td>
<td style="font-weight: normal; width: 150px;" align="center">
#Html.DisplayFor(modelItem => item.vcApellidoMaterno)
</td>
</tr>
}
</table>
this is the view "CreateINF"
#model Sistema_GEC_v3.Models.Infraccion
#{
ViewBag.Title = "Create";
}
<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>
<link href="#Url.Content("~/Content/themes/base/jquery.ui.all.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")" type="text/javascript"></script>
<script type="text/javascript">
var linkObj;
//$(document).ready(function () {
$(function () {
$(".busqueda").button();
$('#dialog').dialog({
autoOpen: false,
width: 930,
resizable: false,
title: 'hi there',
modal: true
});
$(".busqueda").click(function () {
linkObj = $(this);
var dialogDiv = $('#dialog');
var viewUrl = linkObj.attr('href');
$.get(viewUrl, function (data) {
dialogDiv.html(data);
dialogDiv.dialog('open');
});
return false;
});
});
function searchSuccess() {
var id = $("#update-message").html();
var parent = linkObj.closest("tr");
document.getElementById('tipoTrabajador').value = $("#vcNombre" + id.toString()).val();
$('#dialog').dialog('close');
}
function actualizarVentanaModal(viewUrl) {
var dialogDiv = $('#dialog');
$.get(viewUrl, function (data) {
dialogDiv.html(data);
});
}
// });
</script>
<div id="commonMessage"></div>
<div id="dialog" title="Seleccionar Cliente"></div>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Infraccion</legend>
<div class="editor-label">
#Html.LabelFor(model => model.vcCodigoInfraccion)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.vcCodigoInfraccion, new { id = "tipoTrabajador" })
#Html.ValidationMessageFor(model => model.vcCodigoInfraccion)
</div>
<a class="busqueda" href= "#Href("~/Infracciones/PopTrabajador")"> <img src="#Href("~/Content/Images/buscar.png")" alt="0" title="Buscar" id="" border="0" height="16" width="16"/></a>
</fieldset>
<p>
<input value="Guardar" type="submit" name = "button"/>
</p>
}
And this is the controller
public ActionResult PopTrabajador(int? page, string tipoTrabajador)
{
int tamPag = 10;
int numPag = page ?? 1;
var trabajadoresE = dbTExterno.trabajadoresExternos.OrderBy(t => t.vcNombre);
return PartialView("PopTrabajador", trabajadoresE.ToPagedList(numPag, tamPag));
}
[HttpPost]
public ActionResult DevolverTrabajador(TrabajadorExterno trabajador)
{
try
{
return Content(trabajador.idTrabajadorExterno.ToString());
}
catch (Exception e)
{
return RedirectToAction("General", "Error");
}
}
public ActionResult CreateINF()
{
return View();
}
//
// POST: /Infracciones/Create
[HttpPost]
public ActionResult CreateINF(FormCollection collection)
{
try
{
// TODO: Add insert logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}

How to pass a list of objects instead of one object to a POST action method

I have the following GET and POST action methods:-
public ActionResult Create(int visitid)
{
VisitLabResult vlr = new VisitLabResult();
vlr.DateTaken = DateTime.Now;
ViewBag.LabTestID = new SelectList(repository.FindAllLabTest(), "LabTestID", "Description");
return View();
}
//
// POST: /VisitLabResult/Create
[HttpPost]
public ActionResult Create(VisitLabResult visitlabresult, int visitid)
{
try
{
if (ModelState.IsValid)
{
visitlabresult.VisitID = visitid;
repository.AddVisitLabResult(visitlabresult);
repository.Save();
return RedirectToAction("Edit", "Visit", new { id = visitid });
}
}
catch (DbUpdateException) {
ModelState.AddModelError(string.Empty, "The Same test Type might have been already created,, go back to the Visit page to see the avilalbe Lab Tests");
}
ViewBag.LabTestID = new SelectList(repository.FindAllLabTest(), "LabTestID", "Description", visitlabresult.LabTestID);
return View(visitlabresult);
}
Currently the view display the associated fields to create only one object,, but how i can define list of objects instead of one object to be able to quickly add for example 10 objects at the same “Create” request.
My Create view look like:-
#model Medical.Models.VisitLabResult
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#section scripts{
<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)
<fieldset>
<legend>VisitLabResult</legend>
<div class="editor-label">
#Html.LabelFor(model => model.LabTestID, "LabTest")
</div>
<div class="editor-field">
#Html.DropDownList("LabTestID", String.Empty)
Your viewModel
public class LabResult
{
public int ResultId { get; set; }
public string Name { get; set; }
//rest of the properties
}
Your controller
public class LabController : Controller
{
//
// GET: /Lab/ns
public ActionResult Index()
{
var lst = new List<LabResult>();
lst.Add(new LabResult() { Name = "Pravin", ResultId = 1 });
lst.Add(new LabResult() { Name = "Pradeep", ResultId = 2 });
return View(lst);
}
[HttpPost]
public ActionResult EditAll(ICollection<LabResult> results)
{
//savr results here
return RedirectToAction("Index");
}
}
Your view
#model IList<MvcApplication2.Models.LabResult>
#using (Html.BeginForm("EditAll", "Lab", FormMethod.Post))
{
<table>
<tr>
<th>
ResultId
</th>
<th>
Name
</th>
</tr>
#for (int item = 0; item < Model.Count(); item++)
{
<tr>
<td>
#Html.TextBoxFor(modelItem => Model[item].ResultId)
</td>
<td>
#Html.TextBoxFor(modelItem => Model[item].Name)
</td>
</tr>
}
</table>
<input type="submit" value="Edit All" />
}
Your view will be rendered as follows, this array based naming convention makes it possible for Defaultbinder to convert it into ICollection as a first parameter of action EditAll
<tr>
<td>
<input name="[0].ResultId" type="text" value="1" />
</td>
<td>
<input name="[0].Name" type="text" value="Pravin" />
</td>
</tr>
<tr>
<td>
<input name="[1].ResultId" type="text" value="2" />
</td>
<td>
<input name="[1].Name" type="text" value="Pradeep" />
</td>
</tr>
If I understand your question correctly,
you want to change your view to be a list of your model object #model List, then using a loop or however you wish to do it, create however many editors you need to for each object
then in your controller your receiving parameter of create will be a list of your model instead too.

MVC3. Ajax Confirmation comes twice

I have a list of Products. Each line has 'Delete' action. When I try to delete any row everything is true, but after second deleting ajax confirmation comes twice. Please help.
There are product list view.
#model IEnumerable<Domain.Entities.Product>
#{
ViewBag.Title = "Products";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<h1>Products</h1>
<table class="Grid">
<tr>
<th>Name</th>
<th>Description</th>
<th>Price</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>#item.Name</td>
<td>#item.Description</td>
<td>#item.Price</td>
<td>
#using (Ajax.BeginForm("DeleteProduct", "Admin",
new AjaxOptions {
Confirm="Product was deleted!",
UpdateTargetId="DeleteProduct"
}))
{
#Html.Hidden("Id", item.Id)
<input type="image" src="../Images/Icons/DeleteIcon.jpg" />
}
</td>
</tr>
}
</table>
There are AdminController
[Authorize]
public class AdminController : Controller
{
private IProductRepository productRepository;
public AdminController(IProductRepository productRepository)
{
this.productRepository= productRepository;
}
public ViewResult Products()
{
return View(productRepository.Products);
}
[HttpPost]
public ActionResult DeleteProduct(int id)
{
Product prod = productRepository.Products.FirstOrDefault(p => p.Id == id);
if (prod != null)
{
productRepository.DeleteProduct(prod);
TempData["message"] = string.Format("{0} was deleted", prod.Name);
}
return RedirectToAction("Products");
}
}
And finally _AdminLayout.cshtml
<html>
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Admin.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
</head>
<body>
<div id="DeleteProduct">
#if (TempData["message"] != null) {
<div class="Message">#TempData["message"]</div>
}
#RenderBody()
</div>
</body>
</html>
The problem here is that you are calling the DeleteProduct action with AJAX and this action is performing a Redirect to the Products action. Except that the Products action is returning a full HTML instead of a partial. So you get the jquery.unobtrusive-ajax.js injected twice into your DOM. So you get 2 confirmations on the second delete, 3 on the third and so on.
So start by defining a partial containing the table records (~/Views/Admin/_Products.cshtml):
#model IEnumerable<Domain.Entities.Product>
<div>#ViewData["message"]</div>
<table class="Grid">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Price</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#item.Name</td>
<td>#item.Description</td>
<td>#item.Price</td>
<td>
#using (Ajax.BeginForm("DeleteProduct", "Admin",
new AjaxOptions {
Confirm = "Are you sure you wanna delete this product?",
UpdateTargetId = "products"
})
)
{
#Html.Hidden("Id", item.Id)
<input type="image" src="#Url.Content("~/Images/Icons/DeleteIcon.jpg")" alt="Delete" />
}
</td>
</tr>
}
</tbody>
</table>
and then modify your main view so that it uses this partial:
#model IEnumerable<Product>
#{
ViewBag.Title = "Products";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<h1>Products</h1>
<div id="products">
#Html.Partial("_Products")
</div>
and finally modify your DeleteProduct controller action so that it no longer does any redirects but returns the partial instead after deleting the record:
[HttpPost]
public ActionResult DeleteProduct(int id)
{
Product prod = productRepository.Products.FirstOrDefault(p => p.Id == id);
if (prod != null)
{
productRepository.DeleteProduct(prod);
ViewData["message"] = string.Format("{0} was deleted", prod.Name);
}
return PartialView("_Products", productRepository.Products);
}
You have everything funneled through a single AJAX operation, so the click of delete is finding two items to delete on the second click. The way to handle this is work some magic on resetting the bound items so either a) the deleted item is set up to show it is already deleted once confirmed or b) rebinding the entire set of items after a delete to get rid of the item that has been deleted.
As long as you continue to have an item that the client believes has not been deleted, you will continue to "delete both" each time you click.

MVC3 Partial view method not firing

I have a Partial view (Login, with username, password and Submit button), and the partial view is being used on my _layout (materpage).
So, on my _layout page, I have:
<div style="text-align: right">
#Html.Partial("_LoginPartial")
</div>
My _LoginPartial has the following code:
#if (Request.IsAuthenticated)
{
<textarea>Welcome!
[ #Html.ActionLink("Log Off", "Logout", "Account")]</textarea>
}
else
{
#Html.Partial("~/Views/Account/Index.cshtml")
}
The Index file to display the login box looks like this:
#using GalleryPresentation.Models
#model LoginModel
<script src="../../Scripts/jquery.validate.min.js" type="text/javascript"></script>
#using (Html.BeginForm("index", "Account"))
{
<table>
<tr>
<td>#Html.LabelFor(m => m.Username)</td>
<td>#Html.TextBoxFor(m => m.Username)</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.Password)</td>
<td>#Html.PasswordFor(m => m.Password) kjkj</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Login"/></td>
</tr>
<tr>
<td colspan="2">#Html.ValidationSummary()</td>
</tr>
</table>
}
In my AccountCOntroller, I have the following code:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(LoginModel loginModel)
{
if(ModelState.IsValid)
{
var g = new GallaryImage();
var user = g.LoginUser(loginModel.Username, loginModel.Password);
if(user != null)
{
FormsAuthentication.SetAuthCookie(user.username, false);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "Invalid Username/Password");
}
return View(loginModel);
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
I have breakpoints on all methods - but they never get hit. Pressing the submit button simply changes my URL to:
http://localhost:8741/?Username=myusername&Password=mypassword
Can anyone spot the error I am making?
Since Html.BeginForm defaults to making GET requests, you are making a GET request with from your view. However, your action only accepts POST requests.
You can change #using (Html.BeginForm("index", "Account"))
to #using (Html.BeginForm("index", "Account", FormMethod.Post)).

Resources