1

I have a custom form in Drupal.

When a user first sees this form, the only thing on the page is a select box, along with a few other elements they have to fill out.

When they make a selection from the select box, the #ajax callback regenerates the form, and adds about 50 results to the page.

By default, Drupal is scrolling down to the last result. This is a problem, because the users have to scroll back up to the elements near the top of the page to finish their work.

Is there a way to prevent Drupal from scrolling to the bottom of the newly-added form content?

Here is a snippet that shows how I'm setting up the form:

$form = array(
'#tree' => TRUE,
'#prefix' => '<div id="myform">',
'#suffix' => '</div>',
);

Here is a snippet from the select box that triggers returning the results.

$form['selectbox'] = array(
  '#type' => 'select',
  '#title' => t('Select box'),
  '#options' => $predefined_select_options,
  '#empty_option' => t('Select something!'),
  '#ajax' => array(
    'callback' => 'mymodule_form_ajax',
    'wrapper' => 'myform',
    'effect' => 'fade',
  ),
);

$form['other_stuff'] = array(
  '#type' => 'textfield',
  '#title' => t('Other stuff they need to fill out here'),
);

if (isset($form_state['values']['select box'])) {
  foreach ($lots_of_results as $result) {
    $form[$result] = array(
      '#type' = 'fieldset',
      '#title' = 'Lots of results in their own field sets',
    );
  }
  // It scrolls to the bottom of this huge list after it's rendered.
}

Here is the ajax handler for the select box.

function mymodule_form_ajax($form, $form_state) {
  return $form;
}

2 Answers 2

3

You could override the Drupal.ajax.prototype.success handler (/misc/ajax.js) in your theme to control behavior, maybe commenting out Drupal.unfreezeHeight(); and Drupal.freezeHeight(); could do the job? Just copy the whole function and manipulate it your own way.

/**
 * Handler for the form redirection completion.
 */
Drupal.ajax.prototype.success = function (response, status) {
  // Remove the progress element.
  if (this.progress.element) {
    $(this.progress.element).remove();
  }
  if (this.progress.object) {
    this.progress.object.stopMonitoring();
  }
  $(this.element).removeClass('progress-disabled').removeAttr('disabled');

  Drupal.freezeHeight();

  for (var i in response) {
    if (response.hasOwnProperty(i) && response[i]['command'] && this.commands[response[i]['command']]) {
      this.commands[response[i]['command']](this, response[i], status);
    }
  }

  // Reattach behaviors, if they were detached in beforeSerialize(). The
  // attachBehaviors() called on the new content from processing the response
  // commands is not sufficient, because behaviors from the entire form need
  // to be reattached.
  if (this.form) {
    var settings = this.settings || Drupal.settings;
    Drupal.attachBehaviors(this.form, settings);
  }

  Drupal.unfreezeHeight();

  // Remove any response-specific settings so they don't get used on the next
  // call by mistake.
  this.settings = null;
};

Another option would be to render the ajax form with ajax_commands where you could add custom js handlers to your callback.

1

Ran into this issue, where after ajax replace, it would auto scroll up to the top of the page.

 '#ajax' => [
    'callback' => 'mymodule_form_ajax',
    'wrapper' => 'myform',
    'disable-refocus' => true, // <-- The solution
  ],

OR

  '#type' => 'submit',
  '#value' => $this->t('Submit'),
  '#ajax' => [
    'callback' => '::submitForm',
  ],
  '#attributes' => ['data-disable-refocus' => 'true'], // <-- The solution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.