38 votes

jQuery drag and drop - vérification d'un dépôt en dehors d'un droppable

Je m'excuse si cette question a déjà été traitée dans une autre question, je n'ai pas trouvé de réponse spécifique à mon problème !

J'essaie de tester si un draggable jQuery est déposé en dehors d'un droppable légal. Ce problème serait normalement résolu dans 90 % des cas en inversant le draggable, mais je ne veux pas le faire. Au lieu de cela, je veux faire une chose si le draggable est déposé sur un droppable (ce qui fonctionne très bien !), et autre chose s'il est déposé en dehors de tous les droppables possibles (ce qui me perturbe actuellement !).

En un mot :

jQuery('#droppable').droppable(
{
    accept: '#draggable',
    drop: function(event, ui)
    {
        // awesome code that works and handles successful drops...
    }
});

jQuery('#draggable').draggable(
{
    revert: false,
    stop: function()
    {
        // need some way to check to see if this draggable has been dropped
        // successfully or not on an appropriate droppable...
        // I wish I could comment out my headache here like this too...
    }
});

J'ai l'impression de rater quelque chose de vraiment évident... Merci d'avance pour toute aide !

57voto

Luke Girvin Points 8270

Étant donné que l'événement de dépôt du droppable se déclenche avant l'événement d'arrêt du draggable, je pense que vous pouvez définir un indicateur sur l'élément qui est traîné dans l'événement de dépôt comme suit :

jQuery('#droppable').droppable(
{
    accept: '#draggable',
    drop: function(event, ui)
    {
        ui.helper.data('dropped', true);
        // awesome code that works and handles successful drops...
    }
});

jQuery('#draggable').draggable(
{
    revert: false,
    start: function(event, ui) {
        ui.helper.data('dropped', false);
    },
    stop: function(event, ui)
    {
        alert('stop: dropped=' + ui.helper.data('dropped'));
        // Check value of ui.helper.data('dropped') and handle accordingly...
    }
});

3 votes

Une solution très cool Luke, merci pour cela... ça a marché comme sur des roulettes !

0 votes

Incroyable mais : Y a-t-il de la documentation sur les .data ? Pour moi, c'est une sorte de descente du ciel :3 (lire : je n'ai pas pu trouver plus d'informations).

4 votes

Il ne faut pas ui.draggable.data('dropped', true); (ligne 6) est en fait ui.helper.data('dropped', true); ?

9voto

Polmonite Points 478

Je vois que vous avez déjà obtenu une réponse ; de toute façon, j'ai eu ce même problème aujourd'hui et je l'ai résolu de cette façon :

var outside = 0;

// this one control if the draggable is outside the droppable area
$('#droppable').droppable({
    accept      : '.draggable',
    out         : function(){
        outside = 1;
    },
    over        : function(){
        outside = 0;
    }
});

// this one control if the draggable is dropped
$('body').droppable({
    accept      : '.draggable',
    drop        : function(event, ui){
        if(outside == 1){
            alert('Dropped outside!');
        }else{
            alert('Dropped inside!');
        }
    }
});

J'en avais besoin parce que je ne pouvais pas modifier les options de mes draggables, et que je devais donc travailler uniquement avec des droppables (j'en avais besoin à l'intérieur de l'incroyable Calendrier complet plugin). Je suppose qu'il pourrait avoir quelques problèmes en utilisant l'option "gourmande" des droppables, mais cela devrait fonctionner dans la plupart des cas.

PS : désolé pour mon mauvais anglais.

EDIT : Comme suggéré, j'ai créé la version en utilisant le jQuery.data ; il peut être trouvé ici : jsfiddle.net/Polmonite/WZma9/

De toute façon la documentation de jQuery.data dit :

Notez que cette méthode n'offre pas actuellement de prise en charge multiplateforme pour la définition de données sur les documents XML, car Internet Explorer ne permet pas de joindre des données via les propriétés expando.

(ce qui signifie qu'il ne fonctionne pas sur les IE antérieurs à 8)

EDIT 2 : Comme l'a noté @Darin Peterson , le code précédent ne fonctionne pas avec plus d'une zone de dépôt ; ceci devrait résoudre ce problème : http://jsfiddle.net/Polmonite/XJCmM/

EDIT 3 : L'exemple de l'EDIT 2 a un bug. Si je fais glisser "Traîne-moi !" vers le droppable du bas, puis que je dépose "Traîne-moi aussi" vers le droppable du haut, puis que je dépose "Traîne-moi aussi" à l'extérieur, le message "Déposé à l'intérieur !" s'affiche. Donc, ne l'utilisez pas.

EDIT 4 : Comme l'a noté @Aleksey Gor, l'exemple de l'édition 2 était erroné ; en fait, il s'agissait plutôt d'un exemple pour expliquer comment boucler tous les draggables/droppables, mais j'ai en fait oublié de supprimer les messages d'alerte, donc c'était assez confus. Ici le violon actualisé.

0 votes

Sympa et simple ! C'est une bonne solution, surtout quand on n'a pas accès aux draggables. Je me demandais, en pensant maintenant à d'éventuels problèmes de portée, si vous pouviez utiliser l'élément $("#droppable").data("outside", true); pour "transporter" l'état de la variable de manière plus élégante ? Belle solution cependant ! Merci pour votre contribution ! :)

1 votes

Bien sûr. J'ai ajouté la version utilisant jQuery.data à la réponse ;) De toute façon, cela signifie qu'il n'y a pas d'IE7 (au cas où quelqu'un s'en soucie).

0 votes

Brillant ! Merci pour la recherche et la réponse élargie ! +1

4voto

ggzone Points 1246

Essayez d'utiliser l'événement "out" d'un tombable élément.

C'est le documentation

"Cet événement est déclenché lorsqu'un draggable accepté est glissé hors (dans la tolérance de) ce droppable." Si je ne me trompe pas, c'est ce dont vous avez besoin.

Il est également possible de créer une superposition d'éléments sur l'ensemble de la page. Si l'élément est déposé à cet endroit, vous déclenchez votre événement. Ce n'est pas la meilleure solution, mais je pense que c'est la seule façon de procéder. Parce que vous avez besoin d'un autre élément "déposable" pour déclencher ces événements.

0 votes

Hey ggzone, merci pour la réponse rapide... Ce serait parfait si le draggable que je faisais glisser sortait d'un droppable valide. Si un objet à glisser était tiré de sa position d'origine puis déposé quelque part au hasard loin d'un objet à déposer légal, cet événement ne serait jamais déclenché, pour autant que je sache !

0 votes

Génial, merci ggzone... comme tu l'as dit, ce n'est probablement pas la meilleure, et si tu n'as pas encore vu la réponse fournie par Luke, je pense qu'elle offre une solution beaucoup plus élégante avec les mêmes résultats !

1voto

Bogmag Points 23

L'avantage de l'exemple suivant, c'est que vous n'avez pas besoin de modifier ou de connaître le code à déposer :

La propriété de retour en arrière du dragueur peut avoir une fonction(valeur){}. Une valeur est passée en argument, indiquant si l'aide a été déposée sur un élément (l'élément de dépôt), ou 'false' si elle n'a pas été déposée sur un élément (dépôt en dehors ou non accepté).

Note : vous devez retourner la valeur bool correcte de la fonction revert-fonction, afin d'indiquer à l'aide de réverser ou non (true/false). (vrai/faux). True signifie oui, ramène l'aide à sa position initiale position initiale, en le déplaçant vers l'arrière au ralenti (out-of-the-box). Faux signifie non, il suffit de retirer l'aide brusquement. Donner à la propriété revert la valeur "invalide", est un raccourci pour dire

  • oui, si elle est déposée à l'extérieur, alors l'aide est réorientée'.
  • non, si elle est déposée sur un élément largable et qu'elle est acceptée, alors elle tue l'aide immédiatement.

À mon avis, vous pouvez ajouter l'aide d'interface actuelle au conteneur draggable avec la propriété data pendant l'événement de démarrage. Puis le récupérer dans la fonction revert à partir de la propriété data. Ensuite, ajoutez une propriété à l'aide, indiquant si elle a été déposée ou non. Enfin, dans l'événement d'arrêt, vérifiez la valeur de cette propriété de données, et faites ce que vous vouliez.

Ordre d'appel des événements/fonctions pour le draggable : start-revert-stop

Cela pourrait être un exemple :

jQuery('#draggable').draggable(
{
    start: function(event, ui) {
        $(this).data('uihelper', ui.helper);
    },
    revert: function(value){
        var uiHelper = (this).data('uihelper');
        uiHelper.data('dropped', value !== false);
        if(value === false){
             return true;
        }
        return false;
    },
    stop: function(event, ui)
    {
        if(ui.helper.data('dropped') === true){
            // handle accordingly...
        }
    }
});

Vous pouvez même renvoyer true dans la fonction revert, et simplement supprimer l'aide pendant l'événement stop à la place, en fonction de la valeur data('dropped') avec ui.helper.remove(). Ou vous pouvez même l'exploser avec CSS3 si vous avez encore une mauvaise journée ;)

0voto

coorasse Points 149

J'ajoute la solution que j'ai adoptée puisque vous pouvez comprendre cela très facilement à partir des classes css de l'objet que vous déplacez :

jQuery('#draggable').draggable({
  stop: function(event, ui) {
    if (ui.helper.hasClass('ui-draggable-dragging')) {
      console.log('dropped out');
    } else {
      console.log('dropped successfully');
    }
  }
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X