Trucsweb.com

Trucsweb 1997-2017 - 20 ans de partage.

Javascript

Bootstrap

RDFFav

Bootstrap 4 - Fenêtre « modal » adaptative, dynamique et « auto-resize »

De la simple fenêtre modale adaptative en pure CSS à la fenêtre dynamique avec Ajax ou iFrame en passant par la fenêtre modale pleine page au contenu illimité en pure JavaScript Vanille et avec jQuery...ajax,bootstrap,modal,dynamique,iframe,Vanilla,jQuery,Auto-resize

La fenêtre modale est sans aucun doute l’un des IU (Interface usager) les plus simples et les plus utiles. À la différence de la fenêtre PopUp hors DOM (Document Object Model) qu’on peut perdre sous la fenêtre principale, la fenêtre modale beaucoup plus ergonomique et flexible à l’avantage d’être membre du DOM de la page.

Fenêtre modale Bootstrap 4.1.3 avec iFrame

Par contre, la fenêtre modale n’a pas les attributs ni les méthodes de l’objet fenêtre (window), c’est un simple DIV qu’il faut créer et manipuler. C’est pourquoi ce tutoriel utilise comme base le cadriciel Bootstrap (version 4). Voilà la modale Bootstrap de base avec ces dépendances CSS et jQuery :

<!doctype html>
<html lang="fr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <title>Fenêtre modale Bootstrap 4.1.3</title>
  </head>
  <body>
    <h1>Fenêtre modale Bootstrap 4.1.3</h1>
    <button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#oMessagerie">
      Ouvrir la fenêtre modale
    </button>

    <div class="modal fade" id="oMessagerie" tabindex="-1" role="dialog" aria-labelledby="oMessagerieLabel" aria-hidden="true">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="oMessagerieLabel">Titre</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Fermer">
              <span aria-hidden="true">×</span>
            </button>
          </div>
          <div class="modal-body">
            Contenu
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Fermer</button>
          </div>
        </div>
      </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
  </body>
</html>

Outre le fait d’utiliser beaucoup de code, HTML, CSS et de dépendance aux JavaScript tant Bootstrap que jQuery, le problème avec cette fenêtre modale c’est qu’il faut recréer le même code pour chaque fenêtre modale. Du simple message d’erreur à la fenêtre modale des plus complexe. Si c’est excellent pour afficher une invitation de partager de la page d’accueil, c’est complètement absurde pour une application qui demanderait un grand nombre de fenêtres modales. Voilà pourquoi la fenêtre modale devrait toujours être dynamique, c’est-à-dire une seule fenêtre modale utilisée comme conteneur avec un contenu dynamique intégré en JavaScript. Son contenu peut alors être ajouté directement dans le lien qui ouvre la fenêtre modale, dans un iFrame ou mieux, à l’aide d’un appel Ajax. Avec un appel Ajax au serveur, c’est possible d’intégrer un contenu illimité à notre fenêtre modale, à partir d’une base de données par exemple.

Personnellement, j’utilise cette technique pour afficher tous mes messages d’erreur et d’information, simplifiant et surtout normalisant tant l’ergonomie du site que la programmation. Mais aussi pour ajouter une première couche de sécurité aux communications ! Un formulaire dans une fenêtre modale dynamique à l’avantage d’être caché et du coup protégée des nombreux engins capable d’en abuser. En profitant du manque d’intelligence des engins et surtout des abuseurs, la réponse aussi peut être gérée en arrière-plan sans offrir la possibilité aux pourrielleurs à la merci de leur application de capturer l’adresse du formulaire. Bien entendu, il suffit d’un programmeur pour récupérer cette adresse, mais vous serez ainsi protégé de la majorité des abuseurs...

Voyons comment dynamiser cette fenêtre modale à priorité statique.

Dimensions de la fenêtre modale

Avant d’aller plus loin, Bootstrap offre 3 grandeurs de fenêtre modale, la normale comme l’exemple plus haut, la petite avec la classe .modal-sm et la grosse avec la classe .modal-lg. Vous pouvez ajouter la classe .modal-xl toujours compatible mais si c’est de la version 3. Mais n’ajoutez pas ces classes directement dans la fenêtre modale. Utilisez plutôt la fonction « twMessagerie » pour définir le type de fenêtre modale. J’y ajoute d’autres classes pour mes exemples. Vous pouvez créer vos propres classes.

  • .cModalIframeConteneur : Pour intégrer un iFrame ;
  • .cModalPlein : Pour une fenêtre modale plein écran (éviter avec un iFrame) ;
  • .cModalMedium : Pour une grosse fenêtre modale (éviter avec un iFrame) ;
  • .cModalSansEntete : Pour retirer l’entête et le pied (idéale avec un iframe) ;
  • .cModalRouge : Une fenêtre modale avec entête rouge ;
  • .cModalInfo : Une fenêtre modale entièrement bleue.
<style>
.cModalIframeConteneur {
  overflow: hidden;
  padding-top: 56.25%;
  position: relative;
  width: 100%;
}

.cModalIframeConteneur iframe {
   border: 0;
   height: 100%;
   left: 0;
   position: absolute;
   top: 0;
   width: 100%;
}

.cModalPlein {min-width: 100%;margin: 0;}
.cModalPlein .modal-header {-webkit-border-radius: 0px;-moz-border-radius: 0px;border-radius: 0px;}
.cModalPlein .modal-content {min-height: 100vh;border-radius: 0;-moz-border-radius: 0;-webkit-border-radius: 0;}
.cModalPlein .modal-footer {-webkit-border-radius: 0px;-moz-border-radius: 0px;border-radius: 0px;}

.cModalMedium {min-width: 90%;margin: 0 auto;}
.cModalMedium .modal-content {min-height: 80vh;border-radius: 0;-moz-border-radius: 0;-webkit-border-radius: 0;}

.cModalSansEntete .modal-header {display:none;}
.cModalSansEntete .modal-footer {display:none;}

.cModalRouge .modal-header {-webkit-border-radius: 0px;-moz-border-radius: 0px;border-radius: 0px;background-color: #dc3545;color: #ffffff;}
.cModalRouge .modal-footer {-webkit-border-radius: 0px;-moz-border-radius: 0px;border-radius: 0px;background-color: #dc3545;color: #ffffff;}

.cModalInfo .modal-header {background-color: #17a2b8;color: #ffffff;border:none;}
.cModalInfo .modal-body {background-color: #17a2b8;color: #ffffff;}
.cModalInfo .modal-footer {background-color: #17a2b8;color: #ffffff;border:none;}
</style>
Fenêtre modale avec contenu dynamique

Bien que Bootstrap 4 vient avec une base jQuery, le premier exemple est en pur JavaScript dit « vanilla » sans jQuery. Il suffit de spécifier data-toggle="modal" avec la cible de la fenêtre modale, c’est-à-dire son ID data-target="#oMessagerie" pour ouvrir la fenêtre modale conventionnelle. Ajouter la classe « cBoutonModal » pour identifier le bouton et l’attacher à la fonction, plus 4 paramètres :

  • data-titre : Le titre de la fenêtre modale ;
  • data-contenu : Le contenu de la fenêtre modale ;
  • data-src : Le URL d’une page Web. Si spécifier, la fonction intègrera un iFrame ;
  • data-class : Classes supplémentaires.
<button type="button" class="btn btn-primary cBoutonModal"
    data-toggle="modal"
    data-target="#oMessagerie"
    data-titre="Exemple sans iFrame 1"
    data-class="cModalInfo cModalPlein"
    data-contenu="Exemple de contenu 1">
  Test direct 1
</button>

<button type="button" class="btn btn-primary cBoutonModal"
    data-toggle="modal"
    data-target="#oMessagerie"
    data-titre="Exemple sans iFrame 2"
    data-class="cModalRouge modal-lg"
    data-contenu="Exemple de contenu 2">
  Test direct 2
</button>

<button type="button" class="btn btn-primary cBoutonModal"
    data-toggle="modal"
    data-target="#oMessagerie"
    data-titre="Exemple iFrame"
    data-class="cModalRouge modal-xl cModalSansEntete"
    data-contenu="Erreur"
    data-src="http://neural.quebec">
  Test iFrame
</button>

<script>
// Associer la fonction à chaque bouton
let aBoutons = document.querySelectorAll(".cBoutonModal");
aBoutons.forEach(function(elem) {elem.addEventListener("click", function() {twMessagerie("oMessagerie",this);}, false);});
</script>

Et finalement la fonction « twMessagerie »

<script>
function twMessagerie(oModalTemp,_this) {
  // Récupérer la fenêtre modale.
  var oObjet = document.getElementById(oModalTemp);

  // Vider le contenu.
  oObjet.querySelector(".modal-body").innerHTML = "";

  // S’il y a un titre, ajouter le titre à la fenête modale.
  if (_this.hasAttribute("data-titre")) {oObjet.querySelector(".modal-title").innerHTML = _this.getAttribute("data-titre");}

  // S’il y a une ou plusieurs classes, ajouter les classes.
  // Noter que j’utilise la méthode « className » au lieu du nouveau « classList » incompatible IE 10...
  // Et pour éviter de tomber sur une fenêtre avec une vielle classe,
  //   supprimer les classes en s’assurant de gardant « modal-dialog » bien sûr.
  if (_this.hasAttribute("data-class")) {
    oObjet.querySelector(".modal-dialog").className = "modal-dialog "+_this.getAttribute("data-class");
  }else{
    oObjet.querySelector(".modal-dialog").className = "modal-dialog"
  }
  // Si l’attribut « data-src » est présent avec une adresse
  // Ajouter le iFrame
  if (_this.hasAttribute("data-src")&&_this.getAttribute('data-src')!='') {
    // Avec iFrame, intégrer un iFrame et supprimer le « padding ».
    oObjet.querySelector(".modal-body").innerHTML = "<div class='cModalIframeConteneur'><iframe src='"+_this.getAttribute('data-src')+"'></iframe></div>";
    oObjet.querySelector(".modal-body").className = "modal-body p-0";
  } else {
    // Sinon intégrer le contenu et remettre le « padding ».
    oObjet.querySelector(".modal-body").innerHTML = _this.getAttribute('data-contenu');
    oObjet.querySelector(".modal-body").className = "modal-body";
  }
}
</script>

Avec jQuery

Un exemple plus simple mais cette fois avec jQuery et l’événement « onclick ». Mais attention les fonctions Ajax de jQuery ne sont pas disponible avec la version « slim » avec Bootstrap. Vous devez ajouter la librairie jQuery complète AVANT le code :

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#oMessagerie" onclick="twMessagerieJquery2('#oMessagerie','Exemple jQuery','<p>Test JavaScript jQuery</p>','text-white','bg-danger');">Test jQuery</button>

<script>
function twMessagerieJquery2(oModalTemp,oTitreTemp,sCouleurTemp,sCouleurFondTemp) {
  $(oModalTemp).find(".modal-title").html(oTitreTemp);
  $(oModalTemp).find(".modal-title").css("font-weight", "bold"); 
  $(oModalTemp).find(".modal-header").addClass(sCouleurTemp);
  $(oModalTemp).find(".modal-header").addClass(sCouleurFondTemp); 
  $(oModalTemp).find(".modal-body").html('<p><a href="" onclick="twJqueryAjax(event,'modal.txt','#oMessagerie','.modal-body')">Plus de texte</a></p>';);
}

function twJqueryAjax(e,sUrlTemp,sDivTemp,sDivBodyTemp) {
  e.preventDefault();
  $.ajax({url: sUrlTemp, error: function(xhr){
      alert("Une erreur est survenue : " + xhr.status + " " + xhr.statusText);
    }, success: function(result){
      // Ajout du contenu à la suite du texte de la modale.
      $(sDivTemp).find(sDivBodyTemp).html(result+$(sDivTemp).find(sDivBodyTemp).html());
  }});
}
</script>
Contenu dynamique avec Ajax en pure JavaScript (vanilla)

C’est ici que le fun commence, contenu dynamique mais externe c’est encore mieux. Dans mon exemple j’utilise un simple fichier texte avec un paragraphe « Lorem ipsum ». Mais ce pourrait être un script serveur avec une requête SQL par exemple...

Le lien dans le texte pour faire l’appel Ajax :

<a href='modal.txt' data-div='oMessagerie' onclick='twAjax(event,this)'>Plus de texte</a>
Exemple complet Ajax
<!doctype html>
<html lang="fr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <title>Fenêtre modale Bootstrap 4.1.3</title>
    <style>
      .cModalIframeConteneur {
        overflow: hidden;
        padding-top: 56.25%;
        position: relative;
        width: 100%;
      }
      .cModalIframeConteneur iframe {
         border: 0;
         height: 100%;
         left: 0;
         position: absolute;
         top: 0;
         width: 100%;
      }
      .cModalPlein {min-width: 100%;margin: 0;}
      .cModalPlein .modal-header {-webkit-border-radius: 0px;-moz-border-radius: 0px;border-radius: 0px;}
      .cModalPlein .modal-content {min-height: 100vh;border-radius: 0;-moz-border-radius: 0;-webkit-border-radius: 0;}
      .cModalPlein .modal-footer {-webkit-border-radius: 0px;-moz-border-radius: 0px;border-radius: 0px;}
      .cModalMedium {min-width: 90%;margin: 0 auto;}
      .cModalMedium .modal-content {min-height: 80vh;border-radius: 0;-moz-border-radius: 0;-webkit-border-radius: 0;}
      .cModalSansEntete .modal-header {display:none;}
      .cModalSansEntete .modal-footer {display:none;}
      .cModalRouge .modal-header {-webkit-border-radius: 0px;-moz-border-radius: 0px;border-radius: 0px;background-color: #dc3545;color: #ffffff;}
      .cModalRouge .modal-footer {-webkit-border-radius: 0px;-moz-border-radius: 0px;border-radius: 0px;background-color: #dc3545;color: #ffffff;}
      .cModalInfo .modal-header {background-color: #17a2b8;color: #ffffff;border:none;}
      .cModalInfo .modal-body {background-color: #17a2b8;color: #ffffff;}
      .cModalInfo .modal-footer {background-color: #17a2b8;color: #ffffff;border:none;}
    </style>
  </head>
  <body>
    <h1>Fenêtre modale Bootstrap 4.1.3</h1>
    
    <button type="button" class="btn btn-primary cBoutonModal"
        data-toggle="modal"
        data-target="#oMessagerie"
        data-titre="Exemple sans iFrame 1"
        data-class="cModalInfo cModalPlein"
        data-contenu="Exemple de contenu 1">
      Test direct 1
    </button>

    <button type="button" class="btn btn-primary cBoutonModal"
        data-toggle="modal"
        data-target="#oMessagerie"
        data-titre="Exemple sans iFrame 2"
        data-class="cModalRouge modal-lg"
        data-contenu="Exemple de contenu 2">
      Test direct 2
    </button>

    <button type="button" class="btn btn-primary cBoutonModal"
        data-toggle="modal"
        data-target="#oMessagerie"
        data-titre="Exemple iFrame"
        data-class="cModalRouge modal-xl cModalSansEntete"
        data-contenu="Erreur"
        data-src="http://neural.quebec">
      Test iFrame
    </button>

    <button type="button" class="btn btn-primary cBoutonModal"
      data-toggle="modal"
      data-target="#oMessagerie"
      data-titre="Exemple Ajax en JavaScript Vanille"
      data-class="cModalRouge"
      data-contenu="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. <a href='modal.txt' data-div='oMessagerie' onclick='twAjax(event,this)'>Plus de texte</a>">Test Ajax Vanilla</button>

    <div class="modal fade" id="oMessagerie" tabindex="-1" role="dialog" aria-labelledby="oMessagerieLabel" aria-hidden="true">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="oMessagerieLabel">Titre</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Fermer">
              <span aria-hidden="true">×</span>
            </button>
          </div>
          <div class="modal-body">
             Contenu...
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Fermer</button>
          </div>
        </div>
      </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
    <script>
      // Associer la fonction à chaque bouton
      let aBoutons = document.querySelectorAll(".cBoutonModal");
      aBoutons.forEach(function(elem) {elem.addEventListener("click", function() {twMessagerie("oMessagerie",this);}, false);});

      function twMessagerie(oModalTemp,_this) {
        // Récupérer la fenêtre modale.
        var oObjet = document.getElementById(oModalTemp);

        // Vider le contenu.
        oObjet.querySelector(".modal-body").innerHTML = "";

        // S’il y a un titre, ajouter le titre à la fenête modale.
        if (_this.hasAttribute("data-titre")) {oObjet.querySelector(".modal-title").innerHTML = _this.getAttribute("data-titre");}

        // S’il y a une ou plusieurs classes, ajouter les classes.
        // Noter que j’utilise la méthode « className » au lieu du nouveau « classList » incompatible IE 10...
        // Et pour éviter de tomber sur une fenêtre avec une vielle classe,
        //   supprimer les classes en s’assurant de gardant « modal-dialog » bien sûr.
        if (_this.hasAttribute("data-class")) {
          oObjet.querySelector(".modal-dialog").className = "modal-dialog "+_this.getAttribute("data-class");
        }else{
          oObjet.querySelector(".modal-dialog").className = "modal-dialog"
        }
        // Si l’attribut « data-src » est présent avec une adresse
        // Ajouter le iFrame
        if (_this.hasAttribute("data-src")&&_this.getAttribute('data-src')!='') {
          // Avec iFrame, intégrer un iFrame et supprimer le « padding ».
          oObjet.querySelector(".modal-body").innerHTML = "<div class='cModalIframeConteneur'><iframe src='"+_this.getAttribute('data-src')+"'></iframe></div>";
          oObjet.querySelector(".modal-body").className = "modal-body p-0";
        } else {
          // Sinon intégrer le contenu et remettre le « padding ».
          oObjet.querySelector(".modal-body").innerHTML = _this.getAttribute('data-contenu');
          oObjet.querySelector(".modal-body").className = "modal-body";
        }
      }

      function twAjax(e,_this) {
        // empèche le lien de s’éxécuter
        e.preventDefault();

        // Récupère le lien et le nom du DIV
        let sUrlTemp = _this.getAttribute("href");
        let sDivTemp = _this.getAttribute("data-div");

        // Appel Ajax
        var xhr = new XMLHttpRequest();
        // Appelle du lien
        xhr.open("GET", sUrlTemp, true);
        xhr.send();
        console.log("Requête envoyée!");
        xhr.onreadystatechange = function() {
          if (this.readyState === 4) {
            if (this.status === 200){
              console.log("Chargé!");
              // Ajout du contenu au début du texte de la modale.
              var oObjet = document.getElementById(sDivTemp).querySelector(".modal-body");
              oObjet.innerHTML = this.responseText + oObjet.innerHTML;
            } else {
              alert("Une erreur est survenue : " +  this.status + " " + this.statusText);
            }
          } else {
          	console.log("En processus!");
          }
        };
      }
    </script>
  </body>
</html>

, Analyste programmeurConception oznogco multimédia (http://oznogco.com), Trucsweb
Dernière mise à jour :

Commentaires

Ajouter un commentaire
Votre adresse de courriel ne sera pas publiée. * L'astérisque indique les champs obligatoires.
Votre évaluation du tutoriel

10/10 sur 1 revues.
       Visites : 170 - Pages vues : 281
X

Trucsweb.com Connexion

Connexion

X

Trucsweb.com Mot de passe perdu

Connexion

X

Trucsweb.com Conditions générales

Conditions

Responsabilité

La responsabilité des Trucsweb.com ne pourra être engagée en cas de faits indépendants de sa volonté. Les informations mises à disposition sur ce site le sont uniquement à titre purement informatif et ne sauraient constituer en aucun cas un conseil ou une recommandation de quelque nature que ce soit.

Aucun contrôle n'est exercé sur les références et ressources externes, l'utilisateur reconnaît que les Trucsweb.com n'assume aucune responsabilité relative à la mise à disposition de ces ressources, et ne peut être tenue responsable quant à leur contenu.

Droit applicable et juridiction compétente

Les règles en matière de droit, applicables aux contenus et aux transmissions de données sur et autour du site, sont déterminées par la loi canadienne. En cas de litige, n'ayant pu faire l'objet d'un accord à l'amiable, seuls les tribunaux canadien sont compétents.

X

Trucsweb.com Trucsweb

X

Trucsweb.com Glossaire

X

Trucsweb.com Trucsweb

X

Trucsweb.com Trucsweb

Conditions

Aucun message!

Merci.

X
Aucun message!
X

Trucsweb.com Créer un compte

Créer un compte

.
@