1

Related to my previous question, but this specifically pertains to how ajax works rather than what $form_state does.

I have a form class defined with the following code (an "instruction" in this code is just the name for a blank text field, and there needs to be the ability to add as many of these text fields as the user desires):

namespace Drupal\mymodule\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class MymoduleSubmitForm extends FormBase {
/**
 * {@inheritdoc}
 */
public function getFormId() {
    // Unique ID of the form.
    return 'mymodule_submit_form';
}
/**
 * {@inheritdoc}
 */
public function buildForm(array $form, FormStateInterface $form_state) {
    // Create a $form API array.

    $form['#tree'] = TRUE;
    $i = 0;
    $num_instructions = $form_state->get('num_instructions');
    if (empty($num_instructions)) {
        $num_instructions = $form_state->set('num_instructions', 1);
        $num_instructions = $form_state->get('num_instructions');
    }
    $form['instructions'] = array(
            '#type' => 'fieldset',
            '#title' => 'Instructions',
            '#prefix' => '<div id="instructions-wrapper">',
            '#suffix' => '</div>'
    );
    for ($i = 0; $i < $num_instructions; $i++) {
      $form['instructions'][$i] = [
        '#type' => 'textfield',
        '#title' => $this->t('@num', ['@num' => $i + 1]),
      ];
    }
    $form['add_instruction'] = array(
        '#type' => 'submit',
        '#value' => $this->t('Add step'),
        '#ajax' => array(
            'callback' => '::addInstructionCallback',
            'wrapper' => 'instructions-wrapper'
        ),
    );
    $form_state->setCached(FALSE);
    $form['submit'] = array(
            '#type' => 'submit',
            '#value' => $this->t('Submit')
    );
    return $form;
}

/**
 * Implements callback for Ajax event
 *
 * @param array $form
 *   From render array.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   Current state of form.
 *
 * @return array
 *   Form fields.
 */
public function addInstructionCallback(array &$form, FormStateInterface $form_state) {
    ddl($form);
    $name_field = $form_state->get('num_instructions');
    return $form['instructions'];
}

/**
 * {@inheritdoc}
 */
public function validateForm(array &$form, FormStateInterface $form_state) {
}

/**
 * {@inheritdoc}
 */
public function submitForm(array &$form, FormStateInterface $form_state) {
    ddl(1); //ignore this for now
}

The form is called in mymodule.module like this:

function mymodule_node_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
    $current_path = \Drupal::request()->getRequestUri();
    $paths = explode('/', $current_path);
    if ($paths[1] == 'submit-set')
        $build['myform'] = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\MymoduleSubmitForm');
}

My problem is that my Ajax callback function addInstructionCallback does not seem to be firing at all. The indicator appears when I click the button to show that the ajax function is doing its work, and then it goes away and the form hasn't changed. I check /admin/reports/debug and it is completely empty, the ddl($form); call from within my callback function has not fired. There are no PHP error messages to be found in reports or log files either.

I am mostly following the code in this example, but I have also tried an approach using AjaxResponse like in this example and it hasn't made a difference. I have also tried changing the button to a checkbox in case it was breaking because of my unfinished submit function, but that didn't make a difference either.

What am I doing wrong with Ajax?

Update: Console is doing some weird stuff:

Uncaught AjaxError: 
An AJAX HTTP error occurred.
HTTP Result Code: 200
Debugging information follows.
Path: /submit-set?ajax_form=1
StatusText: OK

ResponseText:(entire contents of my page, including theme headers and footers, followed by

{"ajaxPageState":{"theme":"bartik","libraries":"admin_toolbar\/toolbar.tree,admin_toolbar\/toolbar.tree,admin_toolbar_tools\/toolbar.icon,admin_toolbar_tools\/toolbar.icon,bartik\/global-styling,bartik\/global-styling,bartik\/messages,classy\/base,classy\/base,classy\/messages,classy\/messages,classy\/node,classy\/node,contextual\/drupal.contextual-links,contextual\/drupal.contextual-links,contextual\/drupal.contextual-toolbar,contextual\/drupal.contextual-toolbar,core\/drupal.active-link,core\/drupal.active-link,core\/html5shiv,core\/html5shiv,core\/normalize,core\/normalize,history\/mark-as-read,history\/mark-as-read,quickedit\/quickedit.inPlaceEditor.plainText,shortcut\/drupal.shortcut,shortcut\/drupal.shortcut,system\/base,system\/base,toolbar\/toolbar,toolbar\/toolbar,toolbar\/toolbar.escapeAdmin,toolbar\/toolbar.escapeAdmin,tour\/tour,tour\/tour,user\/drupal.user.icons,user\/drupal.user.icons"},"ajaxTrustedUrl":{"\/search\/node":true},"history":{"nodesToMarkAsRead":{"45":true}},"toolbar":{"breakpoints":{"toolbar.narrow":"only screen and (min-width: 16.5em)","toolbar.standard":"only screen and (min-width: 38.125em)","toolbar.wide":"only screen and (min-width: 61em)"},"subtreesHash":"Y9yCNrSN2LUELxt5wnz-3xSDjtgka559ps7ynAoGrpw"},"path":{"baseUrl":"\/","pathPrefix":"","currentPath":"node\/45","currentPathIsAdmin":false,"isFront":false,"currentLanguage":"en","currentQuery":{"_wrapper_format":"html","ajax_form":"1"}},"pluralDelimiter":"\u0003","user":{"uid":"1","permissionsHash":"d0f6778fd5e1fddf0d1d92a309af30862905f78390534ce1aa8a064cbc51b24e"}}

)

Trace:

Drupal.Ajax.error       @   {cache}:2995
complete                @   {cache}.js:2540
t.complete              @   {cache}.js:1320
j                       @   {cache}.js:2
fireWith                @   {cache}.js:2
x                       @   {cache}.js:4
(anonymous function)    @   {cache}.js:4

Have already tried clearing cache.

Update: Modified code to match another example. Still getting the same error.

Update: Adding a console.log(status); to the called complete function above return ajax.error(xmlhttprequest, ajax.url); returns the string parsererror. Trying to log anything else related to the ajax request to console (such as the xmlhttprequest parameter) crashes the page.

  • To debug AJAX I suggest you switch to xdebug - it will be far more helpful to you than devel, as you can step through the code line by line and see what happens, see what the global/local scope has, view the call stack, etc. Particularly with AJAX callbacks, it will give you 100% verification whether or not they're being called, because the breakpoints tell all. It can be setup in Atom, VSCode, or PHPStorm. – Kevin Sep 12 '16 at 17:27
  • Ugh..OMG... I'm soooooooo sorry for all the pain, suffering and wasted time I caused, I linked you to the wrong one, this is the correct one AjaxAddMore.php. The wrong one I linked you to is for when you select a field value, it ajax and shows another field. – No Sssweat Sep 12 '16 at 23:47
  • Don't worry @NoSssweat, I saw that example when I was exploring the link you sent me. I just updated my code in the OP to show a closer example to that one. It is still giving me the exact same error. – saramm1 Sep 13 '16 at 13:10
  • @saramm1 Oh... phew. – No Sssweat Sep 13 '16 at 21:03
2

I've figured it out. My problem was that I was inserting an Ajax-using form into a page node. I don't know why this is a problem, but I installed the Examples module and saw that the AjaxAddMore.php form was working fine as-is once installed. I replaced my custom form with the AjaxAddMore form in the setup I had (inserting a form into a page node), and it also returned the same console error I was getting before.

I looked at the fapi_example.routing.yml file in Examples, particularly the following lines:

fapi_example.ajax_addmore:
path: 'examples/fapi_example/ajax_addmore'
defaults:
  _form:  '\Drupal\fapi_example\Form\AjaxAddMore'
  _title: 'Add-more button'
requirements:
  _permission: 'access content'

and set up my form to display on its own in this manner. I did not need the form to exist with any other page content, so I removed it from the page insertion setup I had before entirely.

I wouldn't call this a solution for a use case where it would be necessary to insert a form into a page node, but for my purposes the form ajax is working now.

  • I had a feeling that this was part of the problem, unfortunately, I was so busy yesterday, didn't have time to test it. – No Sssweat Sep 13 '16 at 21:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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