-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to copy a table column name? #227
Comments
Hey @Norlandz , that's a great question and actually I often wonder how to do that. Your question is actually for the https://datatables.net/ project - the underlying JavaScript library that we use to display the tables. Would you mind searching/asking for this on the datatables forum and keep us posted? Thanks |
@mwouts Btw, as for css workaround |
Hey @Norlandz , possibly the most convenient workaround is to give a name to your index (see below). Alternatively, the ordering component can be deactivated with Let me know if that answers your question.
|
@mwouts Good to know, but this workaround is adding extra info to the df & require more visual space. What I do instead is: inject a javascript jsscript = """
<script>
"use strict";
// hopefully, this will work without memory leak ...
console.log('inject js -- one click select table column name');
// function ready(fn) {
// if (document.readyState !== 'loading') { fn(); return; }
// document.addEventListener('DOMContentLoaded', fn);
// }
// ready(async function () {});
let mpp_eltTh_WithListener_prev = new Map();
// this requires constantly adding new listener to newly added elements (& discard old listeners)
document.addEventListener('click', function (ev) {
// await new Promise((r) => setTimeout(r, 2000));
const arr_elt = document.querySelectorAll('th');
const mpp_eltTh_WithListener_new = new Map();
for (const elt of arr_elt) {
// console.log(elt);
// if (!(elt instanceof HTMLTableCellElement)) throw new TypeError();
const listener_prev = mpp_eltTh_WithListener_prev.get(elt);
if (listener_prev === undefined) {
// new element detected -- add new listener
const listener_new = (ev) => {
// https://developer.mozilla.org/en-US/docs/Web/API/Selection/addRange
const selection = window.getSelection();
if (selection === null)
return;
if (selection.rangeCount > 0) {
selection.removeAllRanges(); // must dk .
}
const range = document.createRange();
range.selectNode(elt);
selection.addRange(range);
};
elt.addEventListener('click', listener_new);
mpp_eltTh_WithListener_new.set(elt, listener_new);
}
else {
// already have listener
mpp_eltTh_WithListener_prev.delete(elt); // delete (exclude) from old map, so that in a later operation it wont be unregistered
mpp_eltTh_WithListener_new.set(elt, listener_prev);
}
}
// clear up old Map, replace with new Map -- remember to delete (exclude) retained elemnt first before go to this step
for (const [elt_prev, listener_prev] of mpp_eltTh_WithListener_prev) {
elt_prev.removeEventListener('click', listener_prev);
// []
// According to the jquery Documentation when using remove() method over an element, all event listeners are removed from memory. This affects the element it selft and all child nodes. If you want to keep the event listners in memory you should use .detach() instead
// <>
// https://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory#:~:text=According%20to%20the%20jquery%20Documentation,detach()%20instead.
// em // whatever
}
mpp_eltTh_WithListener_prev = mpp_eltTh_WithListener_new;
});
</script>
"""
display(HTML(jsscript)) original ts code// hopefully, this will work without memory leak ...
console.log('inject js -- one click select table column name');
// function ready(fn) {
// if (document.readyState !== 'loading') { fn(); return; }
// document.addEventListener('DOMContentLoaded', fn);
// }
// ready(async function () {});
let mpp_eltTh_WithListener_prev = new Map<HTMLTableCellElement, (ev: MouseEvent) => void>();
// this requires constantly adding new listener to newly added elements (& discard old listeners)
document.addEventListener('click', function (ev) {
// await new Promise((r) => setTimeout(r, 2000));
const arr_elt = document.querySelectorAll('th');
const mpp_eltTh_WithListener_new = new Map<HTMLTableCellElement, (ev: MouseEvent) => void>();
for (const elt of arr_elt) {
// console.log(elt);
// if (!(elt instanceof HTMLTableCellElement)) throw new TypeError();
const listener_prev = mpp_eltTh_WithListener_prev.get(elt);
if (listener_prev === undefined) {
// new element detected -- add new listener
const listener_new = (ev) => {
// https://developer.mozilla.org/en-US/docs/Web/API/Selection/addRange
const selection = window.getSelection();
if (selection === null) return;
if (selection.rangeCount > 0) {
selection.removeAllRanges(); // must dk .
}
const range = document.createRange();
range.selectNode(elt);
selection.addRange(range);
};
elt.addEventListener('click', listener_new);
mpp_eltTh_WithListener_new.set(elt, listener_new);
} else {
// already have listener
mpp_eltTh_WithListener_prev.delete(elt); // delete (exclude) from old map, so that in a later operation it wont be unregistered
mpp_eltTh_WithListener_new.set(elt, listener_prev);
}
}
// clear up old Map, replace with new Map -- remember to delete (exclude) retained elemnt first before go to this step
for (const [elt_prev, listener_prev] of mpp_eltTh_WithListener_prev) {
elt_prev.removeEventListener('click', listener_prev);
// []
// According to the jquery Documentation when using remove() method over an element, all event listeners are removed from memory. This affects the element it selft and all child nodes. If you want to keep the event listners in memory you should use .detach() instead
// <>
// https://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory#:~:text=According%20to%20the%20jquery%20Documentation,detach()%20instead.
// em // whatever
}
mpp_eltTh_WithListener_prev = mpp_eltTh_WithListener_new;
});
// how to let tsc use let instead of var in generated js
// ;wrong; h:\Using\t1-vite>npx tsc --target ES6 ./src/main.tsx
// h:\Using\t1-vite\compileThis>tsc -p tsconfig.json Update: code modified for constant checking new table element |
Thanks @Norlandz ! It might make sense to ask for a fix in https://github.com/DataTables/DataTablesSrc, can I let you open an issue or even PR there if you feel that's the right move? Thanks |
I didnt read into the API / source code of DataTables, (there might be api for picking the column name), not sure a issue / PR is appropriate. The code above is just a trivial workaround. (If you want to use it anywhere its totally fine) (I may not submit an issue for now until I read through the api in js in future, but if you want to do that instead its fine too.) |
I am reopening this issue as now with |
I got an answer and a working example on the datatables forum: https://datatables.net/forums/discussion/comment/231058 It involves setting a data attribute on the header cells ( |
Actually, if I have looked more into the js, I should know the easiest solution is injecting this js: js = """
for (const eventType of ['select', 'selectstart']) {
document.addEventListener(eventType, function (event) {
if (event.target.nodeType && event.target.nodeType === 3) { // NodeType.TEXT_NODE
const parentElement = event.target.parentElement;
if (parentElement && parentElement.classList.contains('dt-column-title') && parentElement.getAttribute('role') === 'button') {
event.stopPropagation();
}
}
}, true);
}
"""
display(HTML(f"<script>{js}</script>"))
For an example-reference of the itables es table structure in html: <div id="itables_cb1146f3_8b1e_4108_85ad_2b3a13fc4e35_wrapper" class="dt-container dt-empty-footer">
<div class="dt-layout-row dt-layout-table">
<div class="dt-layout-cell">
<table id="itables_cb1146f3_8b1e_4108_85ad_2b3a13fc4e35" class="display nowrap compact dataTable" data-quarto-disable-processing="true" style="width: 2733.83px; float: left">
<colgroup>
<col data-dt-column="0" style="width: 34px" />
<col data-dt-column="1" style="width: 75.875px" />
(//...)
</colgroup>
<thead>
<tr style="text-align: right" role="row">
<th data-dt-column="0" rowspan="1" colspan="1" class="dt-type-numeric dt-orderable-asc dt-orderable-desc" aria-label=": Activate to sort" tabindex="0">
<span class="dt-column-title" role="button"></span><span class="dt-column-order"></span>
</th>
<th data-dt-column="1" rowspan="1" colspan="1" class="dt-orderable-asc dt-orderable-desc" aria-label="gender: Activate to sort" tabindex="0">
<span class="dt-column-title" role="button">gender</span><span class="dt-column-order"></span>
</th>
<th data-dt-column="2" rowspan="1" colspan="1" class="dt-type-numeric dt-orderable-asc dt-orderable-desc" aria-label="age: Activate to sort" tabindex="0">
<span class="dt-column-title" role="button">age</span><span class="dt-column-order"></span>
</th>
(//...)
</tr>
</thead>
<tbody>
<tr>
<td class="dt-type-numeric">3</td>
<td>Male</td>
<td class="dt-type-numeric">22</td>
<td class="sorting_1">Yes</td>
<td class="dt-type-numeric">2</td>
<td class="dt-type-numeric">1</td>
(//...)
</tr>
(//...)
</tbody>
<tfoot></tfoot>
</table>
</div>
</div>
</div> |
Hi @Norlandz, thank you for the above, it looks great! I will give it a try in the coming days. Ideally I would like to integrate this either in the Also let me ping @AllanJard to see if that seems ok to him or whether he has a different recommendation. Allan, what we are trying to achieve here is to make the columns selectable (so that we can copy the column titles and paste them in the Python shell). Currently we cannot select them (the attempt to select triggers a reordering of the column content). On the forum thread quoted two comments ago you suggested to use |
It is possible to use the Select extension to select a column by clicking on a cell in it (example here - click the "Select columns" button). However, yes, if you want to click in the header, what I would suggest doing is adding an icon that can be used to select the column, and stop the click event from bubbling up the DOM ( Future work: Yes, I have a plan to make this sort of thing easier, and hopefully will be able to work on it later in the year :) |
How to copy a table column name?
The current behavior when click on the
table column name
triggers a sort.Is it possible to allow something like
alt+mouse drag
,, to select & copy the name,, instead of triggering sort?The text was updated successfully, but these errors were encountered: