1

I'm trying to rewrite a form item's suffix on an AJAX callback and it keeps prepending the first choice and then doing nothing else. My code:

function my_dashboard_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id){
  if($form_id == 'node_job_listing_owner_job_form_form'){
    $tid = $form_state->getValue('field_job_description')[0]['target_id'];
    if(empty($tid)){
      $tid = $form['field_job_description']['widget']['#default_value'][0];
    }
    $link = null;
    if(!empty($tid)){
      $link_url = \Drupal\Core\Url::fromRoute('entity.taxonomy_term.canonical', [
        'taxonomy_term' => $tid
      ], [
        'attributes' => [
          'class' => ['use-ajax'],
          'data-dialog-type' => 'dialog',
          'data-dialog-options' => \Drupal\Component\Serialization\Json::encode(['width' => 420]),
          'data-dialog-renderer' => 'off_canvas',
        ],
      ]);
      $link = \Drupal::l('Preview Job Description...'.$tid, $link_url);
    }

    $form['field_job_description']['#suffix'] = $link;
    $form['field_job_description']['widget']['#ajax'] = [
      'callback' => 'updateJobDescriptionPreviewLink',
      'wrapper' => 'edit-field-job-description-wrapper',
      'event' => 'change',
    ];
  }
}

function updateJobDescriptionPreviewLink(&$form, \Drupal\Core\Form\FormStateInterface $form_state){
  return $form['field_job_description'];
}

Basically, I'm trying to put a link below the "Job Description" drop down to preview the description of that term. I have the term id appended to the link text temporarily so I can see what happens. When I edit an existing node, it renders the link correctly the first time (i.e. "Preview Job Description...102"). But then, if I select a different option, it prepends another link to the existing suffix (i.e. "Preview Job Description...99 Preview Job Description...102"). Both links work correctly, but obviously two links aren't what I want. And also after that, it won't change anymore no matter what I select.

I feel like there's something simple I'm overlooking, but I confess Drupal AJAX has always confused me somewhat. Any ideas? Thanks!

1

I think the estrange behaviour it's because the suffix is after and not inside the wrapper, thus not get replaced and since you're ajaxly returning $form['field_job_description']; which contains the wrapper; thus, you end up with two same ID wrappers and fails on the second run.

Move the link generation to a function.

Here is an alternative AJAX approach where we target the link wrapper rather than the form wrapper.

function my_dashboard_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id){
  if($form_id == 'node_job_listing_owner_job_form_form'){
    $link = _my_dashboard_get_term_link($form, $form_state);
    $form['field_job_description']['#suffix'] = '<div class="term-link">' . $link . '</div>'; // wrap link
    $form['field_job_description']['widget']['#ajax'] = [ // removed 'wrapper' =>
      'callback' => 'updateJobDescriptionPreviewLink',
      'event' => 'change',
    ];
  }
}

function updateJobDescriptionPreviewLink(&$form, \Drupal\Core\Form\FormStateInterface $form_state){
  $link = _my_dashboard_get_term_link($form, $form_state);
  $response = new \Drupal\Core\Ajax\AjaxResponse();
  $response->addCommand(new \Drupal\Core\Ajax\HtmlCommand(".term-link", $link));
  return $response;
}

function _my_dashboard_get_term_link(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $tid = $form_state->getValue('field_job_description')[0]['target_id'];
  if(empty($tid)){
    $tid = $form['field_job_description']['widget']['#default_value'][0];
  }
  $link = null;
  if(!empty($tid)){
    $link_url = \Drupal\Core\Url::fromRoute('entity.taxonomy_term.canonical', [
      'taxonomy_term' => $tid
    ], [
      'attributes' => [
        'class' => ['use-ajax'],
        'data-dialog-type' => 'dialog',
        'data-dialog-options' => \Drupal\Component\Serialization\Json::encode(['width' => 420]),
        'data-dialog-renderer' => 'off_canvas',
      ],
    ]);
    $link = \Drupal::l('Preview Job Description...'.$tid, $link_url);
    return $link;
  }
}
| improve this answer | |
  • Thanks so much! I was all around it at times. I gather the $response = new \Drupal\Core\Ajax\AjaxResponse(); is the newer way, correct? – Delford Chaffin Jun 26 at 15:19
  • @DelfordChaffin correct, was introduced in D8. – No Sssweat Jun 26 at 17:50

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.