I have a form in which some select elements are ajax elements that trigger a full reload of the form. When I look at the reloaded form, all the links, e.g. for the pager I have on there and for the tablesort as well, are rewritten so they point to system/ajax, which breaks functionality off course.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sun’s picture

Category: bug » support
Priority: Major » Normal
Status: Active » Postponed (maintainer needs more info)

In order to call this a bug report, clear steps to reproduce the bug are required.

daften’s picture

Component: ajax system » database system

Are these steps enough. If necessary, I can post the code, but unfortunately, it wouldn't work, since it works on an external database which contains proprietary data.

  1. Create a form which contains both
    • a selection box which is ajaxified and which will reload the entire form on change. (the callback function just returns the form)
    • a table which uses tablesort and/or pager. (tablesort will allways create links, so that might be the easiest
  2. Load the page with the form and look at the links produced for tablesort, they are correct
  3. Use the selection box to let the form dynamically be reloaded, the links point to the path system/ajax, which is incorrect.

This issue is because in tablesort.inc the links in the table are created based on the q parameter. This is in basis a good assumption, however, in this specific case it throws errors.
And honestly, i have no idea of a decent workaround, except maybe by allowing an option to be passed to tablesort to give the path.

sun’s picture

Title: Reloading a form through an ajax element, makes all the links (e.g. for pager, tablesort) point to system/ajax » Pager, tablesort links in a form point to system/ajax when reloaded via AJAX
Version: 7.1 » 8.x-dev
Component: database system » ajax system
Category: support » bug
Status: Postponed (maintainer needs more info) » Active
Issue tags: +Needs tests, +Needs backport to D7

That sounds sufficient for me. Next step would be to convert those steps into a test, to confirm the bug exists, and prevent it from being re-introduced after it has been fixed.

daften’s picture

I will (try to) look into that the coming days.
Are you sure this applies to the ajax system, since the URL's are written in tablesort.inc ? It seems this might not be solvable there.

daften’s picture

I'm looking into it, but this is the first time I'm writing tests for drupal, so It's gonna be some trial-and-error (and I don't have much spare time left). The configuration part I get, but can you give me a hint if there are functions to tests for specific links in the output or something similar (so i don't have to test the entire output specifically)?

pbuyle’s picture

subscribe

pbuyle’s picture

Here is a patch to add tests for pager and tablesort links in ajax enabled forms. As demonstrated by these tests, if theme('pager', ...) and theme('table', ...) are called from the form builder functions, the produced links correctly point to the page URL (and not system/ajax). But if the pager or table are returned as render arrays (ie. array('#theme' => 'pager', ...) and array('#theme' => 'table', ...)), the links point to system/ajax.

khacnhat’s picture

subcribe

Kvitz’s picture

I'm experiencing this problem too in drupal 7.12. I'm trying to build a tableselect using theme() function and #markup, as in the patch above, and it does seem to solve the system/ajax problem when an ajax action is triggered, but I'm not being able to change the table in the ajax function afterwards nor to use the pager. Are there any resources on how to build tableselects using theme function to solve the system/ajax problem?

pbuyle’s picture

@Kvitz: The patch in #7 only add tests to demonstrate the issue, it does not solve it.

The workaround, if I remember correctly, is the render the pager in the form builder. So instead of something modern like

$form['foo']['pager'] = array(
  '#theme' => 'pager'
);

You do it old-style and call theme('pager') pager to generate the content of a markup element

$form['foo']['pager'] = array(
  '#markup' => theme('pager')
);

Edit: Oups, I misread your post. Sorry, AFAIK, there is no documentation or resource to solve this. I made some ugly JavaScript hacks to work around this and rewrite the links but nothing worth sharing (as it lacks documentation and is really tied to a specific form).

jbeuckm’s picture

subscribe

lmdoom’s picture

I've managed to solve it next way:
$_GET['q'] param is used by pager to get current page path. So I set page path I need.

$_GET['q'] = YOUR_BASE_PAGE_PATH; 
$pager = theme('pager', $variables);

I hope, it helps someone else.

manuel.hidalgo’s picture

Version: 8.x-dev » 7.14

Hola recien tengo un problema con el siguiente error:

An error occurred while attempting to process /es/system/ajax: this._each is not a function

Alguien ha resuelto esto?

Kvitz’s picture

Thanks Leonid.adcillc. This has indeed improved my problem. It now points to the right place. My only problem now is dealing with multiple paged tables in the same drupal form.

pinin4fjords’s picture

I'm seeing this issue in 7.20. In my case I worked around it by saving the value from GET at the first view of my form:

$form['q'] = array('#type' => 'value', '#value' => isset($form_state['values']['q']) ? $form_state['values']['q'] : $_GET['q']);

... and restoring it later when necessary (in my case immediately before a call to views_embed_view() after some ajax):

$_GET['q'] = isset($form_state['values']['q']) ? $form_state['values']['q'] : $_GET['q'];
4fs’s picture

Hi, Any progress on this issue. Seems to be a deal breaker for my ubercart site. How could I use the info above to place a quick fix in place. Where does the code go etc. Thank you.

learnbydrop’s picture

Ajax Pagination error in the form, any solution for this issue...?

mondrake’s picture

Version: 7.14 » 8.x-dev
Issue summary: View changes

Please, leave this issue to the 8.x-dev version, at the moment. Bugs are first addressed in the developing version (Drupal 8 currently), and only when solved there, backported to previous versions if possible. Changing version will take it away from the radar of the core developers. Thanks.

I can confirm that in D8 this is still the case:

  • have a pager in a form
  • the form is Ajax enabled
  • on first 'normal' call of the form, the pager links are referring to the route path of that form
  • upon Ajax refresh of the form, the pager links are referring to the system.ajax route path
  • when you click on any such link, you get an Ajax error
mondrake’s picture

Working on a fix for #2182555: On Ajax-enabled forms with a pager, pager is disappearing on form validation error and on Ajax form reload, I think now I have clear why this happens, at least in D8.

  1. when generating links, the theme functions get the 'href' to be used for the hyperlink from the current_path() function, which returns the path to the current route.
  2. when getting the form first time, the route is set to the form's path, and the links are generated with the correct path.
  3. if there is an Ajax enabled element on the form, the form and form state structures get cached; when an Ajax reload is executed, the form is rendered from the cached structures, and not 'rebuilt'.
  4. on Ajax reload, the route used is the one of the Ajax controller (e.g. 'system/ajax') and not the one of the form.
  5. so, the form is rendered with the links pointing to the current_path() that at that moment is 'system/ajax'.

At the moment we do not even have pagers on Ajax reload, so I believe #2182555: On Ajax-enabled forms with a pager, pager is disappearing on form validation error and on Ajax form reload needs to be fixed first. If the fix there gets accepted as a solution, we could use a similar model here, i.e. store (parts of) the current request in the cached $form_state, and during Ajax reload temporarily swap the Ajax route request with the original (cached) one, for the part of the Ajax processing that re-renders the form.

kevinquillen’s picture

Yes, this is an issue. You can see this typically when you have triggered an AJAX command, execute some code like drupal_get_form, and return it in a modal. When executing from the AJAX callback, the path is almost always system/ajax because it is handling the command callback from the AJAX framework (in 7). Thus any dynamic paths, like pagers, break when replaced, with the wrong URLs. I am looking at this issue on my screen right now in a Drupal Commerce site I am building.

mondrake’s picture

Version: 8.0.x-dev » 7.x-dev
Issue tags: -Needs backport to D7
Related issues: +#2263569: Bypass form caching by default for forms using #ajax.

This issue was fixed for D8 by #2263569: Bypass form caching by default for forms using #ajax., by POSTing AJAX forms back to the form's URL and identifying differently the need to process them via AJAX. I have no idea if similar approach could be taken here, but this is now a D7 only issue.

czigor’s picture

As a quick fix I overrode theme_pager_link() to set the url of my AJAX-loaded pager to the page url instead of $_GET['q'] (which was system/ajax).

Ali yah’s picture

Is there anyway I can distinguished the first view/load of the form not triggered by a callback function?

wuinfo - Bill Wu’s picture

Nice we get it solved on D8, another reason to use D8. :)

JayKandari’s picture

#12 for D7 !!

amit0212’s picture

function employee_list() {
  global $user;
  $rows = array();
  $result = db_select('emp', 'e');
  $result->fields('e');
  if (isset($_GET['empcode']) && !empty($_GET['empcode'])) {
    $result->condition('empcode', $_GET['empcode']);
  }
  if (isset($_GET['name']) && !empty($_GET['name'])) {
    $result->condition('name', $_GET['name']);
  }
  if (isset($_GET['company']) && !empty($_GET['company'])) {
    $result->condition('company', $_GET['company']);
  }
  if (isset($_GET['department']) && !empty($_GET['department'])) {
    $result->condition('department', $_GET['department']);
  }
  $res = $result->extend('PagerDefault')->limit(5)->execute()->fetchAll();
  foreach ($res as $value) {
    $sid = $value->sid;
    $edit = l('edit', "employee/$sid/edit");
    $view = l('view', "employee/$sid/view");
    $rows[] = array($value->sid, $value->empcode, $value->name, $value->salary, $value->gender, $value->company, $value->department, $value->picture, $edit, $view);
  }
  $header = array('sid', 'empcode', 'name', 'salary', 'gender', 'company', 'department', 'picture', 'operation', 'operation 1');
  $table_element = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#prefix' => drupal_render(drupal_get_form('filter_form')),
    '#suffix' => theme('pager'),
    '#empty' => t('Your table is empty'),
  );
  return drupal_render($table_element);
}
joegl’s picture

joegl’s picture

This definitely was not fixed in 8, unless I'm doing something wrong. My tablesort links are all broken when I render a table in an AJAX callback.

joegl’s picture

Version: 8.0.x-dev » 8.8.x-dev

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.