drag and drop pour un élément dans un composant ( lui-même dans un composant draggable )
Bonjour
Le titre n'est pas très explicite mais je vais expliquer mon souci le mieux possible.
Dans une application, j'ai un composant qui affiche plusieurs blocs de données ( ici des repas pour exemple ) et chaque bloc de repas peut être déplacé avec un drag and drop.
J'ai essayé de faire le plus simple possible avec le moins de code, n'hésitez pas à me dire s'il y a une meilleurs façon de faire ( surtout que ça peut impacter la suite ).
Je sais déjà que lorsqu'il y a des aliments dans le repas, le "glissé" est moins sympas...
Voici donc ce composant:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| import React, { useState } from "react";
import FoodList from "./FoodList";
import "../../css/mealComposition.css"
const Home: React.FC = () => {
interface Meal {
name: string,
foods: Array<string>
nbInputs: number
}
const [mealList, setMealList] = useState<Meal[]>([
{name: "Repas 1", foods: ["banane", "tomate"]},
{name: "Repas 2", foods: []},
{name: "Repas 3", foods: ["pain", "viande"]},
])
const handleDragStart = (e: React.DragEvent<HTMLDivElement>) => {
const targetElement = e.target as HTMLDivElement
setTimeout(() => targetElement.classList.add('dragging'), 0)
}
const handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
const targetElement = e.target as HTMLDivElement
const zone = document.querySelector('.mealDayContent')
const draggedElement = document.querySelector('.dragging')
const enterElementPositionY = targetElement.getBoundingClientRect().top
const draggedElementPositionY = draggedElement.getBoundingClientRect().top
zone.addEventListener('dragover', (e) => {
e.preventDefault()
})
if (enterElementPositionY > draggedElementPositionY) {
zone.insertBefore(draggedElement, targetElement.nextSibling)
} else {
zone.insertBefore(draggedElement, targetElement)
}
}
const handleDragEnd = (e: React.DragEvent<HTMLDivElement>) => {
const targetElement = e.target as HTMLDivElement
targetElement.classList.remove('dragging')
}
const addMeal = () => {
const newMeal = {name: `repas ${mealList.length + 1}`, foods: [], nbInputs: 0}
const updateMealList = [...mealList, newMeal]
setMealList(updateMealList)
}
return(
<>
<div className="mealDay">
Repas de la journée:
<button onClick={addMeal}> + </button>
</div>
<div className="mealDayContent">
{mealList.map((meal: Meal, index: number) => (
<div
key={index}
className="meal"
draggable="true"
onDragStart={(e) => handleDragStart(e)}
onDragEnter={(e) => handleDragEnter(e)}
onDragEnd={(e) => handleDragEnd(e)}>
<div className="mealName">
{meal.name}
</div>
<FoodList foodList={meal.foods}/>
</div>
))}
</div>
</>)
}
export default Home |
Pour l'instant, je fais simple car j'apprends le drag and drop ( jamais fait avant encore moins avec React... !)
Il reste bien sûr à réorganiser l'objet mealList ( je me débrouillerai avec les index au moment du dragend )
Le problème, le vrai, est le suivant: mon composant Foodlist affiche une liste d'ingrédients et je voudrais pouvoir déplacer ces ingrédients
à l'intérieur d'un repas dans la foodList, mais aussi vers une foodList d'un autre repas.
Par exemple: je dois pouvoir glisser tomate dans le repas 3 ( n'importe ou dans la liste, avant le pain, après la viande ou entre les deux )
voici donc mon composant FoodList:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import React from "react";
interface FoodListProps {
foodList: Array<string>
}
const FoodList: React.FC<FoodListProps> = ({foodList}: FoodListProps) => {
return (
<div className="foodList">
{foodList.map((food: string, index: number) => (
<div key={index} draggable="true" className="food">
{food}
</div>
))}
</div>
)
}
export default FoodList |
Quelles seraient les pistes ? Parce que pour le moment, le composant parent a un impact sur ce composant: ça déplace les aliments en dehors des repas !
( ce qui est tout à fait normal, vu que je n'ai rien codé! )
Je pourrais m'en sortir si j'avais tout dans un composant parent ( mapping des aliments ), mais je voudrais justement savoir comment faire dans ce cas.
De plus React, par principe, ça sert à faire des composants. Donc tout faire dans le même composant n'est pas correct.
J'ai mis un peu de CSS (pas la priorité pour l'instant):
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| input {
display: block;
margin-bottom: 10px;
}
.meal {
border: 2px solid red;
border-radius: 4px;
margin: 10px;
padding: 10px;
cursor: move;
}
.mealName {
margin-bottom: 10px;
font-size: 25px;
}
.dragging {
visibility: hidden;
}
.food {
border: 1px solid black;
border-radius: 4px;
padding: 5px;
margin-bottom: 4px;
}
.foodList {
display: flex;
justify-content: start;
align-items: start;
flex-direction: column;
} |
Évidemment, une piste sans librairie, parce que je veux apprendre...
Merci d'avance.
Laurent.