1

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?

  • Can you please post your jQuery code? The problem is likely to be there. – No Sssweat Aug 15 '17 at 4:51
  • 1
    Use Drupal.behaviors and jquery once in your code and you'll be fine. – user21641 Aug 15 '17 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. – Chris Happy Aug 15 '17 at 18:25
  • @IvanJaros Thanks, I'll check it out and get back to you. – Chris Happy Aug 15 '17 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! – Chris Happy Aug 18 '17 at 4:46
1

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, privacy policy and cookie policy

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