Implementation of Drag & Drop using React Beautiful DND and Material Ui….
Hi Guys, hope everything is going fine and good,In this Blog I am going to implement a complex functionality of drag and drop using React beautiful DND and material Ui. You may be familiar with material Ui ,a well known React Framework for web designing,it’s simple and it’s component are by default responsive in nature,and it has it’s own way of styling and grid system.On the other hand React beautiful DND is just a magical drag and drop package which help make a react component draggable and droppable very easily .Actually React DND works totally with simple javascript concepts which are really very effective and easy.
So lets discuss what we are going to develop using React DND ,we will design a component having 6 cards as it’s child component ,those cards are swappable within themselves,for making it little bit tricky I have a added a filter functionality which will determine which card will be visible and which are not.So now we are clear with our application let’s starting coding.
First we will just create a React boilerplate writing npx create-react-app followed by whatever project name you want to give in terminal,after that create a component folder in src folder which will be having 6 cards and App.js will be the root component which will contain all the 6 cards.So lets first see the very simple 6 cards which we will append as a child inside a component called dragAndDrop component.
So these are the 6 cards which we are going to append inside a parent component dragAndDrop,these cards will be then able to swap each other and can be filtered using checkbox present in the checkbox of the dragAndDrop component.Now let’s see the main concept of React Beautiful DND on dragAndDrop component.
So before moving into the code explanation ,we should know some concepts of ReactDND. ReactDND enables beautiful drag and drop experience for list with React.It has three major components:
- DragDropContext.
- Droppable.
- Draggable.
We will discuss about those one by one :
- DragDropContext:
DragDropContext is the component that we use as part of application where we want to have drag and drop enabled for,means all the component in which we want to perform drag and drop must be inside DragDropContext, By default DragDropContext have some default properties/parameters which are :
a. onDragStart: called when drag Start.
b. onDragUpdate: called when something changes during drag.
c. onDragEnd: called at end of the drag.
We are going to use onDragEnd ,it is the responsibility of DragEnd function to synchronously update our DOM to reflect the drag and drop result.
2. Droppable:
Droppable is the component which must be present inside DragDropContext ,it allows draggable components to be able to drop at the desired position,it has a parameter named droppableId,this id needs to be unique within the DragDropContext ,Droppable utilizes the render props pattern and expects it’s child to be a function. one reason why render props pattern is used is that react beautiful DND does not need to create any DOM order for us,we have to create our components the way we want it and then react beautiful DND work into our existing structure ,the 1st argument of the function is provided, provided is an object having several properties like,droppableProps, these are the properties that needed to applied to the component that you want to designate as your droppable component ,innerRef is the another property of provided which is a function used to supply the DOM node of our component to your ReactDND. Another property of provided is placeholder it is a react component that is used to increase available space which is droppable in a drag event when it is needed.
3. Draggable:
Draggable makes the component draggable,it has usually two parameter provided and snapshot ,likely droppable,the provided property of draggable is having properties like draggableProps,innerRef and it is having another property called dragHandleProps which determines which part of the draggable component will work as the handle for dragging the component. Draggable also returns another property other than provided that is snapshot , this object contains no of properties that we can use to style our draggable component.Let’s see how the property snapshot actually looks like
a. When we drag a draggable Component :
const draggableSnapshot ={
isDragging: true(when the draggable component is dragged,isDragging becomes true.)
draggingOver: ‘droppableId’(it contains the droppable id of the draggable is currently dragging over)
}
b. When we drag a draggable component over Droppable component:
const draggableSnapshot={
isDraggingOver: true(when the draggable component is dragged over droppable component ,isDraggingOver gets true.)
draggingOverwith: ‘draggableId’(It contains the id of the draggable component that is dragging over the droppable component)
}
Now let’s see what the onDragStart,onDragUpdate and onDragEnd function actually returns
//onDragStart
const start={
draggableId: ‘task-1’,
type: ‘TYPE’,
source:{
droppableId: ‘column1',
index:0
}
}
//onDragUpdate
const update={
…start,
destination:{
droppableId: ‘column-1’,
index: 0
}
//onDragEnd
const result={
…update,
reason: ‘DROP’
}
so OnDragEnd() function actually return this result object which contains all the properties required to perform the drag & drop functionality.
Let’s see the structure of our application:
So we have created a DragDropContext tag inside that we have created 3 Droppable tags, inside each Droppable tag there is Draggable tag ,inside that Draggable tag we are having a Droppable tag ,and inside that lastly we have kept our cards inside each Draggable tag . So why we are doing this? we have to understand the concept behind this .Inside DragDropContext component we will perform the whole drag and drop functionality,inside that we have 3 Droppable component aligned column wise,this will allow the cards to get droppable ,inside each Droppable we have created Draggable so that all the components inside it becomes draggable,but it will only allow the cards to swap between their respective column components only. To make all component swappable we have to keep a unique droppable id for all the components,for this inside each Draggable tag in each column we are creating another Droppable component and inside that we are keeping the Draggable component which are actually wrapping our cards to make them draggable and droppable.
Now let’s understand the code ,first we have imported all the cards and then defined our useStyle property for our material ui component for styling.if we see in the initialState state of the component we will see the whole DOM rendering will happen mapping this initialState. So our initialState is having ColumnOrder which is an array having values ‘column-1’, ‘column-2' and ‘column-3’,We will keep these three columns inside our first Droppable tag ,inside this Droppable tag we are looping through the columns property of initialState to form the Draggable columns ,inside each Draggable column we are creating another Droppable column ,inside that Droppable column we are looping through the initialState.columns.cardIds to create our final Draggable component and rendering our cards inside it by looping through the cards property of initialState. It will be more clear if we see the render part of our code.Now let’s see the onDragEnd function which is called in DragDropContext, it is the main function which is called whenever a Drag functionality happens,as discussed earlier onDragEnd returns a variable called result which contains all the required data required to manipulate our DOM to perform the drag and drop.Inside onDragEnd() we are getting response on result ,then we are destructuring destination,source,draggableId and type from result ,if the card is placed in a empty space destination will return null ,no swapping will happen so we are checking that ,then we are checking if destination.droppableId==source.droppableId and destination.index==source.index means a card is dragged and lastly dropped on itself ,then also no swapping will happen .Now we are taking the source.droppableId and iterating through our initialState to get the column property of the source and storing the object in start similarly we are storing the column property of destination in finish ,now we are checking start==finish ,means when swapping is happening between cards inside same columns,we are changing the initialState.columns.cardIds immutably so that it reflects in our user interface. So how we are doing this we are taking a copy of that cardIds array ,then using splice method to remove the card having array index= source.index.and replacing it with the card having array index=destination.index.Points to be noted we are passing the cardIds array elements as the draggableId in result,means if we drag cardA from column1 and drop it over cardD in column1 ,draggableId will get cardA and source.index will get index number of cardA and destination.index get index number of cardD.
Array.splice( index, remove_count, item_list )
- index: It is a required parameter. This parameter is the index which start modifying the array (with origin at 0). This can be negative also, which begin after that many elements counting from the end.
- remove_count: The number of elements to be removed from the starting index.
- items_list: The list of new items separated by comma operator that is to be inserted from the starting index.
then we are changing initialState.columns first and then changing the initialState itself by replacing the columns[id] with modified column to perform a immutable modification of state which is very essential for reflecting changes in user interface.
Now if the card present inside different columns are swapped ,we are storing the cardIds array of that specific column in case of source card and removing it from that array.where as in case of destination card we are removing the card having array index =destination.index with the source one, and finally changing them in initialState. This concept initially will look little bit complex but later if you understand ,you will know this is nothing but java script concept.Always try to refer both our DOM structure and onDragEnd function together to understand the concept clearly.Now we will see how our checkbox list which is responsible to make a card visible is working,we have used material-ui AppBar in the header of our component where on clicking on a icon we get a Checkbox list.We are mapping through CardList to render our checkbox list,onChange of our checkbox we are calling handleOption() function. Before rendering the card we are checking if the show property of that card is true or false if the show is false we are rendering that card. So handleOption is the function which toggles the show value of the card to determine whether the card will be visible or not.So As we have understand the whole code,let’s see the output of our code:
So our application is up and running , You can find the whole code in my GitHub repo
CODE:
.So there are many cool stuffs you can do using these awesome libraries, till then don’t stop exploring new things because exploration many a person better in all aspects of life.
HAPPY CODING…..:)