I have a table that I am using jQuery Datatables with.
Picture:
Scenario:
As you can see in the picture, there is a Delete link. When that link is clicked, a modal pop-up will show asking the user if they really want to delete that item. If yes, delete.. if no.. cancel out of the modal.
What I want:
When a user decides to delete an item and confirms it.. I would like to change the status of that item to "Deleted", via ajax. I am able to change the value, but that value does not show in the table. I have researched this for a couple of days now, but nothing seems to work.
My Code
<table id="Item-Table" class="table table-bordered">
<thead>
<tr>
<th class="text-center">
#Html.DisplayNameFor(model => model.AssetTag)
</th>
<th class="text-center">
#Html.DisplayNameFor(model => model.codeMakeModel.MakeModel)
</th>
<th class="text-center">
#Html.DisplayNameFor(model => model.codeStatu.Status)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr class="text-center">
<td>
#Html.ActionLink(item.AssetTag, "Edit", new { id = item.Id })
</td>
<td>
#Html.DisplayFor(modelItem => item.codeMakeModel.MakeModel)
</td>
<td class="changeStatus">
#Html.DisplayFor(modelItem => item.codeStatu.Status)
</td>
<td>
Delete
</td>
</tr>
}
</tbody>
</table>
#section scripts{
<script>
var settings = {};
settings.baseUri = '#Request.ApplicationPath';
var infoGetUrl = "";
if (settings.baseUri === "/projectonservername") {
infoGetUrl = settings.baseUri + "/api/itemsapi/";
} else {
infoGetUrl = settings.baseUri + "api/itemsapi/";
}
$(document).ready(function () {
var itemsTable = $("#Item-Table").DataTable({
"aoColumnDefs": [
{ "bSortable": false, "aTargets": [3] },
{ "bSearchable": false, "aTargets": [3] }
]
});
$("#Item-Table").on("click",
".js-item-delete",
function() {
var link = $(this);
bootbox.confirm({
title: "Delete Item?",
message: "Are you sure you want to delete this item?",
buttons: {
cancel: {
label: '<i class="fa fa-times"></i> Cancel'
},
confirm: {
label: '<i class="fa fa-check"></i> Confirm'
}
},
callback: function(result) {
if (result) {
toastr.options = {
timeOut: 5000
}
$.ajax({
url: infoGetUrl + link.data("item-id"),
method: "DELETE",
success: function (result) {
//itemsTable.cell(itemsTable.row(this), 2).data("Deleted");
//itemsTable.draw();
//itemsTable.reload();
console.log(itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data());
itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data("Deleted").draw();
console.log(itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data());
toastr.success("Item successfully deleted");
},
error: function(jqXHR, textStatus, errorThrown) {
var status = capitalizeFirstLetter(textStatus);
console.log(jqXHR);
toastr.error(status + " - " + errorThrown, "Sorry, something went wrong.");
}
});
}
}
});
});
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
})
</script>
}
What I am Receiving
In the above code, specifically these lines:
console.log(itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data());
itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data("Deleted").draw();
console.log(itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data());
I am logging the value of the cell before I update that cell value, then changing the cell value, then logging the new/updated cell value.
Here is what I am receiving in the console:
But the table is not updating, or rather.. redrawing itself to show deleted.. the only way for it show deleted is to refresh the page which defeats the purpose of ajax..
How do I get the table to update the cell value without a page refresh?
Any help is appreciated.
I was able to answer this myself with some help of DavidDomain in the comments.
He suggested that I could possibly be selecting an incorrect row. So that gave me the idea to get the row at the start of this by adding:
$("#Item-Table").on("click",
".js-item-delete",
function() {
var link = $(this);
var row = $(this).parents("tr"); // get row element
Then set the cell data using that variable like so:
itemsTable.cell(itemsTable.row(row), $('.changeStatus')).data("Deleted").draw();
This worked and successfully drew the table with the updated value.
Related
I have displayed data in view page using data table. I want to display data in descending order according to
public ActionResult Index()
{
return View(db.BusinessRegModel.OrderByDescending(v => v.BusinessId).ToList());
}
BusinessId is primary key.
But in view page, data is not sorted via primary key. I am using jquery data table to display data.
<table id="tblBusinessData" class="table" width="100%" cellspacing="0">
<thead>
<tr>
<th>Edit/Print</th>
<th>
#Html.DisplayNameFor(model => model.RegNum)
</th>
<th>
#Html.DisplayNameFor(model => model.RegDate)
</th>
<th>
#Html.DisplayNameFor(model => model.NameOfFirm)
</th>
//code blocks
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td width="20%">
#Html.ActionLink("Edit", "Edit", new { id = item.BusinessId }, new { #class = "btn btn-warning" })
#Html.ActionLink("Print", "Details", new { id = item.BusinessId }, new { #class = "btn btn-danger" })
</td>
//code blocks
But the data is not sorted in descending order via BusinessId key. How can I do this? I need to display data in descending order by BusinessId.
jquery code
<script type="text/javascript">
$('#tblBusinessData').DataTable();
</script>
Add the column Id to the HTML and hide it via configuration:
$('#tblBusinessData').DataTable({
"columnDefs": [{
"targets": [0],
"visible": false
}],
"order": [
[0, "desc"]
]
});
If you are able to set the desired order in your data before you send it to DataTables, you can simply set order: [] to disable the initial sort while still being able to click on the column headers.
$('#tblBusinessData').DataTable({
order: []
});
I am currently working in Asp.net MVC in Visual Studio 2017. I am new to working with Asp.net MVC and can not get the values i am needing.
I have a table of questions that are all displayed in a table on my view page. Each one of the questions have a Boolean value that shows as check boxes when they are being displayed. I am currently trying to write a script to get the checkbox value of true or false and where that checkbox is checked I am trying to get the Id of the question in the current row.
This is my view where I am displaying the questions.
#model IEnumerable<CapstoneApplication.Models.Question>
#{
ViewBag.Title = "Index";
}
<h2>Questions: Admin View</h2>
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script src="~/Scripts/SaveCheckBox.js"></script>
<p>
#Html.ActionLink("Create Question", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.IsPartOfGame)
</th>
<th>
#Html.DisplayNameFor(model => model.Category.CategoryName)
</th>
<th>
#Html.DisplayNameFor(model => model.QuestionDescription)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.CheckBoxFor(modelItem=>item.IsPartOfGame, new {onclick = "SaveCheckBox(this)" })
</td>
<td>
#Html.DisplayFor(modelItem => item.Category.CategoryName)
</td>
<td>
#Html.DisplayFor(modelItem => item.QuestionDescription)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new {id = item.Id}) |
#Html.ActionLink("Delete", "Delete", new {id = item.Id})
</td>
</tr>
}
</table>
This is the script I am currently using.
function SaveCheckBox(checkboxInput) {
$.ajax({
type: 'GET',
url: 'Index',
data: {idValue: checkboxInput.closest("tr").getAttribute("id"),
newValue: checkboxInput.checked },
dataType: 'json'
});
}
Finally this is the method the script calls to give the values to.
public ActionResult Index(bool? newValue, int? idValue)
{
//save to database here
var questions = db.Questions.Include(q => q.Category);
return View(questions.ToList());
}
The problem I am having is that newValue always returns the correct value of being either true or false but idValue is always null it never grabs the id of the question in the row of the checkbox that was checked.
I would place the id as the data attribute in your CheckboxFor
#Html.CheckBoxFor(
modelItem=>item.IsPartOfGame
, new {onclick = "SaveCheckBox(this)", data_itemid = item.Id}
})
Then I would use this for your javascript
function SaveCheckBox(checkboxInput) {
$.ajax({
type: 'GET',
url: 'Index',
data: {
idValue: checkboxInput.dataset.itemid
, newValue: checkboxInput.checked
},
dataType: 'json'
});
}
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>
For our site we have an Admin section and a user section. We want to allow Admins to specify which order items are listed to the users in the user section.
I have an MVC list table, and I've enabled sorting the rows to actually change the sort value. But I'm trying to save the sort to the database. As you can see below, I have hidden elements for certain properties, and my javascript sets the HiddenFor(item.SortOrder) correctly. It then calls the controller. But I would like the entire collection of rows to be passed back as a List<> object. Are there any good examples?
#model System.Collections.Generic.IList<PublicationSystem.Model.CustomField>
<table class="table sortable-table"
data-source-href='#Url.RouteUrl("Default",
new { action = "_CustomFieldSort" },
Request.Url.Scheme)'>
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model[0].ColumnName)
</th>
<th>
#Html.DisplayNameFor(model => model[0].ColumnCaption)
</th>
<th></th>
</tr>
</thead>
#for (var i=0; i < Model.Count; i++) //each (var item in Model)
{
<tr>
<td>
#Html.HiddenFor(modelItem => Model[i].CustomFieldId,new {name="fieldsToEdit["+i+"].CustomFieldId"})
#Html.HiddenFor(modelItem => Model[i].CustomFormId, new { name = "fieldsToEdit[" + i + "].CustomFormId" })
#Html.HiddenFor(modelItem => Model[i].SortOrder, new { name = "fieldsToEdit[" + i + "].SortOrder", #class = "SortOrder" })
#Html.DisplayFor(modelItem => Model[i].ColumnName)
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].ColumnCaption)
</td>
<td>
... buttons
</td>
</tr>
}
</table>
My javascript:
$(".sortable-table tbody").sortable({
stop: function (event, ui) {
$(".sortable-table tr").each(function (index, element) {
var hiddenInput = $(element).find(".SortOrder").first();
hiddenInput.val(index);
});
$.ajax({
url: $(".sortable-table").attr("data-source-href"),
method: "POST",
data: $(".sortable-table").serialize(),
success: function (result) {
ClearAndRefresh(); // Assumes parent has this function
}
});
}
});
My controller method:
public ActionResult _CustomFieldSort(List<CustomField> fieldsToEdit)
{
if (fieldsToEdit != null) // fieldsToEdit is always null after the sort
{
var fieldCount = fieldsToEdit.Count();
}
return null;// PartialView();
}
I have my javascript correctly trying an ajax call to my controller method, but 'fieldsToEdit' is null. What am I doing wrong?
Bulk update on sorting? using a for loop will enable you to map back the whole list back to a post/get method on the controller
#model System.Collections.Generic.IList<PublicationSystem.Model.CustomField>
<table class="table sortable-table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.ColumnName)
</th>
<th>
#Html.DisplayNameFor(model => model.ColumnCaption)
</th>
<th></th>
</tr>
</thead>
#for (int i=0; i < Model.Length;i++)
{
<tr>
<td>
#Html.HiddenFor(modelItem => Model[i].CustomFieldId,new {name="fieldsToEdit["+i+"].CustomFieldId")
#Html.HiddenFor(modelItem =>Model[i].CustomFormId,new {name="fieldsToEdit["+i+"].CustomFormId")
#Html.HiddenFor(modelItem => Model[i].SortOrder, new { #class = "SortOrder",name="fieldsToEdit["+i+"].SortOrder" })
#Html.DisplayFor(modelItem => Model[i].ColumnName,new {name="fieldsToEdit["+i+"].ColumnName")
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].ColumnCaption,new {name="fieldsToEdit["+i+"].ColumnCaption")
</td>
<td>
... buttons
</td>
</tr>
}
Then hitting back on button to post button will bulk update the whole list, im not sure if I am answering you question correctly or not though.
I'm trying to create a reference into the row cell.
This is my code:
<table class="table table-striped table-bordered table-hover little_margin_table" id="data-table" width="100%">
<thead>
<th>First Name</th>
<th>Email</th>
<th>Password</th>
</thead>
<tbody>
#foreach (var item in Model.Items)
{
<tr id="#item.Id">
<td>#item.FirstName</td>
<td>#item.Email</td>
<td>#item.Password</td>
</tr>
}
</tbody>
</table>
Javascript code:
$(document).ready(function () {
$('#data-table').dataTable({
bFilter: false,
aoColumnDefs: [
{
bSortable: false,
aTargets: [1, 2],
},
{
"targets": 0,
"render": function (data, type, full, meta) {
return '<a href = "#(Url.Action("IndexPage", "Company"))/' + ROWID '</a>';
}
},
]
})
Here I am assuming the row Id :
<tr id="#item.Id">
How can get it to into the function render:
"render": function (data, type, full, meta) {
return '<a href = "#(Url.Action("IndexPage", "Company"))/' + ROWID '</a>';
Help, please.
You could add a extra column to your table:
<td>#item.FirstName</td>
<td>#item.Email</td>
<td>#item.Password</td>
<td>#item.Id</td>
Which is set to hidden in the datatables init code:
'bVisible': false
When you use render you can now get the Id value from full:
"render": function (data, type, full, meta) {
return '<a href = "#(Url.Action("IndexPage", "Company"))/' + full[3] + '</a>';
You could use a delegated event handler to add the id to the link when it is clicked :
$("#data-table").on("click", "td:eq(0) a", function(e) {
this.href+=$(this).closest('tr').attr('id');
})
And forget about adding ROWID to the href in the render callback. The table is generated serverside and your Model.items is never passed to the client as data, so I cannot see any other workaround.