Initially, I tried placing <input>
s into the header <th>
s, but HoT's DOM manipulation is kind of aggressive and they get swiftly removed.
I ended up painting <input>
s above HoT (as direct children of <body>
and replacing header values on change
and blur
events.
I used afterOnCellMouseDown
to create the <input>
s:
new Handsontable(
document.getElementById('example'), {
rowHeaders: true,
colHeaders: true,
minRows: 10,
minCols: 10,
afterOnCellMouseDown: function(event, coords, th) {
if (coords.row === -1 || coords.col === -1) {
let instance = this,
isCol = coords.row === -1,
input = document.createElement('input'),
rect = th.getBoundingClientRect(),
addListeners = (events, headers, index) => {
events.split(' ').forEach(e => {
input.addEventListener(e, () => {
headers[index] = input.value;
instance.updateSettings(isCol ? {
colHeaders: headers
} : {
rowHeaders: headers
});
setTimeout(() => {
if (input.parentNode)
input.parentNode.removeChild(input)
});
})
})
},
appendInput = () => {
input.setAttribute('type', 'text');
input.style.cssText = '' +
'position:absolute;' +
'left:' + rect.left + 'px;' +
'top:' + rect.top + 'px;' +
'width:' + (rect.width - 4) + 'px;' +
'height:' + (rect.height - 4) + 'px;' +
'z-index:1060;';
document.body.appendChild(input);
};
input.value = th.querySelector(
isCol ? '.colHeader' : '.rowHeader'
).innerText;
appendInput();
setTimeout(() => {
input.select();
addListeners('change blur', instance[
isCol ? 'getColHeader' : 'getRowHeader'
](), coords[isCol ? 'col' : 'row']);
});
}
}
}
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/handsontable/5.0.0/handsontable.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/handsontable/5.0.0/handsontable.min.css" rel="stylesheet" />
<div id="example"></div>
Fiddle here.
Note: You don't really need the z-index
if you're in full control of your page's CSS, but I used this in a heavily customized Bootstrap based theme, inside a modal, having z-index:1050
, so I had to give <input>
s more to render them above `.modal-dialog'