Ritarda la chiamata Ajax sul campo di testo per consentire la digitazione


8

Vorrei ritardare il lancio di Ajax nello stesso modo in cui il completamento automatico sembra funzionare. Ad esempio, se un utente sta digitando, ajax non verrà eseguito fino a quando non sono trascorsi 500 ms dall'ultimo keyup.

Attualmente sto guardando drupal.behaviors ma non sono in grado di farlo funzionare.

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

Questo è l'elemento del modulo a cui è associato il comportamento.

$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'),
  ),                      
);

Questo jsfiddle mostra ciò che sto cercando di ottenere.

Sarebbe Come ignorare Drupal.ajax.prototype.beforeSend? essere un percorso per abbatterlo?

Quanto segue funziona per il primo "set" di input con la classe .andtimer. Non funziona per nessun altro set, l'ajax continua sempre con il primo set. Qualche idea su come risolvere questo problema?

(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); 

Utilizzando $ form ['my_input'] ['# ajax'] ['event'] = 'finitoinput' come suggerito e

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);
  }
});

Funziona per ogni "gruppo" di input in cui è necessario ottenere il conteggio degli input riempiti.


Quel codice non ha nulla a che fare con il keyup / keydown o l'associazione di eventi a cui alludi - puoi aggiungere il tuo codice attuale per favore? Tieni presente che se stai solo cercando un aiuto javascript generale, questo non è il posto giusto per trovarlo. La regola è: farlo funzionare prima fuori Drupal, e se non riesci a farlo funzionare dentro Drupal, chiedi qui
Clive

Grazie Clive, ho aggiunto il codice per creare l'input. Sono andato dritto per la prova e farlo funzionare in Drupal. Ancora imparando. Ci proverò fuori e vedrò se non riesco a chiarire un po 'di più il problema nella mia testa.
Inigo Montoya,

Ho parlato troppo presto, non ho capito quanto sei legato a Drupal che stai cercando di fare. Questo rende un problema piuttosto interessante :)
Clive

1
Lo snippet di codice di fondo funziona bene per me, tranne che dopo aver attivato l'evento il campo perde lo stato attivo. Come posso fare è che l'attenzione si concentri sull'elemento dopo lo sparo.
VanD,

Risposte:


7

Un'opzione è utilizzare un evento jQuery personalizzato, ad es. qualcosa come input finito . Impostare $form['my_input']['#ajax']['event'] = 'finishedinput'e fornire alcuni JS per attivare l'evento personalizzato dopo un ritardo appropriato (simile al JS nel violino).


Sorprendente ! Lo stavo proprio cercando :) Grazie mille. Tuttavia, se potessi avere un suggerimento su come applicare questo quando si modifica un input di una forma esposta di viste. Se non imposto il callback su $ form ['my_input'] ['# ajax'] non succede nulla, se aggiungo le visualizzazioni inviate del modulo esposto invia fn come callback (o qualsiasi altra cosa) funzioni ma restituisce un indice indefinito: form_build_id. .. E non so nemmeno come e dove aggiungere un $ form_state ['rebuild'] = TRUE Grazie in anticipo
Kojo

1
@Kojo Potresti fare una nuova domanda a riguardo e includere descrizioni delle impostazioni di AJAX di Views, il filtro esposto, qualsiasi codice personalizzato che stai utilizzando e i problemi che si verificano? Btw CTools autosubmit ha già un ritardo (hardcoded) nell'invio da campi di testo di 0,5 s ( vedi auto-submit.js ).
Andy,

Ah fantastico, ecco l'ambientazione! Non è possibile modificarlo "al volo" per un input specifico? Se non è semplice, posterò una domanda :) Grazie per il tuo aiuto!
Kojo,

1
@Kojo Non così facilmente come dovrebbe essere! Se fossi in me, probabilmente avrei semplicemente creato il mio auto-submit.js e usato hook_js_alter()per assicurarsi che fosse usato al posto dell'originale. (Ma davvero, il codice ctools dovrebbe usare Drupal.settings piuttosto che un valore hardcoded.)
Andy,

1
@Kojo Dai anche un'occhiata a drupal.org/node/2023705 che riguarda il miglioramento dell'esperienza di invio automatico (non solo per input di testo). C'è una patch che potrebbe essere abbastanza per te. EDIT: e se provi ad usarlo, non dimenticare di inserire un commento sul problema dicendo che ha funzionato.
Andy,

0

Questo approccio presenta sia il vantaggio che lo svantaggio di essere applicato a tutti gli eventi AJAX attivati ​​da keyup in qualsiasi pagina in cui viene eseguito questo script.

!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);

-1

Questo è il codice che ho scritto:

<!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>

3
Benvenuto in Drupal Answers. Puoi migliorare la tua risposta scrivendo un breve paragrafo che spiega cosa fa il cide e come risolverà il problema dei PO.
Radicale gratuito il

-1

Ho anche provato "beforeSend" senza molta fortuna. Poi mi sono imbattuto in "beforeSubmit" e questo fa il trucco per me. Puoi usare questa strategia per agganciare anche altri metodi prototipo di ajax Drupal (vedi /misc/ajax.js per tutti i metodi originali):

(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));

Drupal.ajax.prototype.beforeSubmit è una funzione vuota per impostazione predefinita, quindi questo codice in realtà non fa nulla. Invoca semplicemente un vuoto con o senza ritardo.
tvanc,

RE: funzione vuota - Questo è vero. È vuoto per ora. Ma l'API Drupal potrebbe cambiare e potrebbe non essere più vuota. Questa è una sostituzione sicura. Inoltre, attualmente non fa nulla perché spetta all'OP inserire tutti i valori che vogliono sovrascrivere.
jduhls,

Drupal lo dice anche nel codice per sovrascrivere questa funzione: / ** * Modifica i valori del modulo prima dell'invio del modulo. * / Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {// Questa funzione viene lasciata vuota per semplificare la sostituzione dei moduli // che desiderano aggiungere funzionalità qui. };
jduhls,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.