Version imprimable du sujet

Cliquez ici pour voir ce sujet dans son format original

Forums MacBidouille _ Les Langages Du Web _ jQuery : intégration de plugins (dynamiquement)

Écrit par : toluol 12 Nov 2016, 18:32

Bonsoir,

j'ai un problème récurrent lorsque je souhaite intégrer des plugins simples qui doivent à la fois fonctionner lorsque la page se charge, et lorsque, dynamiquement, ma page se recompose en ajax.

Par exemple un color Picker serait appelé ainsi :

Code
$(".monInput").colorpicker({
    parm1: "valeur",
        param2: "valeur",
        param3: "valeur"
});

Mais est-ton obligé de l'intégrer dans une fonction et d'y faire appel à chaque fois qu'on remplace du code html où il y a un "<div class="monInput">" ?

Généralement, quand je crée personnellement des choses, j'utilise la formule...
Code
$("body").on('click','.monInput',function(){
    //mon action ajax...
});

Ce type de code permet d'être toujours valide (au chargement et lorsque les élément sont créés "à la volée").
Peut-on imaginer la même chose avec un plugin ?

Écrit par : No6 13 Nov 2016, 16:48

Whaoo...
J'ai l'impression que tu débute en Javascript...

Déjà, ce que tu considère comme une fonction est de base en JavaScript un objet. ( d'ailleurs en JavaScript tout est Objet, même une simple variable).


ensuite quand tu assigne une fonction ( ex ton "OnClick") cette instanciation ne se fait que sur les objets réellement présents sur la page HTML à ce moment la; ceux qui peuvent arriver par la suite ne seront pas instanciés par cette assignation.

Pour réaliser cette assignation sur des élément non encore existant 2 solutions:
- soit la faire 1 fois sur un élément parent qui reste toujours présent en lui indiquant la sous classe des éléments à considérer
- soit faire cette assignation après l'appel Ajax, mais c'est beaucoup plus contraignant.
il faut mieux utiliser les promesses, et ne pas oublier de faire une déassignation si l'élément est effacé de la page HTML, ben oui, JavaScript est un langage asynchrone, c'est ce qui fait sa force !

Et ne pas oublier non plus les problèmes de Hoisting

aller ; des tuto d'explication (indispensables à connaître) :
1-> https://www.grafikart.fr/formations/debuter-javascript/scope-hoisting
2-> https://www.grafikart.fr/tutoriels/jquery/jquery-on-events-518

quand à passer par les promesses, ( https://api.jquery.com/deferred.promise/ ) c'est un peu plus compliqué à mettre en œuvre,, et selon les as on peut s'en tirer autrement...

Écrit par : toluol 13 Nov 2016, 18:09

En JS (enfin... plutôt jquery), je suis un débutant depuis 5 ans, oui... ^^ Mais on apprend toujours! tongue.gif (Et en apprenant sur le web, je dois dire qu'on ne commence pas toujours par les bons cours, les bons tutos)

Je sais bien ce qu'est un objet et une fonction. Je suis passé par de l'actionscript à un moment ou encore la création de classes en php... Je me suis sans doute mal exprimé.
Ta première solution (cibler un parent) est bien ce que je fais avec mon onClick $("body").on('click','.monInput' et celui-ci marche bien qu'on crée ou qu'efface les instances.

Par contre, je ne vois pas comment appliquer ce principe à un plugin... (sans devoir le rappeler à chaque fois)

Merci pour tes explications et tes liens. Je vais les regarder attentivement. Je connais Grafikart... Ils ont de bonnes explications. smile.gif

Écrit par : No6 13 Nov 2016, 18:47

Ah oui, j'avais pas compris ta question.
Assigner un pluggin jQuery à un élément non présent....
ce qui revient à demander à jQuery de reprogrammer le navigateur web pour qu'il ajoute systématiquement des propriétés (fonctionnelles) à une classe d'éléments non encore présent....

Franchement je trouve pas cela très logique ou possible, mais bon, je me trompe peut-être, et moi aussi j'en apprends tous les jours...

Ce genre de chose est traité différemment dans les framesworks tels que AngularJs, ReactJs ou VueJS. Ills ont tous une sorte de gestionnaire d' évènements qui s'occupe de faire ces assignations au fur et à mesure des changements sur la page, ce qui forcement n'est pas toujours super rapide pour les gros sites, et même les petits car il il y a toute la machinerie du framework qui tourne....

Écrit par : Jaypee 13 Nov 2016, 21:08

C'est vrai qu'il est difficile de trouver un bon cours structuré de Javascript "moderne", je mets des guillemets car n'étant pas très vieux, on a du mal à parler de style classique ou de style moderne...

J'en ai suivi un sur SafariOnlineBooks.com auquel j'ai accès dans ma boîte. Le contenu tournait autour de la notion de privé/public, d'interface, qui aujourd'hui conditionne la programmation et l'usage des frameworks cités. Namespace et Module sont les notions importantes.

Je cite à tout hasard cette référence: https://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript

C'est un point de départ possible.

J-P

Écrit par : No6 8 Aug 2017, 00:56

petit déterrage, mais j'ai la solution !
tongue.gif

En fait, ce que tu veux faire est prévu dans jQuery ...

pour assigner une fonction "fct_x" à un élément id="theone", faut juste l'assigner dans le on("click ...
exemple :

Code
var fonc1 = function () {
      ....
      };
$("button#theone").on("click", fonc1);


tu peux aussi la dés-assigner
Code
$("#theone").off();


moins documenté, mais utile, si on a besoin de passer l'event:
Code
      var fonc2 = function (e) {
        e.stopPropagation();
....
      };
$("button#theone").on("click", {}, fonc2);


Le code complet de mes propres tests:
CODE
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>test affectation button</title>
<style>
button {
margin: 5px;
}
button#theone {
color: red;
background: yellow;
}
div {
border: 1px solid blue;
display: block;
width: 500px;
height: 50px;
padding: 10px;
}
</style>
</head>
<body>
<div id="GDIV">
<button id="theone">rien...</button>
<button id="fct_x">clear</button>
<button id="fct_0">no fct</button>
<button id="fct_1">fct_1</button>
<button id="fct_2">fct_2</button>
</div>
<div id="traceur">...!</div>
<div id="traceur2">...!</div>

<!-- <script src="jquery-3.2.1.min.js"></script> -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
var call_nb = 0;
var fonc1 = function () {
$("div#traceur").text("fonc1");
};

var fonc2 = function (e) {
$("div#traceur").text("fonc2");
e.stopPropagation();
};

$("#GDIV").on("click", function () {
call_nb++;
$("div#traceur2").text(call_nb);
});

$("#fct_x").on("click", function (e) {
$("div#traceur").text("...!");
e.stopPropagation();
});

$("#fct_0").on("click", function (e) {
$("div#traceur").text("no fct");
$("#theone").off();
$("#theone").text("rien");
$("body").off("click", "button#theone");
});

$("#fct_1").on("click", function () {
$("#theone").text("=> F1");
$("button#theone").on("click", fonc1);
});

$("#fct_2").on("click", function () {
$("#theone").text("=> F2");
$("button#theone").on("click", {}, fonc2);
});
});
</script>
</body>
</html>

Écrit par : toluol 23 Dec 2017, 21:22

Je te remercie beaucoup pour ta peine No6. Je redécouvre ce post quelques mois plus tard (après un petit éloignement de la plate-forme macbidouille rolleyes.gif )
Malheureusement, j'ai dû mal m'expliquer car je connais bien ce que tu me montres. Je l'utilise tout le temps. Mon problème est différent.

Je vais réexpliquer d'une autre façon... Tout d'abord essaie ce code parfaitement fonctionnel :

Code
<!doctype html>
<html lang="fr">
<head>
    <title>Colorpicker</title>  
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-colorpicker/2.5.1/css/bootstrap-colorpicker.min.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"></script>  
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-colorpicker/2.5.1/js/bootstrap-colorpicker.min.js"></script>  

    <style>
        h4{margin-top:50px;}
        .form-control{margin-bottom:10px;}
    </style>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-xs-12">
                <h4>Au chargement de la page</h4>
                <input class="form-control" type="text" id="colorpicker" value="#93bdab" style="background-color:#93bdab"/>
                <h4>A la volée</h4>
                <button id="add" type="button" class="btn btn-sm btn-outline-secondary">Ajouter des champs</button>
            </div>
        </div>
    </div>

    <script>
        $('#colorpicker').colorpicker().on('changeColor', function(e){
            $(this).css({'backgroundColor':e.color.toHex()});
        });
        var i=0;
        $('body').on('click','#add', function(e){
            $(this).before('<input class="form-control" type="text" id="colorpicker'+i+'" value="#93bdab" style="background-color:#93bdab"/>');
            $('#colorpicker'+i).colorpicker().on('changeColor', function(e){
                $(this).css({'backgroundColor':e.color.toHex()});
            });
            i++;
        });
    </script>
</body>
</html>


En regardant maintenant le code :
Le truc que je n'aime pas du tout, c'est qu'une même fonction est écrite et appelée plusieurs fois.
Et en plus, depuis cet essai, je n'arrive même plus à me passer du id pour faire fonctionner ce plugin et suis obliger d'incrémenter une valeur (i).

Idéalement, je souhaiterais pouvoir appliquer un plugin sur une classe (par ex. mycolorpicker):
Code
<input class="form-control" type="text" class="mycolorpicker" />

Puis, le faire fonctionner ainsi:
Code
$('body').on('click','.mycolorpicker', function(e){
    var input = $(this);
    input.colorpicker().on('changeColor', function(e){
        $(this).css({'backgroundColor':e.color.toHex()});
    });
});

...pour pouvoir ajouter mes input.mycolorpicker sans me soucier de redéclarer la fonction à chaque fois. Hélas, cette technique ne fonctionne pas.
(Et j'ai ce même problème pour tous les plugins...)

Revoici le code qui ne fonctionne pas:
Code
<!doctype html>
<html lang="fr">
<head>
    <title>Colorpicker</title>  
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-colorpicker/2.5.1/css/bootstrap-colorpicker.min.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"></script>  
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-colorpicker/2.5.1/js/bootstrap-colorpicker.min.js"></script>  

    <style>
        h4{margin-top:50px;}
        .form-control{margin-bottom:10px;}
    </style>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-xs-12">
                <h4>A la volée</h4>
                <button id="add" type="button" class="btn btn-sm btn-outline-secondary">Ajouter des champs</button>
            </div>
        </div>
    </div>

    <script>
$('body').on('click','.mycolorpicker', function(e){
    var input = $(this);
    input.colorpicker().on('changeColor', function(e){
        $(this).css({'backgroundColor':e.color.toHex()});
    });
});
        
        $('body').on('click','#add', function(e){
            $(this).before('<input class="form-control" type="text" class="mycolorpicker"/>');
        });
    </script>
</body>
</html>




Écrit par : No6 24 Dec 2017, 01:54

Oki, cette fois, je pense avoir compris.... ohmy.gif laugh.gif

Mais...
dans ton exemple c'est le pluggin qui décide des evt à connecter l'élément auquel il est affecté.
Et il ne peut être affecté que sur un élément déjà présent sur la page html.

En gros, il est pas prévu pour l'usage que tu souhaite : une affectation de manière dynamique.

Soit tu le réécrit à ta sauce, en récupérant les sources par exemple, mais c'est un coton à coder, en tout cas pour moi.

Pour le type d'usage que tu souhaite, à titre perso, je laisserai un div caché dans un coin avec le color picker dedans, puis je le mettrai au premier plan sur la page en le positionnant à coté d'une de tes zone d'input-color.

Quelque chose du genre :

Code
$(document).on('click focus', '.ClassColorsPickers', function () {
    var elem = this;
    moveColorPickerTo($(this).position());
    theColorPicker.show().on('changeColor', function (e) {
    $(elem).css({
        'backgroundColor': e.color.toHex()
    }).hide();
});


bien sur il faut écrire les fonctions moveColorPickerTo et les suivantes...

PS : pour que ton colorPickerBootstrap soit afficher il faut lui mettre l'option { inline: true, ...} et sans doute d'autres trucs en plus.

Point de vue mémoire ce serait plus propre que le code que tu met en exemple, car celui ci multiplie les colorspicker


====

en fouillant un peu sur le site : https://farbelous.github.io/bootstrap-colorpicker/v2/

ce que je te propose est déjà plus ou moins prévu : avec les commandes (en version :
.colorpicker('show') --> Show the color picker
.colorpicker('hide') --> Hide the color picker
.colorpicker('reposition') --> Updates the color picker's position relative to the element

sinon en version 3
c'est par la https://farbelous.github.io/bootstrap-colorpicker/Colorpicker.html#show (enfin peut-être car j'ai survolé le texte)

Écrit par : toluol 27 Dec 2017, 23:16

Ok, je vois, oui !

Merci pour tes éclaircissements. J'imaginais bien que ces plugins n'avaient pas été conçu dans cet usage.
Le coup de mettre le plugin dans un coin et de l'afficher au besoin, ce n'est pas bête. Je n'y avais jamais songé.
Bon, cela marche pour le colopicker... Mais pas pour un plugin plus complexe comme ckeditor, par exemple.

En tout cas, j'essaierai ta solution pour les plugins "légers" ! Merci encore.

Propulsé par Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)