Search code examples
javascriptreactjsdraggablereact-grid-layout

ReactJS react-grid-layout toggle static property


I've been learning React for a couple of days, this time I'm trying to create a grid of draggable widgets, and I found this library on github: react-grid-layout which does that.

This time, I'm trying to toggle draggable or static property when clicking on a button but I'm having some troubles doing so.

This is my App.js:

import React, { Component } from 'react';
import {InputText} from 'primereact/components/inputtext/InputText';
import GridLayout from 'react-grid-layout';
import './App.css';

class App extends Component {
    render() {
        var layout = [
            {i: 'a', x: 0, y: 0, w: 10, h: 4},
            {i: 'b', x: 1, y: 0, w: 3, h: 2},
            {i: 'c', x: 4, y: 0, w: 1, h: 2}
        ];
        return (
            <React.Fragment>
                <button onClick={this.toggleStatic (layout)}>Enable</button>
                <GridLayout className="layout" layout={layout} cols={30} rowHeight={30} width={1200} onDragStop={this.onDragStop}>
                    <div key="a">a</div>
                    <div key="b">b</div>
                    <div key="c">c</div>
                </GridLayout>
            </React.Fragment>
        );
    }

    toggleStatic(layout) {
        console.log('Layout', layout);
    }

    onDragStop(layout) {
        layout[0].static = true;
        console.log(layout);
    }
}

export default App;

My index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
import 'primereact/resources/themes/omega/theme.css';
import 'primereact/resources/primereact.min.css';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

And my index.css:

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}

.react-grid-item:not(.react-grid-placeholder) {
    background-color: #ccc;
    border: 1px solid black;
}

.layout {
    background-color: #333;
}

.title {
    font-weight: bold;
}

If I check my console, right after reloading the page I get my layout logged into it, before any click:

Layout […]
​0: Object { i: "a", x: 0, y: 0, … }
1: Object { i: "b", x: 1, y: 0, … }    ​
2: Object { i: "c", x: 4, y: 0, … }    ​
length: 3
__proto__: Array []

But if I change my button to:

<button onClick={this.toggleStatic}>Enable</button>

i.e. removing the parameter layout from it, I get this output in the console:

Layout Proxy
    <target>: Object { … }
    <handler>: Object { … }

Right now, my code changes static of first widget to true when any component is dragged, I'm trying to change it for all of then on a button click.

I found this post on the library's issues: Assign static dinamically/programatically, but they're using react-redux.

I found them using this as well:

const mapStateToProps = state => {
  return {
    ...state.dashboard.asMutable()
  };
};

But I'm not sure what does that does.

Any suggestion to at least receive the layout var into the toggleStatic might be enough for me for this matter.


Solution

  • {this.toggleStatic (layout)} will trigger the function on render not onClick, so you gotta change:

    <button onClick={this.toggleStatic (layout)}>Enable</button>
    

    to:

    <button onClick={() => this.toggleStatic(layout)}>Enable</button>
    

    Then when you click on the button you get the layout.

    Add layout in state:

    // ...
    class App extends Component {
        state = {
             layout: [
                {i: 'a', x: 0, y: 0, w: 10, h: 4},
                {i: 'b', x: 1, y: 0, w: 3, h: 2},
                {i: 'c', x: 4, y: 0, w: 1, h: 2}
             ]
        }
        render() {
            return (
                <React.Fragment>
                    <button onClick={() => this.toggleStatic(this.state.layout)}>Enable</button>
                    <GridLayout className="layout" layout={this.state.layout} cols={30} rowHeight={30} width={1200} onDragStop={this.onDragStop}>
                        <div key="a">a</div>
                        <div key="b">b</div>
                        <div key="c">c</div>
                    </GridLayout>
                </React.Fragment>
            );
        }
    
    // ...
    

    Then in toggleStatic function do something like:

    toggleStatic(layout){
        var newLayout = layout.map(l => {
               return {...l, static: !l.static || true}
        })
        this.setState({
            layout: newLayout
        })
    }