I am calling an Action (Edit or Delete) on a Controller from an <a> tag generated in Javascript. I am trying to pass a parameter ('abc123') but the parameter is null when it gets to the controller.
I have tried various ways to create the <a> tag but I always end up with a null parameter showing up at the controller.
End result of generated <a> tags:
<a class="popup" href="./SiteAdmin/Edit?=abc123">Edit</a>
<a class="popup" href="./SiteAdmin/Delete/abc123">Delete</a>
HTML:
<div style="width: 90%; margin: 0, auto" class="tableContainer">
<a class="popup" href="./SiteAdmin/Save/0" style="margin-bottom:20px; margin-top: 20px;">Add New User</a>
<table id="tblUserAdmin" class="table admin-table">
<thead>
<tr>
<th>USERID</th>
<th>Name</th>
<th>role_id</th>
<th>Role</th>
<th>Modified By</th>
<th>Modified Date</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
</table>
</div>
Javascript:
var oTable = $('#tblUserAdmin').DataTable({
"ajax": {
"url": './SiteAdmin/getUsers',
"type": "GET",
"datatype": "json"
},
"columns": [
{ "data": "userid" },
{ "data": "name" },
{ "data": "role_id" },
{ "data": "role_nm" },
{ "data": "modifiedBy" },
{ "data": "modifiedDT" },
{
"data": "userid", "render": function (data) {
return '<a class="popup" href= "./SiteAdmin/Edit?=' + data + '">Edit</a>';
}
},
{
"data": "userid", "render": function (data) {
return '<a class="popup" href= "./SiteAdmin/Delete/' + data + '">Delete</a>';
}
}
Controller:
public class SiteAdminController : Controller
{
private Customer db = new Customer();
public ActionResult Index()
{
return View("~/Views/SiteAdmin/Index.cshtml");
}
[HttpGet]
public ActionResult Edit(string id)
{
// put a break point here to see id was null
var usr = new sec_users();
usr = db.sec_users.Where(a => a.userid == id).FirstOrDefault();
return View(usr);
}
}
Related
I have a simple view page, trying to render jquery datable for my view in MVC4.
My view [Admin.cshtml]
<div style="width:90%; margin:0 auto;">
<table id="myTable">
<thead>
<tr>
<th>Practice Name</th>
<th>Practice Address</th>
<th>Practice Email</th>
<th>Practice Telephone</th>
<th>Created Date</th>
</tr>
</thead>
</table>
</div>
and my reference to css and js for jquery datatables are underneath the section:
<link type="text/css" href="//cdn.datatables.net/1.10.9/css/jQuery.dataTables.min.css" rel="stylesheet"/>
#section Scripts{
<script type="text/javascript" src="//cdn.datatables.net/1.10.9/js/jQuery.dataTables.min.js"></script>
<script>
$(document).ready(function () {
$('#myTable').dataTable({
"ajax": {
"url": "/Home/Admin",
"type": "GET",
"datatype": "json"
},
"columns": [
{ "data": "Practice_Name", "autowidth": true },
{ "data": "Practice_Address", "autowidth": true },
{ "data": "Practice_Email", "autowidth": true },
{ "data": "Practice_Telephone", "autowidth": true },
{ "data": "Created_Date", "autowidth": true }
]
});
});
</script>
}
and in my Controller, i have a simple GET section:
public ActionResult Admin()
{
var data = db.Practices.ToList();
return Json(new { data = data }, JsonRequestBehavior.AllowGet);
}
But, when i run this application, i am getting my resultset like this
Where am i going wrong ?
Change your controller method name:
public ActionResult Admin() to public ActionResult GetAdminData()
Create another action method:
[Authorize]
public ActionResult Admin () => View();
Modify your JavaScript code:
"url": "/Home/Admin" to "url": "/Home/GetAdminData"
And update CDN links because they are too old:
https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css
https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js
Why is all of this needed?
When you navigate to /Home/Admin your return View (the Admin.cshtml)
Your view contains some custom JavaScript logic which will try to fetch a list of items from the database (your GetAdminData method)
GetAdminData returns JSON which can be used by DataTables in order to show your desired content on the page.
This is my /Books/userHome view:
#model CSBSTest.Models.tbl_Book
#{
ViewBag.Title = "UserHome";
Layout = "~/Views/Shared/_Profile.cshtml";
}
<h2>Books for sale by CUST Students</h2>
<br />
<br />
<table id="books" class="table table-bordered table-hover">
<thead>
<tr>
<th>Id</th>
<th>Book Name</th>
<th>Author</th>
<th>Version</th>
</tr>
</thead>
<tbody></tbody>
</table>
#section scripts
{
<script>
$(document).ready( function () {
var dataTable = $("#books").DataTable({
ajax: {
url: "/Book/GetBooks",
dataSrc: ""
},
columns: [
{
data:"Id"
},
{
data: "Name"
},
{
data: "Author"
},
{
data: "Version"
}
]
});
});
</script>
}
I am calling /Books/GetBooks as below:
public ActionResult UserHome()
{
return View();
}
public ActionResult GetBooks()
{
var list = _context.tbl_Book.ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
The GetBooks returns json result which is called from UserHome scripts section as shown above, I want to populate the list returned by /Books/GetBooks into jquery datatable but its gives the following exception:
.
any help will be highly appreciated thanks in advance.
var list = _context.tbl_Book.ToList();
Here "list" is database table object and you should not return it directly.
Use user defined model and than return it
public class customModel{
//properties
}
var list = _context.tbl_Book.ToList();
List<custommodel> test = list.select(a=>new custommodel{
//assingn properties
});
return Json(test , JsonRequestBehavior.AllowGet);
There is a good example on how to use JQuery Datatables with Core MVC at Using jQuery DataTables Grid With ASP.NET CORE MVC
I download the sample project, made some modifications and it works perfectly.
However, I'm getting an error when I try to integrate this into my project.
DataTables warning: table id=example - Requested unknown parameter 'IdStudent' for row 0, column 0. For more information about this error, please see http://datatables.net/tn/4
After I click ok on the error, the table generates with the correct number of rows, but with no data:
This is my class:
public class GridStudent
{
[Key]
public int IdStudent { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
The HTML and JavaScript:
<div class="container">
<br />
<div style="width:90%; margin:0 auto;">
<table id="example" class="table table-striped table-bordered dt-responsive nowrap" width="100%" cellspacing="0">
<thead>
<tr>
<th>IdStudent</th>
<th>Name</th>
<th>LastName</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
</table>
</div>
</div>
<script>
$(document).ready(function ()
{
$("#example").DataTable({
"processing": true, // for show progress bar
"serverSide": true, // for process server side
"filter": true, // this is for disable filter (search box)
"orderMulti": false, // for disable multiple column at once
"ajax": {
"url": "/StudentGrid/LoadData",
"type": "POST",
"datatype": "json"
},
"columnDefs":
[
{
"targets": [0],
"visible": false,
"searchable": false,
}
],
"columns": [
{ "data": "IdStudent", "name": "IdStudent", "autoWidth": true },
{ "data": "Name", "name": "Name", "autoWidth": true },
{ "data": "LastName", "name": "LastName", "autoWidth": true },
{
"render": function (data, type, full, meta)
{ return '<a class="btn btn-info" href="/StudentGrid/Edit/' + full.IdStudent + '">Edit</a>'; }
}
,
{
data: null, render: function (data, type, row)
{
return "<a href='#' class='btn btn-danger' onclick=DeleteData('" + row.IdStudent + "'); >Delete</a>";
}
},
]
});
});
function DeleteData(CustomerID)
{
if (confirm("Are you sure you want to delete ...?"))
{
Delete(CustomerID);
}
else
{
return false;
}
}
function Delete(CustomerID)
{
var url = '#Url.Content("~/")' + "StudentGrid/Delete";
$.post(url, { ID: CustomerID }, function (data)
{
if (data)
{
oTable = $('#example').DataTable();
oTable.draw();
}
else
{
alert("Something Went Wrong!");
}
});
}
</script>
This is the line of code, from the controller, than returns the data:
return await Task.Run(() => Json(new { draw = draw, recordsFiltered = recordsTotal, recordsTotal = recordsTotal, data = data }));
As you can see from the image, the controller is returning the data correctly, but for some reason DataTables can't read it.
I cross check with the sample a thousand times and I can't see a difference on the format of the data being return.
Any suggestions?
This is most likely due to the casing of the serialized JSON. Your data properties in the column definitions within your JavaScript expect Pascal casing. At present, I expect your are serializing JSON as lower camel case rather than Pascal case (e.g. idStudent instead of IdStudent).
To serialize JSON as Pascal case, make sure you have the following in the ConfigureServices method in your Startup class:
services
.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver
= new Newtonsoft.Json.Serialization.DefaultContractResolver();
});
I have a server-side dataTable where when I click each row, I want it to show its Edit and Delete action links for the user to click on it and be directed to those pages.
#*<td>
#Html.ActionLink("Edit", "Edit", new { id = item.DepartmentID }) |
#Html.ActionLink("Details", "Details", new { id = item.DepartmentID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.DepartmentID })
</td>*#
When I search on their website, they use the editor for datatables. But I am not able to implement the actionlinks with the editor for many undefined errors.
Can someone please assist me to figure out how to make the on click event work?
This is the script for the dataTable
init: function () {
dt = $('#datatableServer').DataTable({
"serverSide": true,
"processing": true,
"ajax": {
"url":
"#Url.Action("DataHandler","Department")"
},
"columns": [
{ "data": "Name",
"searchable": true },
{
"data": "Budget", "render": $.fn.dataTable.render.number(',', '.', 0, '$'),
"searchable": false },
{ "data": "StartDate",
"searchable": false,
"type" : "datetime"},
{ "data": "Administrator",
"searchable": true }
],
............
departmentsList.init();});
$('#datatableServer tbody').on('click', 'tr', function () {
//editor.edit(this, 'Edit record', {
//"label": "Update",
//"fn": function () {
//editor.submit()
//}
//})
console.log('clicked');
console.log(dt.row(this).data().DT_RowId); // DT_RowId is each row's Id
});
I have the DT_RowId getting the id for each table row for my data.
var data = query.Select(a => new DepartmentData
{
DT_RowId = a.DepartmentID.ToString(),
Name = a.Name,
..........
}).ToList();
First thing first
When I have them in my , my dataTable does not show.
The number in your column should match the number of you have. From what i can see, you specified 4 columns
"columns": [
{ "data": "Name", "searchable": true },
{ "data": "Budget", "render": $.fn.dataTable.render.number(',', '.', 0, '$'), "searchable": false },
{ "data": "StartDate", "searchable": false, "type" : "datetime"},
{ "data": "Administrator", "searchable": true }
]
but you also have an action column where your Actionlinks sit. So i suggest adding an addtional data column
{ data: "Action" }
Also make sure your have five header columns too
<thead>
<tr>
<th>Name</th>
<th>Budget</th>
<th>StartDate</th>
<th>Administrator</th>
<th>Action</th>
</tr>
</thead>
Now next thing, i haven't acutally tried to use their editor before, the way i do it is to use my own modal, any modal will do, bootstrap modal is an good option.
For example, you specify a modal in your dataTable view, I place it at the end of the page
<div id="companyModal" class="modal hide" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myCompanyModalLabel"></h3>
</div>
#{Html.RenderAction("CompanyModal", "CV");}
</div>
</div>
</div>
I like to use ViewModal in my modal, so i do RenderAction to get all the goodies from ViewModal validation. Of course, you can do #Html.Partial() too instead of RenderAction, RenderAction only if you want to get some value for the ViewModel before returning it.
[ChildActionOnly]
public ActionResult CompanyModal()
{
var model = new CompanyViewModel();
return PartialView("~/Views/Dashboard/CV/_CompanyModal.cshtml", model);
}
The partial view:
#model XXX.CompanyViewModel
<form id="companyForm" style="margin: 0px;">
#Html.AntiForgeryToken()
<div class="modal-body">
#Html.HiddenFor(m => m.CompanyId)
<div class="row-fluid">
<div class="span6">
#Html.LabelFor(m => m.CompanyName)
#Html.TextBoxFor(m => m.CompanyName, new { #class = "input-block-level" })
#Html.ValidationMessageFor(m => m.CompanyName)
</div>
<div class="span6">
#Html.LabelFor(m => m.JobTitle)
#Html.TextBoxFor(m => m.JobTitle, new { #class = "input-block-level" })
#Html.ValidationMessageFor(m => m.JobTitle)
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
<button id="companyEditSubmitBtn" name="edit" class="ladda-button btn btn-primary" data-style="zoom-in" data-spinner-size="25" type="button">Save</button>
</div>
</form>
Now on to the script:
//init dataTable
var cTable = $("#company-table").dataTable();
//open work experience edit modal
$("#company-table").on("click", ".companyEditBtn", function () {
//do
$("#myCompanyModalLabel").text("Edit Work Experience");
//get current position
position = cTable.fnGetPosition((this).closest("tr"));
data = cTable.fnGetData(position);
//set values to modal
$("#companyModal #CompanyId").val(data[0]);
$("#companyModal #CompanyName").val(data[1]);
$("#companyModal #JobTitle").val(data[2]);
//open modal
$("#companyModal").modal("show");
});
After you open the modal, post the value to your server to save using ajax:
//work experience edit
$("#companyEditSubmitBtn").click(function () {
//get the form
var form = $("#companyForm");
//validate form
if (!form.valid()) {
return;
}
//serialize the form
serializedForm = form.serialize();
//ajax post
$.ajax({
url: "#Url.Action("CompanyEdit", "CV")",
type: "POST",
data: serializedForm,
beforeSend: function () {
l.ladda("start");
},
success: function (result) {
if (result.success) {
//update row of table
cTable.fnUpdate([
result.id,
result.name,
result.title,
"<button class='companyEditBtn btn' title='Edit Work Experience'><i class='icon-pencil'></i></button>" + " " + "<button class='companyDeleteBtn btn' title='Delete Work Experience'><i class='icon-trash'></i></button>"
], position);
toastrSuccess(result.message);
} else {
toastrError(result.message);
}
},
error: function (jqXHR, textStatus, errorThrown) {
toastrError(textStatus);
},
complete: function () {
//stop ladda button loading
l.ladda("stop");
//hide modal
$(".modal").modal("hide");
}
});
});
And your edit controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CompanyEdit(CompanyViewModel model)
{
if (ModelState.IsValid)
{
var company = repository.FindCompany(model.CompanyId);
if (company != null)
{
try
{
//map automapper
model.Description = model.Description.Replace(Environment.NewLine, "<br />");
mapper.Map(model, company);
repository.EditCompany(company);
return Json(new { success = true, message = "Wokr Experience Edited", id = company.CompanyId, title = company.JobTitle, name = company.CompanyName });
}
catch (Exception ex)
{
return Json(new { success = false, message = string.Format("{0}", ex) });
}
}
else
{
return Json(new { success = false, message = "Work Experience not found" });
}
}
return Json(new { success = false, message = "Modal state is not valid" });
}
Another thing to mention, instead of using a foreach loop, use DisplayTemplate,
where the Companies property is an IEnumerable which will
automatically do the looping and render the CompanyViewModel.cshtml
display template for each item of this collection.
Source here
<table id="company-table" class="table table-striped table-bordered table-hover dataTables" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Company</th>
<th>Title</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#Html.DisplayFor(m => m.Companies)
</tbody>
<tfoot>
<tr>
<th>ID</th>
<th>Company</th>
<th>Title</th>
<th>Action</th>
</tr>
</tfoot>
</table>
And specify your display template inside Shared -> DisplayTemplates -> CompanyViewModel.cshtml
#model Taw.WebUI.Models.CompanyViewModel
<tr>
<td>
#Html.DisplayFor(m => m.CompanyId)
</td>
<td>
#Html.DisplayFor(m => m.CompanyName)
</td>
<td>
#Html.DisplayFor(m => m.JobTitle)
</td>
<td>
<button class="companyEditBtn btn" title="Edit Work Experience"><i class="icon-pencil"></i></button>
<button class='companyDeleteBtn btn' title="Delete Work Experience"><i class="icon-trash"></i></button>
</td>
</tr>
I am new at JSon and have been searching all over the internet but can't find out where is the error. Can you help me, please? The controller returns the object but nothing is displayed, and it comes out an error saying "Cannot read property 'length' of undefined"`.
This is my main template file:
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.min.css" rel="stylesheet" />
<script src="~/scripts/jquery-1.9.1.js"></script>
<script src="~/scripts/bootstrap.min.js"></script>
<!-- Data table -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.10/css/dataTables.bootstrap.min.css " />
<script src="https://cdn.datatables.net/1.10.10/js/jquery.dataTables.min.js" type="text/javascript"></script>
<script src="https://cdn.datatables.net/1.10.10/js/dataTables.bootstrap.min.js" type="text/javascript"></script>
This is my table:
<table class="table table-bordered" id="tabela">
<thead>
<tr>
<th>Nome</th>
<th>Quantidade</th>
<th>Preco</th>
<th></th>
</tr>
</thead>
</table>
This is my JSon:
$('#tabela').DataTable({
"columnDefs": [
{ "width": "5%", "targets": [0] }, {
"className": "text-center custom-middle-align",
"targets": [0, 1, 2, 3]
},
],
"language": {
"processing": "<div class='overlay custom-loader-background'><i class='fa fa-cog fa-spin custom-loader-color'></i></div>"
},
"processing": true,
"serverSide": true,
"ajax": {
"url": "/produto/BuscarTodos",
"type": "POST",
"dataType": "JSON"
},
"columns": [{
"data": "Nome"
}, {
"data": "Preco"
}, {
"data": "Quantidade"
}, {
"data": "IdProduto"
}, ]
});
This is my controller:
public JsonResult BuscarTodos()
{
try
{
string dados = "";
// Initialization.
string search = Request.Form.GetValues("search[value]")[0];
string draw = Request.Form.GetValues("draw")[0];
string order = Request.Form.GetValues("order[0][column]")[0];
string orderDir = Request.Form.GetValues("order[0][dir]")[0];
int startRec = Convert.ToInt32(Request.Form.GetValues("start")[0]);
int pageSize = Convert.ToInt32(Request.Form.GetValues("length")[0]);
ProdutoConexao con = new ProdutoConexao();
List<Produto> lista = new List<Produto>();
lista = con.FindAll();
// Total record count.
int totalRecords = lista.Count;
if (!string.IsNullOrEmpty(search) && !string.IsNullOrWhiteSpace(search))
{
// Apply search
lista = lista.Where(p => p.Nome.ToLower().Contains(search.ToLower())).ToList();
}
// Sorting.
lista = this.SortByColumnWithOrder(order, orderDir, lista);
// Filter record count.
int recFilter = lista.Count;
// Apply pagination.
lista = lista.Skip(startRec).Take(pageSize).ToList();
// Loading drop down lists.
var result = this.Json(new
{
draw = Convert.ToInt32(draw),
recordsTotal = totalRecords,
recordsFiltered = recFilter,
data = lista
}, JsonRequestBehavior.AllowGet);
return Json(result);
}
catch (Exception ex)
{
return Json(ex);
}
}
private List<Produto> SortByColumnWithOrder(string order, string orderDir, List<Produto> data)
{
// Initialization.
List<Produto> lista = new List<Produto>();
try
{
// Sorting
switch (order)
{
case "0":
// Setting.
lista = orderDir.Equals("DESC", StringComparison.CurrentCultureIgnoreCase) ? data.OrderByDescending(p => p.Nome).ToList() : data.OrderBy(p => p.Nome).ToList();
break;
}
catch (Exception ex)
{
// info.
Console.Write(ex);
}
// info.
return lista;
}
Just to check that your datatable setup is up and correct I will suggest to create an empty table (no controller) just to make sure that you have everything setup correctly. If that works I'll add your controller and dynamic data.
Datatables REQUIRE a specific HTML table format if it can't find it then you'll get that error.
The simplest table you can check with is the following:
<table>
<thead>
<tr>
<th>header 1</th>
</tr>
</thead>
<tbody>
<tr>
<td>Content 1</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Footer 1</td>
</tr>
</tfoot>
The footer is optional, everything else is required.
EDIT 1:
Take a look at the similar example they posted