IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

React Discussion :

drag and drop pour un élément dans un composant ( lui-même dans un composant draggable )


Sujet :

React

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    280
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 280
    Par défaut 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 javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    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 javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    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 css : Sélectionner tout - Visualiser dans une fenêtre à part
    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.

  2. #2
    Membre chevronné
    Homme Profil pro
    Urbaniste
    Inscrit en
    Août 2023
    Messages
    387
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Urbaniste

    Informations forums :
    Inscription : Août 2023
    Messages : 387
    Par défaut
    Bonjour,

    A mon avis vous avez déconnecté le state et la vue lorsque vous faites "zone.insertBefore(draggedElement..."

    Normalement l'évènement dragstart doit permettre d'attacher
    une valeur identifiant "la chose" en cours de déplacement/copie.

    Ainsi, lors du drop, vous pouvez récupérer cette identifiant pour ré organiser le state,
    l'opération de rendu fera alors son travail automatiquement.

    Attention ici

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    zone.addEventListener('dragover', (e) => {
    			e.preventDefault()
    		})
    Vous attachez la fonction autant de fois que l'évènement handleDragEnter est déclenché.

    Voir la MDN, https://developer.mozilla.org/en-US/...rag_operations
    Et comme ce n'est pas du react, c'est plus simple à partager.

    Bonne journée.

  3. #3
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    280
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 280
    Par défaut
    Oui, j'ai déconnecté le state et la vue.

    Pour les effets pendant les déplacements: de cette façon, j'ai les blocs sur lesquels je passe qui se déplacent automatiquement.
    Et lors du drop, le bloc déplacé prends sa nouvelle place ( dans le trou prévu a cet effet par les déplacements )


    J'ai essayé en permutant les objets dans le tableau mealList et le rendu automatique: je n'arrive pas à obtenir l'effet voulu...

    C'est pour ça que j'ai choisi cette approche par la suite, récupérer des index et faire cette modification lors du drop.

    Par contre, vous avez raison, je dois changer la place de mon zone.addEventListener

  4. #4
    Membre chevronné
    Homme Profil pro
    Urbaniste
    Inscrit en
    Août 2023
    Messages
    387
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Urbaniste

    Informations forums :
    Inscription : Août 2023
    Messages : 387
    Par défaut
    Bonjour,

    Quand vous dites permuter, vous ne mettez pas à jour par copie le tableau ?

    https://react.dev/learn/updating-arrays-in-state

    Arrays are mutable in JavaScript, but you should treat them as immutable when you store them in state. Just like with objects, when you want to update an array stored in state, you need to create a new one (or make a copy of an existing one), and then set state to use the new array.
    Votre description n'est pas tout à fait ce que j'ai pu lire en haut.

    Bonne journée.

  5. #5
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    280
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 280
    Par défaut
    Si, je permute comme ça:
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let updatedMealList: Meal[] = [...mealList]
     
    		const temp = updatedMealList[draggedElement.current]
    		updatedMealList[draggedElement.current] = updatedMealList[index]
    		updatedMealList[index] = temp

    Si c'est bien ce dont vous parlez ?

  6. #6
    Membre chevronné
    Homme Profil pro
    Urbaniste
    Inscrit en
    Août 2023
    Messages
    387
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Urbaniste

    Informations forums :
    Inscription : Août 2023
    Messages : 387
    Par défaut
    Bonjour,

    je suppose que c'est suivi d'un setMealList(updatedMealList).

    Du coup là je vois pas trop.

    Si je pouvais le reproduire ici j'y verrais plus clair car dans le code présenté, le seul appel à setMealList est dans la fonction addMeal qui est elle même un écouteur de l'évènement Button.onclick.

    Bonne journée.

Discussions similaires

  1. Drag and drop pour l'API 8 avec Android Support Library
    Par hariman dans le forum Composants graphiques
    Réponses: 0
    Dernier message: 23/10/2012, 12h10
  2. Drag and Drop d'un élément dans un TreePanel
    Par major68 dans le forum Ext JS / Sencha
    Réponses: 0
    Dernier message: 01/03/2011, 10h20
  3. Réponses: 0
    Dernier message: 19/01/2011, 15h04
  4. Réponses: 10
    Dernier message: 27/05/2008, 15h09
  5. Drag and drop pour control en VBA
    Par cbleas dans le forum VBA Access
    Réponses: 2
    Dernier message: 10/03/2007, 10h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo