I have an Ajax form nested within each row in a table to provide an add / remove feature. The partial lists all roles available (Microsoft identity 2.0), and for each, whether the specified user is associated with that role or not, as well as a button to toggle the user in and out of the role (Ajax).
Everything works fine when I use Ajax.Beginform, however when I use regular jquery, it works the first time I click the button to toggle the user's association with a role, but the second time it loads the partial view on a new page on its own without css styling.
Searching around on stackoverflow, I see others with similar issues, but they seem to not have ajax work at all, unlike me who has it working on the first request, then not subsequently. I should also mention, I am fairly new to Asp.net and this is the first time I am using jquery directly (following Scott Allan's tutorials on PluralSight).
Here's what I've tried already: Checked that the action is being hit by the ajax request with a debug breakpoint. Checked that I am referencing jquery in my layout view, and not more than once. Checked that I am referencing jquery and jquery unobtrusive ajax in the correct order. Checked that web.config has the relevant flags set to true.
I've been stuck on this for hours now, any guidance would be greatly appreciated.
BundleConfig.cs:
namespace GCCP
{
public class BundleConfig
{
// For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*",
"~/Scripts/jquery.unobtrusive*"));
bundles.Add(new ScriptBundle("~/bundles/gccp").Include(
"~/Scripts/gccp.js"));
// Use the development version of Modernizr to develop with and learn from. Then, when you're
// ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/Scripts/modernizr-*"));
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js"));
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"));
// Set EnableOptimizations to false for debugging. For more information,
// visit http://go.microsoft.com/fwlink/?LinkId=301862
BundleTable.EnableOptimizations = true;
}
}
}
Action methods:
public ActionResult UserRoles(string returnUrl, string UserName)
{
ViewBag.ReturnUrl = returnUrl;
UserRolesViewModel Model = new UserRolesViewModel();
Model.UserName = UserName;
Model.RoleAssignments = UserRoleAssignments(UserName);
return View(Model);
}
[HttpPost]
public ActionResult ToggleUserToRoleAssignment(string returnUrl, string UserName, string RoleName)
{
ViewBag.ReturnUrl = returnUrl;
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
string userID = userManager.FindByName(UserName).Id;
if ( roleManager.RoleExists(RoleName) == true )
{
if ( userManager.IsInRole(userID, RoleName) == true )
{
userManager.RemoveFromRole(userID, RoleName);
}
else
{
userManager.AddToRole(userID, RoleName);
}
}
ViewModel:
namespace GCCP.Models
{
public class UserRolesViewModel
{
[Required]
[Display(Name = "User")]
public string UserName { get; set; }
public Dictionary<string, bool> RoleAssignments { get; set; }
public string AjaxTest { get; set; }
}
}
View:
@using GCCP.Models;
@using System.Web.Mvc.Ajax;
@model UserRolesViewModel
@{
ViewBag.Title = "User Roles";
}
<h2>
@Model.UserName | Assigned Roles
</h2>
@Html.Partial("_UserRolesList", Model)
Partial View:
@using GCCP.Models;
@using System.Web.Mvc.Ajax;
@model UserRolesViewModel
<div id="roleAssignmentList">
<table class="table table-condensed">
<thead>
<tr>
<th>
Roles
</th>
<th>
Assigned
</th>
<th>
Add / Remove
</th>
</tr>
</thead>
<tbody>
@foreach ( var item in Model.RoleAssignments )
{
if ( item.Value )
{
<tr class="active">
<td>
@item.Key
</td>
<td>
<i class="glyphicon glyphicon-ok"></i>
</td>
<td>
<form action="@Url.Action("ToggleUserToRoleAssignment")" method="post" data-gccp-ajax="true" data-gccp-target="#roleAssignmentList">
<input type="hidden" name="RoleName" value="@item.Key"/>
<input type="hidden" name="UserName" value="@Model.UserName"/>
<input type="submit" value="Change"/>
</form>
</td>
</tr>
}
else
{
<tr>
<td>
@item.Key
</td>
<td>
<i class="glyphicon glyphicon-remove"></i>
</td>
<td>
<form action="@Url.Action("ToggleUserToRoleAssignment")" method="post" data-gccp-ajax="true" data-gccp-target="#roleAssignmentList">
<input type="hidden" name="RoleName" value="@item.Key"/>
<input type="hidden" name="UserName" value="@Model.UserName"/>
<input type="submit" value="Change"/>
</form>
</td>
</tr>
}
}
</tbody>
</table>
</div>
Jquery:
$(function () {
var ajaxFormSubmit = function () {
var $form = $(this);
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize()
};
$.ajax(options).done(function (data) {
var $target = $($form.attr("data-gccp-target"));
$target.replaceWith(data);
});
return false;
};
$("form[data-gccp-ajax='true']").submit(ajaxFormSubmit);
});
Thanks in advance :)