Version 4.1.0
of the @handsontable/vue
wrapper introduces a new feature - a hot-column
component.
It doesn't only allow to configure the column-related settings using the hot-column
component's attributes, but also create custom renderers and editors using Vue components.
Declaring column settings
To declare column-specific settings, simply pass the settings as hot-column
props (either separately
or wrapped as a settings
prop, exactly as you would for hot-table
).
<hot-table :data="hotData">
<hot-column title="First column header">
</hot-column>
<hot-column :settings="secondColumnSettings" read-only="true">
</hot-column>
</hot-table>
Declaring a custom renderer as a component
The wrapper allows creating custom renderers using Vue components. The data you would normally get as arguments of
the rendering function will be injected into the rendering component's $data
object.
To mark a component as a Handsontable renderer, simply add a hot-renderer
attribute to it.
autoRowSize
and autoColumnSize
options require calculating the
widths/heights of some of the cells before rendering them into the table, it's not currently possible to use them alongside component-based renderers,
as they're created after the table's initialization.Be sure to turn those options off in your Handsontable config, as keeping them enabled may cause unexpected results.
<hot-table :settings="hotSettings">
<hot-column :width="250">
<custom-renderer hot-renderer></custom-renderer>
</hot-column>
</hot-table>
By default, the number of entries available for the cache is set to
3000
, which means 3000 cells can be rendered at the same time, while being read from the cache.
However, for larger tables, some of the cells may not be able to be cached, and thus, their corresponding component would be recreated each time a cell is rendered (which is not
great for performance).To prevent this problem, it is possible to pass the
wrapperRendererCacheSize
option to the HotTable
component and set it to a number of
entries to be available in the renderer cache.
Declaring a custom editor as a component
You can also utilize the Vue components to create custom editors. To do so, you'll need to create a component compatible with
Handsontable's editor class structure. The easiest way to do so is to extend BaseEditorComponent
- a base editor component exported from @handsontable/vue
.
This will give you a solid base to build upon. Note, that the editor component needs to tick all of the boxes that a regular editor does,
such as defining the getValue
, setValue
, open
, close
and focus
methods,
which are abstract in the BaseEditor
. For more info, check the documentation on
creating custom editors from scratch.
<hot-table :settings="hotSettings">
<hot-column :width="250">
<custom-editor hot-editor></custom-editor>
</hot-column>
</hot-table>
<script type="text/x-template" id="editor-template">
// We're binding the `style` attribute to the style object in our component's data
// as well as the `mousedown` event to a function, which stops the event propagation
// in order to prevent closing the editor on click.
<div v-if="isVisible" id="editorElement" :style="style" @mousedown="stopMousedownPropagation" >
<button v-on:click="setLowerCase">{{ value.toLowerCase() }}</button>
<button v-on:click="setUpperCase">{{ value.toUpperCase() }}</button>
</div>
</script>
Using the renderer/editor components with v-model
You can obviously use Vue's v-model
with the renderer and editor components.
In the example below, we're utilizing an input with v-model
assigned, and the reading the bound property from the renderer component to highlight the rows
entered into the input.
<div id="v-model-example">
<label for="mainInput">List of row indexes (starting from 0):</label><br>
<input id="mainInput" v-model="highlightedRows"/>
<br><br>
<hot-table :settings="hotSettings" :row-headers="true" :col-headers="true">
<hot-column :width="50">
<custom-renderer hot-renderer></custom-renderer>
</hot-column>
</hot-table>
</div>
A more advanced example
In this example, we'll be combining several capabilities of the wrapper:
- We will create a custom editor component with an external dependency, which will act as both renderer and editor
- We will declare settings for several columns using Vue's
v-for
- We will create a component, which state will be bound by the data we get from the first component
Due to the complexity of this example, I've decided to split the components to different files, so it's previewable on Codesandbox instead of jsfiddle.
1. Editor component with an external dependency, which will act as both renderer and editor
To use an external editor component with Handsontable, you'll need to create an addition "bridge" component, to connect your dependency's and Handsontable's API. In this example, we'll use an external color-picker component, vue-color.
The editor implementation is pretty straightforward: you need to import your dependency, place in in your editor template and attach its events to your editor logic and you're done!
In our case, we're also adding an "Apply" button, which triggers Handsontable base editor's finishEditing
method,
so all the heavy lifting regarding passing the new value to the dataset is done for us.
All that's left is to modify the component template to be used as a renderer and editor. We'll utilize the isEditor
and isRenderer
properties,
injected to the component instances created by the wrapper. The template will be divided into a render part and an editor part using Vue's v-if
.
This component contains some Vuex state logic, but ignore it for now, we'll get to it in the third point.
2. Using v-for
for column declaration
Let's use v-for
to declare the second and third column in a loop. Obviously, you can bind the loop to your data and get the settings from there.
<hot-table :settings="hotSettings">
<hot-column :width="120">
<stars-rating hot-renderer></stars-rating>
</hot-column>
<hot-column v-for="n in 2" :width="120" v-bind:key="'col' + n">
<color-picker hot-editor hot-renderer></color-picker>
</hot-column>
</hot-table>
3. Binding the state between components.
As you can see in our first editor/renderer component, we're already commiting all of the changes into the applications $store
.
This way, we can easily bind the state of our new component (based on a star-rating component dependency) to the data in the second and third column.