web-dev-qa-db-fra.com

Passer la fonction javascript comme attribut data- * et exécuter

Nous connaissons les syntaxes ci-dessous, lors de la définition d'un attribut value pour onClick:

<button type="submit" onclick="alert('hi');"></button>
<button type="submit" onclick="doWork"></button> <!-- This one doesn't work -->
<button type="submit" onclick="doWork()"></button>
<button type="submit" onclick="doWork('Mike', 2)"></button>

Ce qui m'intéresse, c'est de définir un data-attribute Personnalisé et d'exécuter la valeur comme suit:

<button type="submit" data-callback="alert('hi');"      class="marker"></button>
<button type="submit" data-callback="doWork"            class="marker"></button>
<button type="submit" data-callback="doWork()"          class="marker"></button>
<button type="submit" data-callback="doWork('Mike', 2)" class="marker"></button>

<script type="text/javascript">
    jQuery("body").on("click","button.marker", function(e) {
        var callback = jQuery(e.currentTarget).data("callback");

        // Now I need to execute the callback no matter of the format
        // 1. Execute as function's body
        // 2. Or by function 'name'
        // 3. Or by function 'name' with 0 parameters
        // 4. Or by function 'name' with n parameters
    })

    function doWork(name, nr){
        var personName = name || "Unnamed";
        var personNr = nr || 0;
        alert("Name is: " + personName + " Nr: " + personNr);
    }
</script>

J'ai collé l'échantillon dans jsBin

Comment accomplir le même comportement en utilisant des attributs de données personnalisés?

22
Cristian E.

Une façon consiste à utiliser eval ()

jQuery(".container").on("click", "button.marker", function (e) {
    var callback = jQuery(e.currentTarget).data("callback");

    var x = eval(callback)
    if (typeof x == 'function') {
        x()
    }
});

Démo: Fiddle

Remarque: assurez-vous qu'il est sûr dans votre environnement, c'est-à-dire qu'il n'y a aucune possibilité d'injection de script en raison d'une mauvaise entrée des utilisateurs

13
Arun P Johny

Je pense qu'une meilleure idée serait de lier dynamiquement les événements et de les déclencher. Si vous souhaitez qu'ils ne soient connus que par un autre code, vous pouvez utiliser des événements personnalisés.

<button type="submit" class="marker marker1"></button>
<button type="submit" class="marker marker2"></button>
<button type="submit" class="marker marker3"></button>
<button type="submit" class="marker marker4"></button>

<script>
    var $markers = $('.marker');
    $markers.filter('.marker1').bind('customCallback', function(){ alert("hi"); });
    $markers.filter('.marker2').bind('customCallback', function(){ doWork(); });
</script>

Vos autres composants pourraient alors les invoquer avec $ (selector) .trigger ('customCallback');

9
Taplar

Simplement avec:

 $("body").on("click","button.marker", function(e) {
     eval($(this).data("callback"));
 })
7
Jeremy Thille

Si vous vouliez vraiment passer des fonctions (avec ou sans paramètres) d'une chose à une autre sans les lier en tant qu'événements, vous pouvez le faire de cette façon (je suis parti de la réponse de @ Taplar)

<button type="submit" class="marker marker1"></button>
<button type="submit" class="marker marker2"></button>
<button type="submit" class="marker marker3"></button>
<button type="submit" class="marker marker4"></button>

<script>
  var $markers = $('.marker');
  $markers.filter('.marker1').get(0).customCallback =  doWork;
  $markers.filter('.marker2').get(0).customCallback = function(){ 
    doWork(arg0,arg1); 
  };
</script>

Ensuite, vous pouvez y accéder dans votre autre composant en tant que:

<script>
  $('.marker').each(function(){
    var  thisFunction = $(this).get(0).customCallback;
    //do something useful with thisFunction
  });
</script>
3

Vous pouvez simplement lier une fonction en tant qu'attribut de données

const ele = $('button');

ele.data('onClick', evt => {
    alert('bye');
})

ele.click(evt => {
    const ele = $(evt.target);
    ele.data('onClick')(evt);
})
2
Mojimi

Une autre façon consiste à utiliser window[func](args).

Similaire à eval(), mais vous devrez stocker le nom de la fonction et l'argument séparément dans l'attribut HTML.

Voici un exemple rapide ... CodePen

<button type="submit" data-func="Angel" data-args='use me instead of evil()' class="marker">TEST</button>

<script type="text/javascript">

    //=== The Listener =====
    $(".marker").on("click",function(){

        // Get the function name and arguments
        let func = $(this).attr("data-func");
        let args = $(this).attr("data-args");

        // Call the function
        window[func](args);
    })


    //=== The Function =====
    function Angel(msg){
        alert(arguments.callee.name + " said : " + msg);
    }
</script>
0
Asuka165