Verzögern Sie den Ajax-Aufruf im Textfeld, um die Eingabe zu ermöglichen

8

Ich möchte Ajax daran hindern, auf die gleiche Weise zu feuern, wie die automatische Vervollständigung zu funktionieren scheint. Wenn ein Benutzer beispielsweise tippt, wird der Ajax erst ausgeführt, nachdem seit der letzten Eingabe 500 ms verstrichen sind.

Ich schaue gerade auf drupal.behaviors, kann es aber nicht zum Laufen bringen.

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

Dies ist das Formularelement, an das das Verhalten angehängt ist.

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

Diese jsfiddle zeigt, was ich erreichen will .

Würde Drupal.ajax.prototype.beforeSend überschrieben? ein Weg sein, dies zu beseitigen?

Das Folgende funktioniert für den ersten 'Satz' von Eingaben mit der Klasse .andtimer. Es funktioniert bei keinem anderen Satz, der Ajax fährt immer mit dem ersten Satz fort. Irgendwelche Ideen, wie man das behebt?

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

Verwenden von $ form ['my_input'] ['# ajax'] ['event'] = 'finishinput' wie vorgeschlagen und

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

Funktioniert für jede 'Gruppe' von Eingaben, bei denen die Anzahl der gefüllten Eingaben ermittelt werden muss.

Inigo Montoya
quelle
Dieser Code hat nichts mit Keyup / Keydown oder der Ereignisbindung zu tun, auf die Sie anspielen. Können Sie bitte Ihren tatsächlichen Code hinzufügen? Denken Sie daran, dass dies nicht der richtige Ort ist, wenn Sie nur nach allgemeiner Javascript-Hilfe suchen. Die Regel lautet: Lass es zuerst außerhalb von Drupal funktionieren, und wenn du es nicht innerhalb von Drupal zum Laufen bringen kannst , frag hier
Clive
Danke Clive, ich habe den Code hinzugefügt, um die Eingabe zu erstellen. Ich habe mich sofort an die Arbeit gemacht und es in Drupal zum Laufen gebracht. Ich lerne immernoch. Ich werde es draußen versuchen und sehen, ob ich das Problem in meinem Kopf nicht ein bisschen mehr klären kann.
Inigo Montoya
Ich habe zu früh gesprochen und nicht bemerkt, wie sehr Sie an Drupal gebunden sind. Das macht ein ziemlich interessantes Problem :)
Clive
1
Das untere Code-Snippet funktioniert gut für mich, außer dass das Feld nach dem Auslösen des Ereignisses den Fokus verliert. Wie kann ich machen, dass der Fokus nach dem Brennen auf dem Element bleibt.
VanD

Antworten:

7

Eine Möglichkeit besteht darin, ein benutzerdefiniertes jQuery-Ereignis zu verwenden, z. so etwas wie fertige Eingabe . Stellen Sie $form['my_input']['#ajax']['event'] = 'finishedinput'einige JS ein und stellen Sie sie bereit, um Ihr benutzerdefiniertes Ereignis nach einer angemessenen Verzögerung auszulösen (ähnlich wie bei JS in der Geige).

Andy
quelle
Tolle ! Ich habe genau danach gesucht :) Vielen Dank. Wenn ich jedoch einen Tipp dazu haben könnte, wie Sie dies anwenden können, wenn Sie eine Eingabe eines belichteten Ansichtsformulars ändern. Wenn ich den Rückruf nicht auf $ form ['my_input'] ['# ajax'] setze, passiert nichts. Wenn ich die übermittelten Übermittlungsansichten hinzufüge, die vom Übermittlungs-fn als Rückruf (oder was auch immer) angezeigt werden, funktioniert dies, gibt aber einen undefinierten Index zurück: form_build_id. .. Und ich weiß auch nicht, wie und wo ich ein $ form_state ['rebuild'] = TRUE hinzufügen soll. Vielen Dank im Voraus
Kojo
1
@Kojo Könnten Sie eine neue Frage dazu stellen und Beschreibungen der AJAX-Einstellungen von Views, des exponierten Filters, des von Ihnen verwendeten benutzerdefinierten Codes und der auftretenden Probleme enthalten? Btw CTools autosubmit hat bereits eine (fest codierte) Verzögerung beim Senden aus Textfeldern von 0,5 s ( siehe auto-submit.js ).
Andy
Ah toll, hier ist die Einstellung! Ist es nicht möglich, es "on the fly" für eine bestimmte Eingabe zu ändern? Wenn es nicht einfach ist, werde ich eine Frage posten :) Vielen Dank für Ihre Hilfe!
Kojo
1
@Kojo Nicht so einfach wie es sein sollte! Wenn ich es wäre, würde ich wahrscheinlich nur meine eigene auto-submit.js erstellen und verwenden, hook_js_alter()um sicherzustellen, dass sie anstelle des Originals verwendet wird. (Aber wirklich imho sollte der ctools-Code Drupal.settings anstelle eines fest codierten Werts verwenden.)
Andy
1
@Kojo Schauen Sie sich auch drupal.org/node/2023705 an, in dem es darum geht, die automatische Übermittlung zu verbessern (nicht nur für Texteingaben). Es gibt einen Patch, der für Sie ausreichen könnte. BEARBEITEN: und wenn Sie versuchen, es zu verwenden, vergessen Sie nicht, einen Kommentar zu dem Problem abzugeben, der besagt, ob es funktioniert hat.
Andy
0

Dieser Ansatz hat sowohl den Vorteil als auch den Nachteil, dass er für alle durch Keyups ausgelösten AJAX-Ereignisse auf jeder Seite angewendet wird, auf der dieses Skript ausgeführt wird.

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

Dies ist der Code, den ich geschrieben habe:

<!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.
quelle
3
Willkommen bei Drupal Answers. Sie können Ihre Antwort verbessern, indem Sie einen kurzen Absatz schreiben, in dem erläutert wird, was der Cide bewirkt und wie er das OP-Problem löst.
Free Radical
-1

Ich habe auch "beforeSend" ohne viel Glück versucht. Ich bin dann auf "beforeSubmit" gestoßen und das macht den Trick für mich. Mit dieser Strategie können Sie sich auch in andere Drupal-Ajax-Prototypmethoden einbinden (alle Originalmethoden finden Sie unter /misc/ajax.js):

(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
quelle
Drupal.ajax.prototype.beforeSubmit ist standardmäßig eine leere Funktion, sodass dieser Code eigentlich nichts tut. Es wird nur ein Leerzeichen mit oder ohne Verzögerung aufgerufen.
tvanc
RE: leere Funktion - Dies ist wahr. Es ist vorerst leer. Die Drupal-API kann sich jedoch ändern und ist möglicherweise nicht mehr leer. Dies ist eine sichere Überschreibung. Außerdem macht es derzeit nichts, da es Sache des OP ist, die Werte einzufügen, die überschrieben werden sollen.
Jduhls
Drupal sagt sogar im Code, dass diese Funktion überschrieben werden soll: / ** * Ändern Sie die Formularwerte vor dem Senden des Formulars. * / Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {// Diese Funktion bleibt leer, um das Überschreiben von Modulen zu vereinfachen, // die hier Funktionen hinzufügen möchten. };
Jduhls