0

I tried to using this react dnd on the react typescript. sample not working on the type script project , any one know how to do that correctly on the react typescript

import React, { Component } from 'react';
    import ReactDOM from 'react-dom';
    import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

    // fake data generator
    const getItems = (count, offset = 0) =>
      Array.from({ length: count }, (v, k) => k).map(k => ({
        id: `item-${k + offset}`,
        content: `Item: ${k + offset}, Random value: ${Math.round(Math.random() * 100)}`,
        color: Math.random () > 0.66 ? 'pink': Math.random() > 0.5 ? 'lightgreen' : 'beige'
      }))

    // a little function to help us with reordering the result
    const reorder = (list, startIndex, endIndex) => {
      const result = Array.from(list)
      const [removed] = result.splice(startIndex, 1)
      result.splice(endIndex, 0, removed)
      return result
    }

    /**
     * Moves an item from one list to another list.
     */
    const move = (source, destination, droppableSource, droppableDestination) => {
      const sourceClone = Array.from(source)
      const destClone = Array.from(destination)
      const [removed] = sourceClone.splice(droppableSource.index, 1)

      destClone.splice(droppableDestination.index, 0, removed)

      const result = {}
      result[droppableSource.droppableId] = sourceClone
      result[droppableDestination.droppableId] = destClone

      return result
    }

    const grid = 4

    const getItemStyle = (isDragging, draggableStyle) => ({
      // some basic styles to make the items look a bit nicer
      userSelect: 'none',
      padding: grid * 2,
      margin: `0 0 ${grid}px 0`,

      // change background colour if dragging
      background: isDragging ? 'lightgreen' : 'lightgrey',

      // styles we need to apply on draggables
      ...draggableStyle
    })

    const getListStyle = isDraggingOver => ({
      background: isDraggingOver ? 'lightblue' : '#eee',
      padding: grid,
      margin: '3px',
      width: 250
    })

    class App extends Component {
      state = {
        list1: getItems(5,1),
        list2: getItems(4, 6),
        list3: getItems(6, 10)
      }

      /**
       * A semi-generic way to handle multiple lists. Matches
       * the IDs of the droppable container to the names of the
       * source arrays stored in the state.
       */
      droppableIds = {
        droppable1: 'list1',
        droppable2: 'list2',
        droppable3: 'list3'
      }

      getList = id => this.state[this.droppableIds[id]]

      onDragEnd = result => {
        const { source, destination } = result

        // dropped outside the list
        if (!destination) { return }

        if (source.droppableId === destination.droppableId) {
          const items = reorder(
            this.getList(source.droppableId),
            source.index,
            destination.index
          )

          let copiedState = Object.assign({}, this.state)

          if (source.droppableId === 'droppable1') {
            copiedState.list1 = items
          } else if (source.droppableId === 'droppable2') {
            copiedState.list2 = items
          } else if (source.droppableId === 'droppable3') {
            copiedState.list3 = items
          }

          this.setState(copiedState)
        } else {
          const result = move(
            this.getList(source.droppableId),
            this.getList(destination.droppableId),
            source,
            destination
          )

          console.warn('result', result)
          this.setState({
            list1: result.droppable1 ? result.droppable1 : this.state.list1,
            list2: result.droppable2 ? result.droppable2 : this.state.list2,
            list3: result.droppable3 ? result.droppable3 : this.state.list3
          })
        }
      }

      // Normally you would want to split things out into separate components.
      // But in this example everything is just done in one place for simplicity
      render() {
        const lists = [
          {
            droppableId: 'droppable1',
            listId: 'list1',
            title: 'List A'
          },
          {
            droppableId: 'droppable2',
            listId: 'list2',
            title: 'List B'
          },
          {
            droppableId: 'droppable3',
            listId: 'list3',
            title: 'List C'
          },
        ]
        return (
          <div style={{ display: 'flex' }}>
            <DragDropContext onDragEnd={this.onDragEnd}>

              {lists.map((list, listIndex) =>
                <Droppable key={'list-droppable-' + listIndex} droppableId={list.droppableId}>
                  {(provided, snapshot) => (
                    <div
                      ref={provided.innerRef}
                      style={getListStyle(snapshot.isDraggingOver)}>
                      <h4>
                        {list.title}
                      </h4>
                      {this.state[list.listId] && this.state[list.listId].map((item, index) => (
                        <Draggable
                          key={item.id}
                          draggableId={item.id}
                          index={index}>
                          {(provided, snapshot) => (
                            <div
                              ref={provided.innerRef}
                              { ...provided.draggableProps }
                              { ...provided.dragHandleProps }
                              style={getItemStyle(
                                snapshot.isDragging,
                                provided.draggableProps.style
                              )}>
                              <div style={{ background: item.color }}>
                                {item.content}
                              </div>
                            </div>
                          )}
                        </Draggable>
                      ))}
                      {provided.placeholder}
                    </div>
                  )}
                </Droppable>
              )}
            </DragDropContext>
          </div>
        )
      }
    }

    // Put the things into the DOM!
    ReactDOM.render(<App />, document.getElementById('root'));
core114
  • 5,155
  • 16
  • 92
  • 189

1 Answers1

4

Try something like this.

import React, { Component } from "react";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";

// fake data generator
const getItems = (count: number, offset: number): object =>
  Array.from({ length: count }, (v, k): number => k).map(
    (k: number): {} => ({
      id: `item-${k + offset}`,
      content: `Item: ${k + offset}, Random value: ${Math.round(
        Math.random() * 100
      )}`,
      color:
        Math.random() > 0.66
          ? "pink"
          : Math.random() > 0.5
          ? "lightgreen"
          : "beige"
    })
  );

// a little function to help us with reordering the result
const reorder = (list: [], startIndex: number, endIndex: number): object => {
  const result = Array.from(list);
  const [removed] = result.splice(startIndex, 1);
  result.splice(endIndex, 0, removed);
  return result;
};

/**
 * Moves an item from one list to another list.
 */
const move = (
  source: any,
  destination: any,
  droppableSource: any,
  droppableDestination: any
): {} => {
  const sourceClone = Array.from(source);
  const destClone = Array.from(destination);
  const [removed] = sourceClone.splice(droppableSource.index, 1);

  destClone.splice(droppableDestination.index, 0, removed);

  let result: any = {};
  result[droppableSource.droppableId] = sourceClone;
  result[droppableDestination.droppableId] = destClone;

  return result;
};

const grid = 4;

const getItemStyle = (isDragging: boolean, draggableStyle: any): object => ({
  // some basic styles to make the items look a bit nicer
  userSelect: "none",
  padding: grid * 2,
  margin: `0 0 ${grid}px 0`,

  // change background colour if dragging
  background: isDragging ? "lightgreen" : "lightgrey",

  // styles we need to apply on draggables
  ...draggableStyle
});

const getListStyle = (isDraggingOver: boolean): object => ({
  background: isDraggingOver ? "lightblue" : "#eee",
  padding: grid,
  margin: "3px",
  width: 250
});

interface State {
  list1: object;
  list2: object;
  list3: object;
}

class App extends Component<State> {
  state: State = {
    list1: getItems(5, 1),
    list2: getItems(4, 6),
    list3: getItems(6, 10)
  };

  /**
   * A semi-generic way to handle multiple lists. Matches
   * the IDs of the droppable container to the names of the
   * source arrays stored in the state.
   */
  droppableIds = {
    droppable1: "list1",
    droppable2: "list2",
    droppable3: "list3"
  };

  getList = (id: string): any => this.state[this.droppableIds[id]];

  onDragEnd = (result: any) => {
    const { source, destination } = result;

    // dropped outside the list
    if (!destination) {
      return;
    }

    if (source.droppableId === destination.droppableId) {
      const items: object = reorder(
        this.getList(source.droppableId),
        source.index,
        destination.index
      );

      let copiedState: any = Object.assign({}, this.state);

      if (source.droppableId === "droppable1") {
        copiedState.list1 = items;
      } else if (source.droppableId === "droppable2") {
        copiedState.list2 = items;
      } else if (source.droppableId === "droppable3") {
        copiedState.list3 = items;
      }

      this.setState(copiedState);
    } else {
      const result: any = move(
        this.getList(source.droppableId),
        this.getList(destination.droppableId),
        source,
        destination
      );

      this.setState({
        list1: result.droppable1 ? result.droppable1 : this.state.list1,
        list2: result.droppable2 ? result.droppable2 : this.state.list2,
        list3: result.droppable3 ? result.droppable3 : this.state.list3
      });
    }
  };
  render() {
    const lists = [
      {
        droppableId: "droppable1",
        listId: "list1",
        title: "List A"
      },
      {
        droppableId: "droppable2",
        listId: "list2",
        title: "List B"
      },
      {
        droppableId: "droppable3",
        listId: "list3",
        title: "List C"
      }
    ];
    return (
      <div style={{ display: "flex" }}>
        <DragDropContext onDragEnd={this.onDragEnd}>
          {lists.map((list, listIndex) => (
            <Droppable
              key={"list-droppable-" + listIndex}
              droppableId={list.droppableId}
            >
              {(provided: any, snapshot: any) => (
                <div
                  ref={provided.innerRef}
                  style={getListStyle(snapshot.isDraggingOver)}
                >
                  <h4>{list.title}</h4>
                  {this.state[list.listId] &&
                    this.state[list.listId].map((item: any, index: number) => (
                      <Draggable
                        key={item.id}
                        draggableId={item.id}
                        index={index}
                      >
                        {(provided: any, snapshot: any) => (
                          <div
                            ref={provided.innerRef}
                            {...provided.draggableProps}
                            {...provided.dragHandleProps}
                            style={getItemStyle(
                              snapshot.isDragging,
                              provided.draggableProps.style
                            )}
                          >
                            <div style={{ background: item.color }}>
                              {item.content}
                            </div>
                          </div>
                        )}
                      </Draggable>
                    ))}
                  {provided.placeholder}
                </div>
              )}
            </Droppable>
          ))}
        </DragDropContext>
      </div>
    );
  }
}

export default App;

And here is a working example codesandox

TRomesh
  • 4,323
  • 8
  • 44
  • 74
  • I got this error 'Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{}'. TS7053 92 | droppable3: "list3" 93 | }; > 94 | getList = (id: string): [] => this.state[this.droppableIds[id]]; | ^ 95 | 96 | onDragEnd = (result: any) => { 97 | const { source, destination } = result;' – core114 Feb 17 '20 at 09:11
  • In tsconfig.json there is an option "noImplicitAny" that it was set to true(if the property is not there just add it with false value), just simply set it to false and now I can access properties in objects using strings. – TRomesh Feb 17 '20 at 10:20
  • Hi, yes its worked for me, but i have small issue on this, do you know the reason for flowing error ?TypeError: Cannot read property 'style' of undefined (anonymous function) style={getItemStyle( | ^ 203 | snapshot.isDragging, 204 | provided.draggableProps.style 205 | )} – core114 Feb 17 '20 at 12:31
  • @core114 im not quite sure what cause this error. Maybe the getItemStyle() is not returning the correct data types expected. Need to see this full code to have a proper idea about it. If my answer worked can you accept it :D – TRomesh Feb 18 '20 at 06:13