2

I have a form file:

namespace Drupal\h_scheduler\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use \Drupal\node\Entity\Node;

class DayAddEntries extends FormBase {

  public counter = 0;

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'hs_day_add_form';
  }

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

    $form_state->setCached(FALSE);

    $form['#attached']['library'][] = 'h_scheduler/form_actions';

    /*...More fields....*/

    /* Special */
    $form['specials'] = array(
      '#type' => 'fieldset',
      '#tree' => TRUE,
      '#title' => t('Specials'),
      '#prefix' => '<div id="specials">',
      '#suffix' => '</div>',
    );

    if ($this->counter) {
      for ($i = 1; $i <= $this->counter; $i++) {
        $form['specials']['special'.$i] = array(
          '#type' => 'fieldset',
          '#title' => t('Special ') . $i,
          '#tree' => TRUE,
        );
        $form['specials']['special'.$i]['field'] = array(
          '#type' => 'number',
          '#title' => t('Every'),
          '#title_display' => 'before',
        );
        $form['specials']['special'.$i]['field'] = array(
          '#type' => 'textfield',
          '#title' => t('Prefix'),
          '#title_display' => 'after',
        );
      }
    }
    $form['specials']['operations']['#type'] = 'actions';
    $form['specials']['operations']['add_special'] = array(
      '#type' => 'button',
      '#value' => $this->t('Add special'),
      '#ajax' => array(
        'callback' => '::ajaxAddSpecial',
        'wrapper' => 'specials',
      ),
    );

    /* Not working */
    $form['specials']['operations']['remove_special'] = array(
      '#type' => 'button',
      '#value' => $this->t('Remove special'),
      '#ajax' => array(
        'callback' => '::ajaxRemoveSpecial',
        'wrapper' => 'specials',
      ),
    );

    /* Submit */
    $form['actions']['#type'] = 'actions';
    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Save'),
      '#button_type' => 'primary',
    );

    $this->counter++;

    return $form;
  }

  /**
   * Increments the number of specials to have
   */
  public function ajaxAddSpecial($form, FormStateInterface $form_state) {
    return $form['specials'];
  }

  /**
   * Decrements the number of specials to have
   */
  public function ajaxRemoveSpecial($form, $form_state) {
    $this->counter -= 2;
    return $form['specials'];
  }

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

    /* Do stuff */

  }
}

jQuery:

jQuery(function($) {
  $('#edit-specials .fieldset-wrapper .fieldset-wrapper, #edit-regular .fieldset-wrapper').addClass('entry-wrapper').each(addStyleClasses);

  function addStyleClasses() {
    console.log('hi');
    $(this).children('.form-item')
      .addClass(function() {
        var regex = /form-item-\S+-(\S+)/;
        return regex.exec($(this).attr('class'))[1];
      })
      .not('.every').wrapAll('<div class="item-wrapper">');
  }

});

I'm able to add a new "special" item, but when I do it appears wacky.

This is because I've styled the form using a jQuery function that adds classes and wraps elements. However, that function does not run when the form['specials'] is rebuilt.

My question, how do I run a JS function after an ajax call?

6
  • Can you please post your jQuery code? The problem is likely to be there.
    – No Sssweat
    Aug 15, 2017 at 4:51
  • 1
    Use Drupal.behaviors and jquery once in your code and you'll be fine.
    – user21641
    Aug 15, 2017 at 5:53
  • @NoSssweat Added JS. I can confirm that my jQuery code works the on load, but when I rebuild the form['specials'] the JS doesn't apply to it. Aug 15, 2017 at 18:25
  • @IvanJaros Thanks, I'll check it out and get back to you. Aug 15, 2017 at 18:27
  • @IvanJaros I solved it using Drupal.behaviors and jquery once! Thanks, and if you'll add an answer, I'll accept it! Aug 18, 2017 at 4:46

1 Answer 1

3

This has a solution on Stackexchange here already, but:

This would be your full javascript file:

(function ($, Drupal) {
  Drupal.behaviors.myModuleName = {
    attach: function (context, settings) {
      // I am doing a find() but you can do a once() or whatever you like :-)
      $('#element', context).find('.sub-element').each(function () {
        // Do your thing here
      });
    }
  };
})(jQuery, Drupal);

Note on the question's js: I would say when calling a function like your addStyleClasses() it would be more reliable to explicitly pass your target element in the function call than using $(this) in there.

Your Answer

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

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