web-dev-qa-db-fra.com

Fond modal de bootstrap restant

J'affiche une fenêtre modale Bootstrap à charger lors de l'exécution d'appels AJAX. Je diffuse un événement "progress.init" auquel le modal de chargement doit s'afficher et un "progress.finish" lorsque je souhaite masquer le modal. Il existe certaines conditions dans lesquelles le modal est masqué très rapidement après avoir été affiché, ce qui fait que le fond modal reste à l'écran. Les appels suivants pour masquer l'élément ne suppriment pas la toile de fond. Je ne peux pas non plus simplement supprimer tous les arrière-plans, car d'autres fenêtres modales pourraient s'afficher par-dessus la fenêtre de chargement. J'ai mis en place un jsfiddle démontrant le problème en appelant simplement la fonction modale (au lieu de déclencher des événements).

var loadingModal = $("#loadingModal");

$("#btnShow").click(function () {
   loadingModal.modal("show");
    //hide after 3 seconds
    setTimeout(function () {
        loadingModal.modal("hide");
    }, 3000);
});

$("#btnProblem").click(function () {
   //simulate a loading screen finishing fast, followed by another loading screen
    loadingModal.modal("show");
    loadingModal.modal("hide");
    loadingModal.modal("show");

    //Again simulate 3 seconds
    setTimeout(function () {
        loadingModal.modal("hide");
    }, 3000);
});

Et le HTML:

<div id="loadingModal" class="modal fade">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-body">
        <p>Loading...</p>
      </div>
    </div>
  </div>
</div>
<button id="btnShow">Show Loading</button>
<button id="btnProblem">Cause show/hide problem</button>

Idéalement, j'aimerais résoudre ce problème sans attendre une heure précise avant d'appeler modal ("masquer"). En d'autres termes, je veux essayer d'éviter quelque chose comme:

elem.on("progress.finish", function () {
    window.setTimeout(loadingModal.modal("hide");
}, 750);

J'ai également essayé de m'abonner aux événements hidden.bs.modal et shown.bs.modal à partir du bootstrap pour essayer de montrer/cacher l'élément s'il le faut, mais peut-être s'y tromper ... Des idées pour permettre cela modal à afficher/masquer?

30
Patrick

Juste au cas où quelqu'un d’autre se heurterait à un problème similaire: j’ai trouvé que retirer la classe du fondu modal empêcherait ce fond de coller à l’écran, même après que le modal soit caché. Il semble s'agir d'un bogue dans le fichier bootstrap.js pour les modaux.

Une autre solution (tout en conservant les effets de fondu) consisterait à remplacer l’appel de jQueryElement.modal par votre propre javascript personnalisé qui ajoute la classe "in", définit display: block et ajoute un fond lors de l’affichage, puis effectuer les opérations vous voulez cacher le modal.

Supprimer simplement le fondu était suffisant pour mon projet.

45
Patrick

Si après le masquage modal, l'arrière-plan estompé est conservé et ne vous permet pas de cliquer à un endroit où vous pouvez le supprimer de force en utilisant le code ci-dessous.

masquez d'abord votre élément div modal.

$('modalId').modal('hide');

deuxièmement, supprimez la classe 'modal-open' du corps et '.modal-backdrop' à la fin de la page.

$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
29
Gampesh

Juste au cas où quelqu'un d’autre se heurterait à un problème similaire: j’ai gardé le fondu, mais j’ai simplement ajouté data-dismiss="modal" au bouton de sauvegarde. Travaille pour moi.

25
user2443343

Le problème est que bootstrap supprime la toile de fond de manière asynchrone. Ainsi, lorsque vous appelez hide et show rapidement l'un après l'autre, le fond n'est pas supprimé.

La solution (comme vous l'avez mentionné) consiste à attendre que le modal soit complètement masqué, à l'aide de l'événement 'hidden.bs.modal'. Utilisez jQuery one pour effectuer le rappel une seule fois. J'ai ajouté votre jsfiddle pour montrer comment cela fonctionnerait. 

// wait for the backdrop to be removed nicely.
loadingModal.one('hidden.bs.modal', function()
{
    loadingModal.modal("show");

    //Again simulate 3 seconds
    setTimeout(function () {
        loadingModal.modal("hide");
    }, 3000);
});
// hide for the first time, after binding to the hidden event.
loadingModal.modal("hide");

En parcourant le code dans Bootstrap:

C'est ce qui rend caché le modal asynchrone :

$.support.transition && this.$element.hasClass('fade') ?
    this.$element
        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
    this.hideModal()

Ceci vérifie si les transitions sont prises en charge et si la classe fade est incluse dans le modal. Lorsque les deux sont true, il attend la fin de l'effet de fondu avant de masquer le modal. Cette attente se reproduit avant enlève le fond .

C’est pourquoi la suppression de la classe de fondu rendra le masquage du mode modal synchrone (plus besoin d’attendre la fin de l’effet de fondu CSS) et pourquoi la solution par reznic fonctionne.

Cette vérification détermine s'il faut ajouter ou supprimer le fond. isShown = true est exécuté de manière synchrone . Lorsque vous appelez hide et show rapidement l'un après l'autre, isShown devient true et le contrôle ajoute un fond, au lieu de supprimer le précédent, créant ainsi le problème que vous rencontrez.

22
JibstaMan

La solution consiste à masquer entièrement le fond si vous n'en avez pas besoin:

<div class="modal fade preview-modal" data-backdrop="" id="preview-modal"  role="dialog" aria-labelledby="preview-modal" aria-hidden="true">
11
DIG

Après avoir inspecté l'élément, il reste la div avec la classe modal-backdrop après avoir cliqué sur le bouton retour du navigateur. Je l'ai donc simplement supprimé:

$(window).on('popstate', function() {
    $(".modal-backdrop").remove();
});
3
leona

supprimez simplement la classe 'fade' de modal

2
reznic

C'est ce qui a fonctionné pour moi - 

Lorsque l'événement hidden.bs.modal est déclenché, la fonction .remove() de jQuery peut supprimer l'élément ayant la classe .modal-backdrop. Ainsi, chaque fois que le modal est fermé, le modal-backdrop sera sera supprimé .

//setting callback function for 'hidden.bs.modal' event
$('#modal').on('hidden.bs.modal', function(){
  //remove the backdrop
  $('.modal-backdrop').remove();
})

Bonne chance.

2
Akash

Un autre cas possible (le mien) - vous ajoutez le code HTML modal dynamiquement à DOM et il contient davantage le nœud racine 1. Les nœuds de commentaires comptent aussi, donc si vous avez copié le modèle à partir du site de démarrage, vous les avez.

2
Ivan Koshelev

Utilisez ce code pour supprimer complètement modal:

 $('.modal').remove();
 $('.modal-backdrop').remove();
 $('body').removeClass( "modal-open" );
1

L'approche la meilleure et la plus simple consiste à utiliser l'attribut data-dismiss. Fondamentalement, l'attribut data-dismiss rejettera le modal et vous ne verrez pas le fond restant.

Comment utiliser l'attribut data-ignore

Tout ce que vous avez à faire est d’ajouter ce qui suit à l’endroit où vous voulez fermer votre modal:

data-dismiss="modal" 

Par exemple, j'ai un bouton et lorsque quelqu'un clique sur le bouton, il ferme le modal.

<button class="btn btn-info float-right" onclick="foo()" data-dismiss="modal">Save changes</button>

Vous pouvez également gérer la fonction JavaScript sur onClick. Il ferme le modal et exécute également la fonction JavaScript.

C'est la meilleure approche à utiliser avec l'attribut data-dismiss.

1
amitsin6h

Ajoute ça:
$ (". modal-backdrop"). hide (); 
à la fonction ng-click dans le contrôleur pour empêcher le fondu en fondu de rester.

1
Raj

Soyez prudent en ajoutant {Data-licencié = "modal"} Comme mentionné dans la deuxième réponse. Lorsque vous utilisez Angulars ng-commit à l'aide d'une fonction définie par le contrôleur, les données ignorées sont d'abord exécutées et la fonction définie par le contrôleur n'est jamais appelée. Je passe une heure à comprendre cela.

0
Oliver S.

Un problème que je rencontrais (pouvait aider quelqu'un) était simplement que j'utilisais un partiel pour charger le Modal. 

<li data-toggle="modal" data-target="#priceInfoModal">
<label>Listing Price</label>
<i class="fa fa-money"></i>
@Html.Partial("EditPartials/PriceInfo_Edit")
</li>

J'avais placé l'appel partiel à l'intérieur du même élément de liste Donc, data-target = "# priceInfoModal" et div id = "priceInfoModal" Étaient dans le même conteneur, ce qui m'a empêché de fermer le port modal.

0
sam80e

Donc, si vous ne voulez pas supprimer le fondu ou le bricolage avec les objets dom, vous devez simplement attendre que le spectacle soit terminé:

$('#load-modal').on('shown.bs.modal', function () {
    console.log('Shown Modal Backdrop');
    $('#load-modal').addClass('shown');
});

function HideLoader() {
    var loadmodalhidetimer = setInterval(function () {
        if ($('#load-modal').is('.shown')) {                
            $('#load-modal').removeClass('shown').modal('hide');
            clearInterval(loadmodalhidetimer);
            console.log('HideLoader');
        }
        else { //this is just for show.
            console.log('Waiting to Hide');
        }
    }, 200);
}

IMO Bootstrap devrait déjà le faire. Peut-être un peu plus, s'il est possible que vous appeliez hide sans avoir terminé show, vous voudrez peut-être en ajouter un peu à show.bs.modal, ajoutez la classe 'projection' et assurez-vous que le timer le destiné avant d'entrer dans la boucle. Assurez-vous de bien "montrer" au point indiqué.

0
Tod