Closed ghiscoding closed 4 months ago
Start a new pull request in StackBlitz Codeflow.
This is a regression caused by PR #1476 which was fixing another bug #1475
in PR #1476, I used cloneNode(true)
to clone the HTML element but that method doesn't copy the event listeners. This change does not exist in SlickGrid, hence why the new bug doesn't show up in SlickGrid.
At this point, I'm not sure if the use of cloneNode()
is the best approach and if not, then what approach should we use to not regress #1475. Note that the button listener does work after removing the cloneNode()
but reopens my previous fix for #1475. If I keep the cloneNode()
then I'll have to copy all optional event listeners by hand (not sure how to do that though), see this SO How to copy a DOM node with event listeners?... so anyway, considering this new issue, I don't think the cloneNode()
was the best thing to do in the first place, it would require more troubleshooting to understand why bug #1475 happened in the first place and removing the clone would fix current issue
@zewa666 @ardakod I'm opened to suggestion here
side note, my tendency of using animated gif can be quite useful, especially when revisiting old issues like this one
well the root-cause is understandable.
appendChild
inside slickGrid.ts->applyHtmlCode
will do sopickerHeaderColumnValueExtractor
from global-grid-options.ts. In here there is an issue tough ... it grabs the name by supposing it's a string, yet it is the in step1 created span element. Next it calls applyHtmlCode
again, which will execute again appendChild on the same element, thus move the element from the column header to the picker.so the issue I'd say is how the label for the picker is constructed as merely the text needs to be displayed there but not the actual element moved. I've created a PR with a potential solution.
yeah I found that if I modify the global value extractor as below, it fixes the issue without the need for the clone. I'm not sure reading the .textContent
is always the right way to do it though
function pickerHeaderColumnValueExtractor(column: Column, gridOptions?: GridOption) {
let colName = column?.name ?? '';
if (colName instanceof HTMLElement) {
colName = colName.textContent || '';
}
const headerGroup = column?.columnGroup || '';
const columnGroupSeparator = gridOptions?.columnGroupSeparator ?? ' - ';
if (headerGroup) {
return headerGroup + columnGroupSeparator + colName;
}
return colName;
}
EDIT
ohhh I just realized you did the exact same changes lol, thanks for the PR, I left some comments
yeah it was just a quick one to show where the potential solution could go. Seeing you did the same makes me feel like its the proper thing to do. I've closed my PR since you're at it anyways.
if you don't like textContent you could instead use the deepClone here since you'll most likely not care about the attached handlers in the context of the columnPicker. I'd personally stick with the textContent as it feels cleaner though
yeah the concern I have is the following (I've also put the same comment in your now closed PR)
I had another possible problem with the .textContent
, this will read all element texts but is that really ideal though? I mean I just tested this with an HTML element that has some text and a button with text and it gives me what is shown below (the button text is also pulled). However, I'm not sure that we can do much about it?!?
that is using the following code
const div = document.createElement('div');
const button = document.createElement('button');
button.className = 'button button-small';
button.textContent = 'click';
button.addEventListener('click', () => alert('hi'));
div.appendChild(document.createTextNode('Column 1 '));
div.appendChild(button);
this.columnDefinitions = [
{
id: 'sel', name: div, field: 'num', width: 80, type: FieldType.number,
excludeFromExport: true,
resizable: true,
filterable: true,
selectable: false,
focusable: false
},
well if you'd want to maintain that functionality here too, which I quite frankly think is a sideeffect users typically dont think off, we'd need a deepClone of the element for the picker.
I think the better approach alltogether would be to introduce something like a pickerLabel: string | HTMLElement | DocumentFragment
property on the column interface which would be taken first and textContent of name as a fallback.
so do you mean something like this instead
headerColumnValueExtractor: (columnDef: Column) => getHtmlStringOutput(columnDef.pickerLabel || columnDef.name || '', 'innerHTML')
EDIT
actually it seems that I have to do this change on the global value extractor instead
yep exactly, that would keep textContent as default, which most likely will be fine 9 out of 10 times. but for these other cases you can create the label to override the behavior
Yeah that seems like a nice feature, now with this new prop (renamed it to columnPickerLabel
), it shows my custom label
this.columnDefinitions = [
{
id: 'sel', name: div, field: 'num', width: 80, type: FieldType.number,
+ columnPickerLabel: 'Custom Label',
excludeFromExport: true,
resizable: true,
filterable: true,
selectable: false,
focusable: false
},
ok so I've opened PR #1607, I'm just missing a bit more unit tests and E2E tests but apart from that the code should be good as it is and fix this issue without regressing. @zewa666 thanks a ton for the feedback provided, it was again very helpful 😉
Describe the bug
This bug was first reported in Angular-Slickgrid but is really code related to Slickgrid-Universal, so I'm closing the Angular-Slickgrid issue and opening this new one with same info
Reproduction
Which Framework are you using?
Angular
Environment Info
Validations