Datatable missing some rows when open in modal - javascript

In html I have a table defined inside a modal that opens when I click a button:
<button type="button" id="myBtn" class="btn btn-primary" onclick="createTable()">Open modal</button>
<div class="modal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">myTable</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<table class="table table-striped table-bordered table-fixed" style="width:100%" id="myTable">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody id="myTableBody"> </tbody>
</table>
</div>
</div>
</div>
</div>
I want to destroy and create the table each time I click the button, so I've defined this Javascript function to do that:
function createTable()
{
data = [{ID:'1', Name:'Name1', Date:'2022-04-27'}, {ID:'2', Name:'Name2', Date:'2022-04-27'}, {ID:'3', Name:'Name3', Date:'2022-04-27'}, {ID:'4', Name:'Name4', Date:'2022-04-27'} ]; // example of data
$("#myTable").find('tbody').empty(); // reset table
for (var i=0; i<data.length; i++) // fill rows
{
var row = `<tr>
<th scope="row"> ${data[i].ID}</th>
<td>${data[i].Name}</td>
<td>${data[i].Date}</td>
</tr>`
$("#myTable").find('tbody').append(row);
}
$("#myModal").modal("show"); // open modal
$('#myTable').DataTable({
scrollY: '400px',
scrollCollapse: true,
destroy: true
})
}
The problem is that, when I click the button, the modal opens but the table does not always contains all the data: sometimes the first rows (of data) are missing. If I refresh the page and then open the modal, all the rows are present.
data has size > 1000 and is taken from a DB, but in the code I only put an example of it. Here is the code https://jsfiddle.net/326w480u/
Any idea of the cause of this behavior?
EDIT1:
briefly, the problem is that Datatable is updated only when I refresh the page, not when I close and open the modal
EDIT2:
I solved populating the Datatable when I define it, and not by means of the for loop:
$('#myTable').DataTable({
scrollY: '400px',
data: data,
columns: [{data:'ID'},{data:'Name'},{data:'Date'}],
scrollCollapse: true,
destroy: true
})

Related

Modal doesn't come with input's values

I have to use modals in my project. But unfortunately it does not work well.
On the page, when I click on the Add New Role button, everything goes right. But then when I click on the role edit button, the modal is displayed with blank values. While the IDs are successfully sent to the action.
After that when you reload the page, and first click on the edit role button, the modal will not display at all. At the same time, if you click the Add New Role button again, the modal is successfully displayed and everything is OK. At the same time, if you click the role edit button again, the modal will be displayed again in blank. (Just as before the IDs were successfully sent to the action but not found). I think this problem is related to two things:
The problem is with the action (maybe the code I wrote didn't send
the values well)
The problem may be that the following JQuery codes is not
performing well:
Jquery (file name: application-role-index.js):
(function ($) {
function RoleList() {
var $this = this;
function initilizeModel() {
$("#modal-action-application-role").on('loaded.bs.modal', function (e) {
}).on('hidden.bs.modal', function (e) {
$(this).removeData('bs.modal');
});
}
$this.init = function () {
initilizeModel();
}
}
$(function () {
var self = new RoleList();
self.init();
})
}(jQuery))
Anyway i hope you can help me. Here is the code I will use for this section:
Action in 'RoleListController':
[HttpGet]
public async Task<IActionResult> AddEditRole(string Id)
{
RoleListViewModel model = new RoleListViewModel();
if (!string.IsNullOrEmpty(Id))
{
ApplicationRole applicationRole = await _roleManager.FindByIdAsync(Id);
if (applicationRole != null)
{
model.Id = applicationRole.Id;
model.Name = applicationRole.Name;
model.Explanation = applicationRole.Explanation;
}
return PartialView("_AddAndEditAppRole", model);
}
else
{
return PartialView("_AddAndEditAppRole");
}
}
The View page i'm using modal:
<div class="btn-group">
<a class="btn btn-primary" id="showaddrole" data-toggle="modal" asp-action="AddEditRole" data-target="#modal-action-application-role">افزودن نقش جدید</a>
</div>
<table dir="rtl" class="table table-bordered table-striped myTable table-condensed">
<thead>
<tr>
<th>ID</th>
<th>#Html.DisplayNameFor(Model => Model.Name)</th>
<th>#Html.DisplayNameFor(Model => Model.Explanation)</th>
<th>#Html.DisplayNameFor(Model => Model.NumberOfUsers)</th>
<th>عملیات</th>
</tr>
</thead>
<tbody>
#foreach (var role in Model)
{
<tr>
<td>#role.Id</td>
<td>#role.Name</td>
<td>#role.Explanation</td>
<td>#role.NumberOfUsers</td>
<td>
<a class="btn btn-info myTableIC" asp-route-id="#role.Id" asp-action="AddEditRole" data-target="#modal-action-application-role" data-toggle="modal">
<i class="glyphicon glyphicon-pencil"></i>
</a>
<a class="btn btn-danger myTableIC" asp-route-id="#role.Id" asp-action="DeleteRole">
<i class="glyphicon glyphicon glyphicon-remove"></i>
</a>
</td>
</tr>
}
</tbody>
</table>
#Html.Partial("_Modal", new BootstrapModel { ID = "modal-action-application-role", Size = ModalSize.Medium })
#section Scripts{
<script src="~/js/modal-js/application-role-index.js"></script>
}
I have prepared a short video of how my program works so you can move forward with a better understanding:
You can find that by this link...
i suggest a solution at first create a div block with a unique id
<div id="popup"></div>
than use ajax to call the action like this :
$("#btnAdd").click(function () {
$.ajax({
type: 'POST',
url: '#Url.Action("AddEditRole")',
success: function (result) {
$("#popup").html(result);
$("#popup-addRole").modal("show");
}
});
});
then create an partiel view of popup with the id of model is popup-addRole something like this
<div class="modal" id="popup-edt" role="dialog">
<div class="modal-dialog" role="document" style="width:50%;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
//add your form here
</div>
</div>
</div>
</div>
don't forget to add model you want to use
i hope that fix the problem

Send an event to another function

Problem
Is there a way to send 'event' to another function with jQuery?
I have this code to prevent remove of row of my table to execute certain treatments, then remove the row.
I want to add a modal window between. But I do not know how to proceed.
Actually, I do like this
$('#delete-row').on('click', '.tr-special .remove-line-exceptionnel', function (event) {
event.preventDefault();
var $row = $(event.target).closest('.tr-special');
console.log($row);
var elementSortable = $row.find('ul').attr('id');
items = $row.find('li');
$( items ).each(function( index ) {
//function out of purpose
});
$row.remove();
});
Output of console.log is
r.fn.init [tr.tr-special, prevObject: r.fn.init(1)]
I want to call my modal, after click on Delete button with class .remove-line, so in normal times I do like this
$('.remove-line').on('click', function (event) {
$('#custom-width-modal').modal('show');
});
And what I would like is : when I press the button Confirm in my modal, the code of $('#delete-row').on('click', '.tr-special .remove-line', function (event) {.. execute.
$('.modal-footer').on('click', '.validDelete', function(e) {
var $row = $(e.target).closest('.tr-special');
console.log($row);
});
Output of console.log is
r.fn.init [prevObject: r.fn.init(1)]
I hope you understand me
If you simply declare the $row variable globally...
In the .remove-line-exceptionnel click handler, store the element to possibly delete. Then in the .validDelete click handler, you remove the element.
So there is no send an event anywhere. There is two events... One to know which element to delete and one to actually do it.
// Declare a variable globally
var $row;
// Button (or whatever) in the row
$('#delete-row').on('click', '.tr-special .remove-line-exceptionnel', function (event) {
// Store the row element to delete
$row = $(event.target).closest('.tr-special');
// Show modal
$('#custom-width-modal').modal('show');
});
// Modal button
$('.modal-footer').on('click', '.validDelete', function(e) {
// Remove the row
$row.remove();
// Hide modal
$('#custom-width-modal').modal('hide');
});
table{
margin: 0 auto;
}
td{
padding: 1em;
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<table id="delete-row">
<tr class="tr-special">
<td>Row 1</td>
<td><button class="remove-line-exceptionnel">Remove</button></td>
</tr>
<tr class="tr-special">
<td>Row 2</td>
<td><button class="remove-line-exceptionnel">Remove</button></td>
</tr>
<tr class="tr-special">
<td>Row 3</td>
<td><button class="remove-line-exceptionnel">Remove</button></td>
</tr>
</table>
<div id="custom-width-modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Are you sure?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary validDelete">Yes, I'm sure.</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

MVC - Html.Action to retrieve element using Javascript, then pass it as parameter to Controller, then return a PartialView

View - My view has a modal that has an #Html.Action that calls the PartialViewResult in Controller. Notice the #Html.Action("RetrieveItemPrice", new { item_Id = 1 }) still has predefined item_Id.
Q#1: How do I create a function that will get an element's value and put it in the item_Id parameter before sending it to the Controller? Could this be inserted in the #Html.Action?
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<div id="pvPrice" class="" style="border: 0px solid green; ">
#Html.Action("RetrieveItemPrice", new { item_Id = 1 })
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<table id="dbTable">
<thead>
<tr>
<th class="hidden">
#Html.DisplayNameFor(model => model.itemId)
</th>
<th>
#Html.DisplayNameFor(model => model.itemName)
</th>
</tr>
</thead>
<tbody id="dbBody">
#foreach (var item in Model.Items)
{
<tr>
<td class="hidden">
#Html.DisplayFor(modelItem => item.itemid)
</td>
<td>
#Html.DisplayFor(modelItem => item.itemname)
</td>
</tr>
}
</tbody>
</table>
Controller
public PartialViewResult RetrieveItemPrice(string item_Id)
{
var prices = from ip in _odb.ITEM_PRICE_MSTR
join i in _odb.ITEM_MSTR on i.ITM_ID equals i.ITM_ID
select new ItemModel
{
itemid = i.ITM_ID,
itemname = i.ITM_DESC,
itemprice = ip.ITM_PRICE,
defaultflag = ip.DEFAULT_FL,
startdate = DbFunctions.TruncateTime(ip.START_DT),
enddate = DbFunctions.TruncateTime(ip.END_DT),
createddt = i.CREA_DT
};
prices = prices.Where(i => i.itemid.ToLower().Contains(item_Id.ToLower()));
prices = prices.OrderByDescending(i => i.itemprice);
var vm = new ItemViewModel();
vm.Items = prices.ToPagedList(pageNumber, pageSize);
return PartialView("_ViewItemPrice", vm);
}
Q#2: When I return a PartialView in Controller using PartialViewResult, who's going to receive and display it in the View? I ran the code, but nothing is being displayed. I think I still lack codes in View to receive the returned PartialView in Controller
Assuming you have many items with different item_Id and you want to show the modal dialog when this item is clicked. You should be listen to the click event on the element, make an ajax call and get the response (partial view result) and use that to build your modal dialog content.
Assuming your main view has code like this
<table>
#foreach (var item in Model.Items)
{
<tr>
<td>#item.itemname</td>
<td><a href="#Url.Action("RetrieveItemPrice",new { item_Id = itemId})"
class="modal-link" >#item.itemname</a>
</td>
</tr>
}
</table>
<!-- The below code is for the modal dialog -->
<div id="modal-container" class="modal fade" tabindex="-1" role="dialog">
X
<div class="modal-content">
<div class="modal-body"></div>
</div>
This will generate links with css class modal-link for each item in the table. The href value of the links will be like YourControllerName/RetrieveItemPrice?item_id=123(123 will be replaced with actual itemid) Now listen to the click event on these, make an ajax call to the href attribute value of these links and use the response for populating the modal dialog content.
$(function () {
$('body').on('click', '.modal-link', function (e) {
e.preventDefault();
$("#modal-container").remove();
$.get($(this).attr("href"), function (data) {
$('<div id="modal-container" class="modal fade">
<div class="modal-content" id="modalbody">'
+ data + '</div></div>').modal();
});
});
});
This code will replace the entire content of the modal with the partial view result coming from the RetrieveItemPrice action method. That means you need to include the necessary markup needed for the modal header and footer(with buttons) in the _ViewItemPrice partial view.
A#1: the code calling #Html.Action is executed on server-side, at that phase the html document has not been sent to client-side so you don't have to look for a way to retrieve element value. You can pass it directly to the call, instead, because the model used for rendering the view (including the element) should be accessible to the code in the modal.
If you place the modal markups right inside the view, you definitely can get #Model.ItemId, for example.
If you place the modal in a partial view, you can pass item id via ViewBag:
#Html.Partial("Modal", null, new ViewDataDictionary{{"ItemId", Model.ItemId}})
then use it in the modal markups:
#Html.Action("RetrieveItemPrice", new { item_Id = ViewBag.ItemId })
A#2: you should try if [ChildActionOnly] makes the action RetrieveItemPrice works.

Datatables in Bootstrap modal width

In my modal I am trying to put Datatables in there, the problem I'm having is that the width is incorrect, it should be the width of the modal but it is actually like this
My jQuery calling the Datatables
function getValidTags(){
var ruleID = $('.ruleID').val();
var table = $('.valid-tags').DataTable({
"ajax": {
"url": "/ajax/getValidTags.php",
"type": "POST",
"data": {
ruleID: ruleID
},
},
"columnDefs": [{
"targets": 2,
"render": function(data, type, full, meta){
return '<button class="btn btn-default btn-sm" type="button">Manage</button> <button class="btn btn-danger btn-sm">Delete</button>';
}
}]
});
}
My HTML
<!-- Modal where you will be able to add new rule -->
<div class="modal fade validation-list-modal" tabindex="-1" role="dialog" aria-labelledby="LargeModalLabel" aria-hidden="true" data-keyboard="false" data-backdrop="static">
<div class="modal-dialog modal-wide">
<div class="modal-content">
<div class="modal-header modal-header-custom">
<input class="ruleID" type="hidden"></input>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
<h4 class="modal-title modal-title-main">Create New Rule</h4>
</div>
<div class="modal-body">
<div class="topBar">
<div>
<input type="text" class="validTags inputTextStyling">
</div>
</div>
<table class="table table-striped table-condensed valid-tags">
<thead>
<tr>
<th>Tag Name</th>
<th>Autofixes</th>
<th>Manage</th>
</tr>
</thead>
<tbody class="validTagsTable">
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="saveValidTags">Save</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
I find this more appropriate solution,
First make your table width 100%
like this:
<table width="100%" id="datatable"></table>
then initialize your table
$('#datatable').DataTable();
and this this
$(document).on('shown.bs.modal', function (e) {
$.fn.dataTable.tables( {visible: true, api: true} ).columns.adjust();
});
For starters try adding following class to your table element
.dataTableLayout {
table-layout:fixed;
width:100%;
}
It would be good if you could make a fiddle of your code with dummy data for solving your problem.
I dont think the accepted answer is the correct answer. There should be no need at all for altering the CSS. It could cause unexpected issues elsewhere. The problem is, that the container (the modal) not is fully established at the time the dataTable is rendered. Look at columns.adjust() :
var table = $('#example').DataTable({
initComplete: function() {
this.api().columns.adjust()
}
...
})
or
$('.modal').on('shown.bs.modal', function() {
table.columns.adjust()
})
I just added table inside div, assigned width:100%; overflow-x:auto to that div and it worked.

Carry the id of a row to modal

I have a table that is being populated dynamically from the database, In it there is a button on whose click i wish to display a modal, as the work is done in bootstrap so its not difficult to create a modal.
<table id="report" class="table table-bordered" >
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
<?
$sql="SELECT * from `request` ";
$result= mysqli_query($con, $sql);
if(mysqli_num_rows($result)>0)
{
while($row = mysqli_fetch_assoc($result))
{
$requestid = $row['requestid'];
?>
<tr>
<td><? echo $requestid; ?> </td>
<td><div href="javascript:;" class="btn btn-drank mb-10" data-toggle="modal" data-target="#myModal2">Detail</div></td>
<td> </td>
<td> </td>
</tr>
<?}
}
</table>
Table will look similar to this
Now the part where i am stuck is that i also wish to carry the requestid of the row whose corresponding detail button user has clicked to the modal, so that if user clicks on detail of first row, modal displays the data of first row, and when the user clicks on detail of second row, modal displays the data of second row and so on..
Code for modal is
<div class="modal fade" id="myModal2" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<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="myModalLabel">Details</h4>
</div>
// wish to get the request id and once i have it i can use it to fetch data
</div>
</div>
</div>
UPDATE
Adding this update on top because I feel this would be more elegant and easiest way.
No need of having Step 1 and Step 2 i.e. a global variable and click event for modal invoker. You can just have shown.bs.modal method and get the sourceElement i.e. element that invoked modal, and fetch id corresponding to that row as below:
$("#myModal2").on('shown.bs.modal',function(e){
var sourceElement=e.relatedTarget;
/*e.relatedTarget gives you which element invoked modal*/
var id=$(sourceElement).closest('tr').find("td:first").text();
/*using sourceElement you can easily fetch id
alert(id);
})
Updated DEMO
DEMO
3 steps:
Have a global variable to store id
Click event to all div whose data-target="#myModal" to fetch clicked row's id
Make use of modal's shown.bs.modal to get id obtained during click event
Step 1
var id=0; /*a global variable*/
Step 2
$("div[data-target=#myModal2]").on('click',function(){
id=$(this).closest('tr').find("td:first").text();
/*get the closest tr of clicked div and find first td which has id value and store it in
id variable*/
})
Step 3
$("#myModal2").on('shown.bs.modal',function(e){
alert(id);
/*since id is a global variable and it will get value as soon as click occurs
Fetch the data with above id*/
})
Add data-id="id of the row" in button
<button data-id="id of the row" class="btn btn-drank mb-10" data-toggle="modal" data-target="#myModal2">Detail</button >
Put a form tag and input type hidden in that form.
<div id="myModal2" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"></h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<form >
<input type="hidden" id="id">
<button type="submit" class="btn btn-danger">Delete</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</form>
</div>
</div>
</div>
</div>
Then in script do it with event show.bs.modal
$(document).ready(function () {
$('#myModal12').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);//Button which is clicked
var clickedButtonId= button.data('Id');//Get id of the button
// set id to the hidden input field in the form.
$("input #id").val(clickedButtonId);
});
You can add a listener for show.bs.modal so you have a reference to the componet clicked by the user and to the modal, as stated in the documentation.
$('#myModal2').on('show.bs.modal', function (e) {
var modal = $(this);
var rowBtn = $(e.relatedTarget);
var row = rowBtn.closest('tr');
// Here you id for the clicked row
var rowId = row.find('td:first').text();
row.find('td').each(function(){
// Here you can iterate between each row cell
var cellCont = $(this).text();
// e.g. use cellCont to create modal content
});
// Here you can update modal content
// e.g. modal.find('.modal-body').html( your dynamic content );
});

Categories

Resources