8

I'm starting with react and trying to set up handsontable in my react app following: react-handsontable

// import React...
import React from 'react';
import ReactDOM from 'react-dom';

// ... Handsontable with its main dependencies...
import moment from 'moment';
import numbro from 'numbro';
import pikaday from 'pikaday';
import Zeroclipboard from 'zeroclipboard';
import Handsontable from 'handsontable';

// ... and HotTable
import HotTable from 'react-handsontable';

class ExampleComponent extends React.Component {
  constructor(props) {
    super(props);
    this.handsontableData = [
      ["", "Ford", "Volvo", "Toyota", "Honda"],
      ["2016", 10, 11, 12, 13],
      ["2017", 20, 11, 14, 13],
      ["2018", 30, 15, 12, 13]
    ];
  }

  render() {
    return (
      <div id="example-component">
        <HotTable root="hot" data={this.handsontableData} colHeaders={true} rowHeaders={true} width="600" height="300" stretchH="all" />
      </div>
    );
  }
}

Works so far but how do I get the instance of the table like in pure javascript

var ht = new Handsontable(document.getElementById('example1'), options);


ht.setDataAtCell(0, 0, 'new value');

Thanks, Tim

Tim
  • 147
  • 1
  • 10

4 Answers4

8

If you're trying to access the core methods, like 'setDataAtCell()', you can use refs to access them.

For example add the "ref='xyz'" attribute to the HTML element and you can then call it with "this.refs.xyz". I've modified your example below to illustrate. It adds a button that onClick runs a function to 'setDataAtCell'.

// import React...
import React from 'react';
import ReactDOM from 'react-dom';

// ... Handsontable with its main dependencies...
import moment from 'moment';
import numbro from 'numbro';
import pikaday from 'pikaday';
import Zeroclipboard from 'zeroclipboard';
import Handsontable from 'handsontable';

// ... and HotTable
import HotTable from 'react-handsontable';

class ExampleComponent extends React.Component {
  constructor(props) {
    super(props);
    this.handsontableData = [
      ["", "Ford", "Volvo", "Toyota", "Honda"],
      ["2016", 10, 11, 12, 13],
      ["2017", 20, 11, 14, 13],
      ["2018", 30, 15, 12, 13]
    ];
  }

  handleClick(e) {
    this.refs.hot.hotInstance.setDataAtCell(0, 0, 'new value')
  }

  render() {
    return (
      <div id="example-component">
        <HotTable root="hot"
                  data={this.handsontableData}
                  colHeaders={true}
                  rowHeaders={true}
                  width="600"
                  height="300"
                  stretchH="all"
                  ref="hot"
        />
        <br/>
        <button onClick={(e)=>this.handleClick(e)}>Click Me</button>
      </div>
    );
  }
}

export default ExampleComponent

This method can be used to access other methods like "getData()" which can be used to get a snapshot of the data in the table which can be saved to state or similar. So it's more lengthy than "ht" you can use "this.refs.hot.hotInstance" for similar affect.

You can read more about the ref attribute in "Refs and the DOM" in the React documentation.

Tantivy
  • 556
  • 1
  • 4
  • 11
  • 3
    Thanks, this worked for me, but React now recommends using the [`createRef` API](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) instead of using `this.refs` directly ([more info](https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs)). – Rafael Jun 20 '18 at 10:04
4

To access the instance of HotTable component, use ref. However, don't use old way of using ref. As of version 16.3, React provides 2 ways :

  • using createRef API which is the recommended way
  • using callback ref which is already available in earlier version, but better than the old "string ref" way.

I only show how to use createRef here :

  1. In your constructor, add the following :

    this.refToHotIns=React.createRef();
    

    The name of the field property is arbitrary, you can name it as you like.

  2. In your render() method, change the JSX element to :

       <HotTable ref={this.refToHotIns} data={this.handsontableData} colHeaders={true} rowHeaders=true} width="600" height="300" stretchH="all" />
    
  3. Now, this.refToHotIns.current references to mounted HotTable instance. The Handsontable instance is stored under the hotInstance property of the wrapper component. So you can then access properties/methods of HotTable instance, like so :

    this.refToHotIns.current.hotInstance.setDataAtCell(0, 0, 'new value');
    
Lex Soft
  • 2,308
  • 2
  • 13
  • 13
3

It's pretty simple to write your own react wrapper for handsontable, and then you can create a reference to your HOT instance. Here is some sample React component code:

componentWillReceiveProps({ gridSpec }) {

     if (gridSpec) {
        const {columns, colHeaders, data} = gridSpec;
        const container = document.getElementById(GRID_ID);

        this.hotInstance = new handsontable(container, {
            columns,
            colHeaders,
            data,
            height: 600
        });
    }
}

shouldComponentUpdate () {

    return false;
 }

render () {
    return (
        <div style={{overflowX: 'hidden', height: '600px'}}>
            <div id={GRID_ID} />
        </div>
    )
}
1

you have your data as an array defined in the constructor.

this.handsonetableData = [[First row],[second row]]

You could simply link that data to a state and setState inside your component. It should be really straightforward.

this.state = {
  table: [[first line], [second line]]
}

Eventually going further you can write your own method that update a specific value of that array.

constructor (props) {
  super(props)
  this.state = {
    table: [[first row], [second row]]
  }
}
updateValueInTable (row, col, value)
  checkIdontDoAnythingStupid()
  let newTable = this.state.table
  newTable[row][col] = value
  this.setState({ table: newTable})
}

If you do not want to use the state and use something like redux you put the logic in the reducer and the triggers in actions. And there you are!

Of course is up to you how to check that you manipulate correctly your array, a lot of libraries can come to help (lodash and co.)

piratz
  • 361
  • 1
  • 9
  • thanks for your answer, but this sill does not give me an instance of the table. – Tim May 17 '17 at 07:21
  • sorry Tim, why do you need an instance of the Table when can control it with the array? I ask to understand better your question.. – piratz May 18 '17 at 08:09
  • I need a instance to be able to use the handsontable api not only data manipulation. – Tim May 23 '17 at 10:15
  • also when you do things like sorting, the afterchange event gives you the logical indexes, not the physical ones. This means the data you are working with will come out of sync with the data in the state. – Mike Jun 13 '17 at 21:23
  • @Tim, here's how to access the data: handleClick(e) { console.log(this.refs.hot.props.data); } – Florida G. Oct 07 '17 at 15:17