Laravel Datatables - Searchable hidden column still requires a table header column? - datatables

I have a Laravel index page with yajra datatables of a model of a customer, with tags (one-to-many) flattened into a single column. This all works as expected. Here is my javascript from my index.blade.php
#push('child-scripts')
<script type="text/javascript">
$(function () {
var table = $('.data-table').DataTable({
lengthMenu: [ 10, 25, 50, 75, 100 ],
pageLength: 50,
processing: true,
serverSide: true,
ajax: "{{ route('customer.index') }}",
columns: [
{data: 'title', name: 'title'},
{data: 'field', name: 'field'},
{data: 'people_count', name: 'people_count', searchable: false},
{data: 'contact_count', name: 'contact_count', searchable: false},
{data: 'phone_count', name: 'phone_count', searchable: false},
{data: 'sample', name: 'sample'},
{data: 'tags', name: 'tags'},
{data: 'action', name: 'action', orderable: false, searchable: false},
]});
});
</script>
here is the relevent part of my html from the same file
<table class="table data-table table-auto strange">
<thead class="border-b">
<tr>
<th>Name</th>
<th>Field</th>
<th>
<x-fluentui-people-16-o /></th>
<th>
<x-fluentui-contact-card-16-o /></th>
<th>
<x-fluentui-call-16-o /></th>
<th>Sample</th>
<th></th>
<th></th>
</tr>
</thead>
</table>
The tags are verbose and taking too much screen real estate.
I followed the directions here to make them searchable but not visible.
laravel yajratable - hide column but make it searchable
{data: 'tags', name: 'tags', visible: false},
Adding visible: false did the trick, I can search for tags and get results.
Question
All of this breaks, the moment I remove ` <th></th> ` from the html. I must have 8 `<th>` elements even though I only have 7 visible columns. What is going on?

OK, this is a little embarrassing. I went back to add titles to my header columns to make them a little more clear.
<th>Sample</th>
<th>Tags</th>
<th>Action</th>
</tr>
</thead>
</table>
Only to discover that the Tag header cell for the corresponding column was gone; datatables had hidden it too. I left it off it off because I presumed that it would just get in the way. I have wasted so much time on this already, but I hope this will be a help to someone else.
TL;DR
Datatables proactively removes the header cell for the corresponding column; you must add it so datatables can hide it.

Related

Update Export-Data on DataTable [duplicate]

I've been struggling with this code. I need to avoid specific columns from being exported. I have done that but I don't know how to export the text inside any input element.
Here is the code:
$("#campaignMaterialsTable table").DataTable({
dom: 'Bfrtip',
buttons: [
{
extend: 'excel',
className: 'export-button',
text: 'Export as Excel',
columns: ':not(.notexport)',
//exportOptions: {
// format: {
// body: function (data, row, column, node) {
// //
// //check if type is input using jquery
// return $(data).is("input") ?
// $(data).val() :
// data;
// },
// columns: ':not(.notexport)'
// }
//},
title: 'Campaign Materials'
}]
});
I don't know here to put the code at the right place.. while initializing..
I referred to this links, but still not getting what I want:
https://datatables.net/forums/discussion/50724/export-values-typed-in-input-box-excelhtml5
https://datatables.net/forums/discussion/42205/export-data-with-text-box-in-td-of-data-table#latest
https://datatables.net/extensions/buttons/examples/html5/outputFormat-function.html
https://datatables.net/forums/discussion/50724/export-values-typed-in-input-box-excelhtml5
I assume you have a DataTable containing one or more input fields, something like this:
The user can type values into the input fields.
You want to export data to Excel, so that the result looks like this:
Here we can see the user-provided data as well as the standard table data.
To achieve this, I used the following table data:
<table id="example" class="display nowrap dataTable cell-border" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Adélaïde Nixon</td>
<td>System Architect</td>
<td><input type="text" id="office" name="office"></td>
<td>432434</td>
<td>2011/04/25</td>
<td>$320,800</td>
</tr>
<tr>
<td>John Smith</td>
<td>Maager</td>
<td><input type="text" id="office" name="office"></td>
<td>6123</td>
<td>2011/04/25</td>
<td>$320,800</td>
</tr>
<tr>
<td>John Smith 2</td>
<td>Director</td>
<td><input type="text" id="office" name="office"></td>
<td>6123</td>
<td>2011/04/25</td>
<td>$320,800</td>
</tr>
</tbody>
</table>
And I used the following DataTable initialization code:
<script type="text/javascript">
$(document).ready(function() {
$('#example').DataTable({
dom: 'Bfrtip',
buttons: [
{
extend: 'excel',
exportOptions: {
format: {
body: function ( inner, rowidx, colidx, node ) {
if ($(node).children("input").length > 0) {
return $(node).children("input").first().val();
} else {
return inner;
}
}
}
}
}
]
});
});
</script>
The body function assumes that, for input fields, there is only an input field in the cell (i.e. the input field is not contained in a form or any other element).
It uses the node parameter to check for input data, to avoid data formatting issues that could occur (e.g. with dates). I recommend doing that rather than using $(data).is("input").
If there is no input field found in the cell, then the cell contents (inner) are returned.
If the structure of your table does not match these assumptions, then you may need to adjust the above code, of course.
Edit
Regarding the follow-up question about choosing which columns to export, there are various ways.
You can hard-code the column indexes you want to export (where index 0 means the first column). For example:
exportOptions: {
columns: [ 0, 1, 2, 3, 5 ],
format: {
body: function ( inner, rowidx, colidx, node ) {
if ($(node).children("input").length > 0) {
return $(node).children("input").first().val();
} else {
return inner;
}
}
}
}
This exports all columns apart from the Start Date column (index 4).
Or you can use the approach in your question, based on a class, I believe. I have not actually tried that one.
Take note of where the columns: [ 0, 1, 2, 3, 5 ] directive is placed - it is inside the exportOptions section.
you can use
exportOptions:{
columns: ':visible'
}
in below buttons
buttons: [
{
extend: 'pdf',
footer: true,
exportOptions: {
columns: ':visible'
}
},
it will export only visible columns

Jest: Quasar table is not rendering rows

I'm using Jest for testing a quasar table in VueJs 3. The table I have is like this:
<template>
<q-table id="myTable"
:rows="rows"
:columns="columns"
virtual-scroll
:rows-per-page-options="[0]"
hide-bottom
/>
</template>
<script lang="ts">
import {defineComponent, PropType} from 'vue'
export default defineComponent({
name: 'TableDemo',
props: {
rows: {
type: [] as PropType<[{ name: string, surname: string }]>,
default: []
},
},
setup() {
const columns = [
{
name: 'name',
required: true,
align: 'left',
label: 'name',
field: 'name',
sortable: true
},
{
name: 'surname',
label: 'surname',
align: 'left',
field: 'surname',
sortable: true
},
]
return {columns}
}
})
</script>
I'm trying to write a very simple test to understand how this works:
it('Should contain the word "John"', async () => {
)
const wrapper = mount(TableDemo, {
props: {rows: [{name: 'John', surname: 'Marston'}]},
}
)
expect(wrapper.find('#myTable').text()).toContain('John')
})
My problem is that it doesn't render the rows, but only the columns.
Here what Jest renders:
<div class="q-table__container q-table--horizontal-separator column no-wrap q-table__card q-table--no-wrap"
id="myTable"><!---->
<div class="q-table__middle q-virtual-scroll q-virtual-scroll--vertical scroll">
<table class="q-table">
<thead>
<tr>
<th class="text-left sortable">name<i aria-hidden="true"
class="notranslate material-icons q-icon q-table__sort-icon q-table__sort-icon--left"
role="presentation">arrow_upward</i></th>
<th class="text-left sortable">surname<i aria-hidden="true"
class="notranslate material-icons q-icon q-table__sort-icon q-table__sort-icon--left"
role="presentation">arrow_upward</i></th>
</tr>
</thead>
<tbody class="q-virtual-scroll__padding">
<tr>
<td colspan="2" style="height: 0px; --q-virtual-scroll-item-height: 48px;"/>
</tr>
</tbody>
<tbody class="q-virtual-scroll__content" id="qvs_1" tabindex="-1"/>
<tbody class="q-virtual-scroll__padding">
<tr>
<td colspan="2" style="height: 48px; --q-virtual-scroll-item-height: 48px;"/>
</tr>
</tbody>
</table>
</div><!----></div>
Where is my mistake? Why doesn't the table render the row?
UPDATE
I actually realized that it works without "virtual-scroll" option, so the problem is bound to that. Does anyone have experience with it?
It seems they have used some timer function inside virtual scroll implementation, this is my fix:
call jest.useFakeTimers(); method before describe block, then inside test call jest.runAllTimers(); and await wrapper.vm.$nextTick(); before assertion
it('renders correctly', async () => {
const wrapper: any = wrapperFactory();
jest.runAllTimers();
await wrapper.vm.$nextTick();
expect(wrapper.html()).toMatchSnapshot();
});

DataTables Editor - Adding Soft Delete to SmartAdmin Angular 5 App

I am using SmartAdmin 1.9.1, which is an Angular 5 framework. SA provides a DataTables plugin, that I want to extend with the DataTables' Editor, so that I can do soft deletes of rows. DataTables is v1.10.18, Editor is v1.8.1.
DataTables without Soft Delete is working fine in my app. I've even been able to extend it with row selection checkboxes. Looking at the Editor Soft Delete example, I grabbed the code for the Delete block, and added it to my a5 component.html, as shown here:
<sa-datatable
[options]="{
data: sysMsgs,
columns: [
{data: 'checked'},
{data: 'rowid'},
{data: 'senderID'},
{data: 'message'},
{data: 'dateCreated'}
],
buttons: [
'copy', 'csv', 'pdf', 'print',
{
extend: 'selected',
text: 'Delete',
action: function ( e, dt, node, config ) {
var rows = table.rows( {selected: true} ).indexes();
editor
.hide( editor.fields() )
.one( 'close', function () {
setTimeout( function () { // Wait for animation
editor.show( editor.fields() );
}, 500 );
} )
.edit( rows, {
title: 'Delete',
message: rows.length === 1 ?
'Are you sure you wish to delete this row?' :
'Are you sure you wish to delete these '+rows.length+' rows',
buttons: 'Delete'
} )
.val( 'users.removed_date', (new Date()).toISOString().split('T')[0] );
}
}
],
columnDefs: [
{
targets: 0,
orderable: false,
className: 'select-checkbox'
},
{
targets: [2],
visible: true
}
],
select: {
style: 'os',
selector: 'td:first-child'
},
order: [[ 1, 'asc']],
searching: true,
search: {
smart: false
}
}"
tableClass="table table-striped table-bordered table-hover"
>
<thead>
<tr>
<th data-hide="mobile-p">Select</th>
<th data-hide="mobile-p">ID</th>
<th data-hide="mobile-p">Sender</th>
<th data-hide="mobile-p">Message</th>
<th data-hide="mobile-p">Date Sent</th>
</tr>
</thead>
</sa-datatable>
The Soft Delete example is based on using jQuery, which I'd like to avoid, because I'd prefer to keep all my code Angular 5.
I cannot figure out how to modify the sa-datatable without resorting to jQuery. Do you have any ideas on how to get this working?
Thanks,
Bob
I decided not to use DataTables Editor, and instead was able to handle soft deletes by calling functions in the original DataTables code. Here is what I am now using:
<sa-datatable
[options]="{
data: collMsgs,
columns: [
{data: 'checked'},
{data: 'senderID'},
{data: 'message'},
{data: 'messageStatus'},
{data: 'dateCreated'},
{data: 'dateExpires'}
],
buttons: [
'copy', 'csv', 'pdf', 'print',
{
extend: 'selected',
text: 'Delete',
action: handleButtons()
},
{
extend: 'selected',
text: 'Archive',
action: handleButtons()
},
{
extend: 'selected',
text: 'Read',
action: handleButtons()
}
],
columnDefs: [
{
targets: 0,
orderable: false,
className: 'select-checkbox'
},
{
targets: [2],
visible: true
}
],
select: {
style: 'multiple',
selector: 'td:first-child'
},
order: [[ 1, 'asc']],
searching: true,
search: {
smart: false
}
}"
tableClass="table table-striped table-bordered table-hover"
>
<thead>
<tr>
<th data-hide="mobile-p">Select</th>
<th data-hide="mobile-p">Sender</th>
<th data-hide="mobile-p">Message</th>
<th data-hide="mobile-p">Status</th>
<th data-hide="mobile-p">Date Sent</th>
<th data-hide="mobile-p">Date Expires</th>
</tr>
</thead>
</sa-datatable>
Bob

click and change events are not working for Angular 6 Datatables Responsive extension

I use Angular 6 datatables for show data in the frontend. I used responsive extension to show more data as described in
https://l-lin.github.io/angular-datatables/#/extensions/responsive
<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="row-border hover">
<thead>
<tr>
<th>Category Name</th>
<th>Description</th>
<th>Is Enable</th>
<th>Sub Categories</th>
<th>update</th>
<th>delete</th>
<th>Extra Data</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of vehicleCategoryData; let i = index">
<td>{{data.categoryName}}</td>
<td>{{data.description}}</td>
<td>{{data.isEnable}}</td>
<td>{{data.subCategory.length}}</td>
<td><i class="fa fa-edit" (click)="update(i)"></i></td>
<td><i class="fa fa-trash-o" (click)="delete(i)"></i></td>
<td>{{data.extraData}}
</tbody>
</table>
also my dtOptions are defined as follows.
dtOptions: any = {
pagingType: 'full_numbers',
pageLength: 5,
columns: [{
title: 'Category Name',
data: 'categoryName'
}, {
title: 'Description',
data: 'description'
}, {
title: 'Is Enable',
data: 'isEnable'
},{
title: 'Sub Categories',
data: 'sub'
},
{
title: 'update',
data: 'up'
},
{
title: 'delete',
data: 'del'
},
{
title : 'Extra Data',
data : 'sc',
className : 'none'
}],
responsive: true
};
So everything works fine. but
(click)="update(i)"
(click)="delete(i)"
events are not working. How can i solve this problem. Any suggestions?
I solve this problem by using the listHiddenNodes function.
First i imported the Responsive variable in the component
import Responsive from 'datatables.net-responsive';
then i put this code on the dtOptions
this.dtOptions = {
responsive: {
details: {
renderer: Responsive.renderer.listHiddenNodes()
}
},
};
That's all!

get data of slected row in vue good table

guys, I m new to vue so don't know how to achieve following situation
how i can get data of current selected row
here is code
<div class="table-responsive-sm">
<vue-good-table
title="Page List"
:columns="columns1"
:rows="rows1"
:paginationOptions="{enabled: false}">
<template slot="table-row-after" slot-scope="props" >
<td class="fancy"><input type="checkbox" v-model="checkview[props.row.originalIndex]">
</td>
<td class="has-text-right"><input type="checkbox" v-model="checkedit[props.row.originalIndex]"></td>
<td class="has-text-right"><input type="checkbox" v-model="checkupate[props.row.originalIndex]"></td>
<td class="has-text-right"><input type="checkbox" v-model="checkdelete[props.row.originalIndex]"></td>
</template>
</vue-good-table>
columns1: [
{
label: 'Page Name',
field: 'pagename',
sortable: false,
},
{
label: 'View',
sortable: false,
},
{
label: 'edit',
sortable: false,
},
{
label: 'update',
sortable: false,
},
{
label: 'delete',
sortable: false,
},
],
rows1:[],
methods:{
getTotals1(){
var self = this;
this.$http.get('http://localhost:3000/api/permissionpgs')
.then(function (response) {
console.log(response.data)
self.rows1 = response.data;
})
},
}
is there any way to get data of value when save method got trigger. last ting this is vue good table
you're storing the values of checked items in 3 different objects. checkedit, checkupdate and checkdelete. If the user checks/unchecks your checkboxes in the table. These objects will have the following form:
checkupdate{
2: true, // index of the row: whether checked or unchecked
5: false,
20: true
}
now to get the rows for each of these objects all you have to do is loop through the object properties, collect the index that has value as true. then do this.rows1[index] to get the actual row object.