Retarder l'appel ajax sur le champ de texte pour permettre la saisie

8

Je voudrais retarder ajax de se déclencher de la même manière que la saisie semi-automatique semble fonctionner. Par exemple, si un utilisateur tape, l'ajax ne fonctionnera pas avant que 500 ms ne se soient écoulées depuis la dernière frappe.

Je regarde actuellement les comportements de drupal.be mais je ne suis pas en mesure de le faire fonctionner.

Drupal.behaviors.mymodule = {
  attach: function(context, settings) { 
    $('input.andtimer', context).delay(500).ajaxStart();
  }
};

Il s'agit de l'élément de formulaire auquel le comportement est attaché.

$form['my_input'] = array(
  '#type' => 'textfield',
  '#default_value' => $value,
  '#ajax' => array(
    'callback' => 'my_callback',        
    'event' => 'keyup',
    'wrapper' => 'my_wrapper',  
    'trigger_as' => array(
      'name' =>  'my_button',
  ),
  'progress' => array('type' => 'none'),
  ),
  '#attributes' => array(
    'class' => array('andtimer'),
  ),                      
);

Ce jsfiddle montre ce que j'essaie de réaliser.

Est-ce que comment remplacer Drupal.ajax.prototype.beforeSend? être un moyen de le faire?

Ce qui suit fonctionne pour le premier «ensemble» d'entrées avec la classe .andtimer. Il ne fonctionne pour aucun autre ensemble, l'ajax continue toujours avec le premier ensemble. Une idée sur comment réparer ça?

(function($, Drupal) {
    Drupal.behaviors.bform = {
        attach : function(context, settings) {

            var events = $('.andtimer').clone(true).data('events');
            $('.andtimer').unbind('keyup');
            var typingTimer;
            var doneTypingInterval = 300;
            $('.andtimer').keyup(function() {
                clearTimeout(typingTimer);
                typingTimer = setTimeout(doneTyping, doneTypingInterval);
                function doneTyping() {
                    $.each(events.keyup, function() {
                        this.handler();
                    });
                }

                return false;
            });
        }
    };
})(jQuery, Drupal); 

Utiliser $ form ['my_input'] ['# ajax'] ['event'] = 'finishinput' comme suggéré et

var typingTimer;
var doneTypingInterval = 600;

$('.andtimer').on('keyup', function (e) {
  clearTimeout(typingTimer);
  if ($(this).val) {
    var trigid = $(this);
    typingTimer = setTimeout(function(){                    
      trigid.triggerHandler('finishedinput');
    }, doneTypingInterval);
  }
});

Fonctionne pour chaque «groupe» d'entrées où le nombre d'entrées remplies doit être obtenu.

Inigo Montoya
la source
Ce code n'a rien à voir avec keyup / keydown ou la liaison d'événement à laquelle vous faites allusion - pouvez-vous ajouter votre code réel s'il vous plaît? Gardez à l'esprit que si vous cherchez simplement de l'aide générale sur javascript, ce n'est pas l'endroit idéal pour le trouver. La règle est la suivante: faites-le d'abord fonctionner à l'extérieur de Drupal, et si vous ne pouvez pas le faire fonctionner à l' intérieur de Drupal, demandez ici
Clive
Merci Clive, j'ai ajouté le code pour construire l'entrée. Je suis allé directement pour l'essayer et le faire fonctionner dans Drupal. Encore à apprendre. Je vais faire un tour dehors et voir si je ne peux pas clarifier un peu plus le problème dans ma tête.
Inigo Montoya
J'ai parlé trop tôt, je ne savais pas à quel point tu es lié à Drupal. Cela pose un problème assez intéressant :)
Clive
1
L'extrait de code inférieur fonctionne bien pour moi, sauf qu'après le déclenchement de l'événement, le champ perd le focus. Comment puis-je faire pour que l'accent reste sur l'élément après le tir.
VanD

Réponses:

7

Une option consiste à utiliser un événement jQuery personnalisé, par exemple. quelque chose comme entrée terminée . Définissez $form['my_input']['#ajax']['event'] = 'finishedinput'et fournissez du JS pour déclencher votre événement personnalisé après un délai approprié (similaire au JS du violon).

Andy
la source
Incroyable ! Je cherchais exactement ça :) Merci beaucoup. Cependant, si je pouvais avoir une astuce sur la façon de l'appliquer lorsque vous modifiez une entrée d'un formulaire exposé de vues. Si je ne mets pas le rappel sur $ form ['my_input'] ['# ajax'] rien ne se passe, si j'ajoute les vues de soumission exposées du formulaire submit fn en tant que rappel (ou autre), cela fonctionne mais retourne un index non défini: form_build_id. .. Et je ne sais ni comment ni où ajouter un $ form_state ['rebuild'] = TRUE Merci d'avance
Kojo
1
@Kojo Pourriez-vous poser une nouvelle question à ce sujet et inclure des descriptions des paramètres Views AJAX, du filtre exposé, de tout code personnalisé que vous utilisez et des problèmes qui se produisent? La soumission automatique de Btw CTools a déjà un délai (codé en dur) lors de la soumission à partir de champs de texte de 0,5 s ( voir auto-submit.js ).
Andy
Ah super, voici le décor! N'est-il pas possible de le modifier "à la volée" pour une entrée spécifique? Si ce n'est pas simple, je posterai une question :) Merci pour votre aide!
Kojo
1
@Kojo Pas aussi facilement qu'il le devrait! Si c'était moi, je créerais probablement mon propre auto-submit.js et l'utiliser hook_js_alter()pour m'assurer qu'il est utilisé à la place de l'original. (Mais à mon humble avis, le code ctools devrait utiliser Drupal.settings plutôt qu'une valeur codée en dur.)
Andy
1
@Kojo Jetez également un œil à drupal.org/node/2023705 qui vise à améliorer l'expérience de soumission automatique (pas seulement pour les entrées de texte). Il y a un patch qui pourrait vous suffire. EDIT: et si vous essayez de l'utiliser, n'oubliez pas de mettre un commentaire sur la question en disant si cela a fonctionné.
Andy
0

Cette approche présente à la fois l'avantage et l'inconvénient d'être appliquée à tous les événements AJAX déclenchés par des touches sur n'importe quelle page où ce script s'exécute.

!function ($) {
  const originalMethod = Drupal.ajax.prototype.eventResponse,
        timeoutDelay   = 500;

  var timeoutId;

  // Override the default event handler
  Drupal.ajax.prototype.eventResponse = function (element, event) {
    const self = this;
    clearTimeout(timeoutId);

    if ('keyup' === this.event) {
      // Fire the original event handler with a delay
      timeoutId = setTimeout(function (element, event) {
        originalMethod.apply(self, [element, event]);
      }, timeoutDelay, element, event);
    }
    else {
      // Fire the original event handler immediately
      originalMethod.apply(this, [element, event]);
    }
  };
}(jQuery);
tvanc
la source
-1

Voici le code que j'ai écrit:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt-br" lang="pt-br">
<head><title>Submit after typing finished</title>
<script language="javascript" type="text/javascript">
function DelayedSubmission() {
    var date = new Date();
    initial_time = date.getTime();
    if (typeof setInverval_Variable == 'undefined') {
            setInverval_Variable = setInterval(DelayedSubmission_Check, 50);
    } 
}
function DelayedSubmission_Check() {
    var date = new Date();
    check_time = date.getTime();
    var limit_ms=check_time-initial_time;
    if (limit_ms > 800) { //Change value in milliseconds
        alert("insert your function"); //Insert your function
        clearInterval(setInverval_Variable);
        delete setInverval_Variable;
    }
}

</script>
</head>
<body>

<input type="search" onkeyup="DelayedSubmission()" id="field_id" style="WIDTH: 100px; HEIGHT: 25px;" />

</body>
</html>
Alfredo Lingoist Jr.
la source
3
Bienvenue dans Drupal Answers. Vous pouvez améliorer votre réponse en écrivant un court paragraphe expliquant ce que fait le cide et comment il résoudra le problème des PO.
Radical gratuit le
-1

J'ai également essayé "beforeSend" sans trop de chance. Je suis alors tombé sur "beforeSubmit" et cela fait l'affaire pour moi. Vous pouvez également utiliser cette stratégie pour vous connecter à d'autres méthodes de prototype Drupal ajax (voir /misc/ajax.js pour toutes les méthodes originales):

(function($, Drupal) {
    var delayedTimeoutId;
    var delayInterval = 500;

    /**
     * Modify form values prior to form submission.
     */
    Drupal.ajax.prototype.original_beforeSubmit = Drupal.ajax.prototype.beforeSubmit;
    Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
        // Some console stuff for info purposes:
        if(window.console) {
            console.log('beforeSubmit args:');
            console.log(this); // contains stuff like PHP AJAX callback, triggering selector, etc.
            console.log(form_values); // the form data
            console.log(element); // the triggering element
            console.log(options); // ajax options
        }

        // If it is the triggering selector or callback I want to delay, then do the delay:
        if(this.selector == '#my-text-input-id' || this.callback == '_my_module_ajax_callback') {
            // Clear timeout if it exists;
            clearTimeout(delayedTimeoutId);
            // Start waiting:
            delayedTimeoutId = setTimeout(function(drupalAjax, form_values, element, options) {
                delayedTimeoutId = null;
                // Execute original beforeSubmit:
                drupalAjax.original_beforeSubmit(form_values, element, options);
            }, delayInterval, this, form_values, element, options)
        } else {
            // Continue with original beforeSubmit:
            this.original_beforeSubmit(form_values, element, options);
        }
    };
}(jQuery, Drupal));
jduhls
la source
Drupal.ajax.prototype.beforeSubmit est une fonction vide par défaut, donc ce code ne fait rien. Il appelle juste un vide avec ou sans retard.
tvanc
RE: fonction vide - C'est vrai. Il est vide pour l'instant. Mais l'API Drupal pourrait changer et elle pourrait ne plus être vide. Il s'agit d'une dérogation sûre. De plus, il ne fait actuellement rien car il appartient à l'OP d'insérer les valeurs qu'il souhaite remplacer.
jduhls
Drupal le dit même dans le code pour remplacer cette fonction: / ** * Modifier les valeurs du formulaire avant la soumission du formulaire. * / Drupal.ajax.prototype.beforeSubmit = fonction (valeurs_formulaire, élément, options) {// Cette fonction est laissée vide pour simplifier le remplacement des modules // qui souhaitent ajouter des fonctionnalités ici. };
jduhls