2

I'm trying to get the hang of Forms'N'Ajax in Drupal 8.

I have a classic problem with my selects in D8:

$form['manufactureYear'] = array(
  '#type' => 'select',
  '#title' => $this->t('Manufacture year'),
  '#options' => $manufactureYears,
  '#required' => TRUE,
  '#ajax' => [
    'callback' => array($this, 'populateDurationYears'),
    'wrapper' => 'edit-loanDurationYears'
  ],
);

Then I have a second select:

$form['loanDurationYears'] = array(
  '#type' => 'select',
  '#title' => $this->t('Loan duration years'),
);

The function populateDurationYears is the one that are killing me. I've tried with the ReplaceCommand in a AjaxResponse, but when I submit the form the loanDurationYears select is empty.

Can somebody help me here?

EDIT: - If I change ReplaceCommand with AppendCommand it's almost correct. The code now looks like this:

<select id="edit-loandurationyears" class="form-select" name="loanDurationYears" data-drupal-selector="edit-loandurationyears">
  <div>
    <option value="3">3 years</option>
    <option value="4">4 years</option>
    <option value="5">5 years</option>
    <option value="6">6 years</option>
    <option value="7">7 years</option>
    <option value="8">8 years</option>
    <option value="9">9 years</option>
  </div>
</select>

What's up with that <div>? It messes up the select :-(

EDIT 2:

The populateDurationYears method looks like this:

$response = new AjaxResponse();
if($maxDurationYears != 0) {
  for($i = $minLoanDurationYears-1; $i < $maxDurationYears; $i++) {
    $option .= "<option value='" . (string)($i+1) . "'>" . (string)($i+1) . " år</option>";
  }
  $response->addCommand(new AppendCommand('#edit-loandurationyears', $option));
}
return $response;

3 Answers 3

2

I've figured it out on how to do this...

I fill out the #options for the second <select> when I build the form. I hide it with a #states.

When the user then selects something in the first <select> I use the populateDurationYears method to remove invalid options like this:

$options = [];
if($maxDurationYears != 0) {
  for($i = $minLoanDurationYears-1; $i < $maxDurationYears; $i++) {
    $options[] = ($i+1) . " years";
  }
  $form['loanDurationYears']['#options'] = $options;
}
return $form['loanDurationYears'];

This does the trick :-) No need for AjaxResponse or anything like the ReplaceCommand etc... Keep it simpel Stupid! ;-)

2
  • I think you shoud mark this (your own) answer as accepted ... Commented Aug 26, 2017 at 11:14
  • can you share the full code ?
    – tasqyn
    Commented Mar 24, 2021 at 9:51
0

You should use #prefix and #suffix to add a wrapper around $form['loanDurationYears']. Your code would look like this:

$form['manufactureYear'] = array(
  '#type' => 'select',
  '#title' => $this->t('Manufacture year'),
  '#options' => $manufactureYears,
  '#required' => TRUE,
  '#ajax' => [
    'callback' => array($this, 'populateDurationYears'),
    'wrapper' => 'loanduration-wrapper'
  ],
);

$form['loanDurationYears'] = array(
  '#type' => 'select',
  '#title' => $this->t('Loan duration years'),
  '#prefix' => '<div id="loanduration-wrapper">',
  '#suffix' => '</div>',
);
4
  • it still gives the DIV tag inside the SELECT tag? The OPTION tags are there - but the DIV messes it up :-( Commented Apr 5, 2016 at 6:54
  • Do you get the same results if you use ReplaceCommand instead of AppendCommand?
    – Yusuf
    Commented Apr 5, 2016 at 6:58
  • The ReplaceCommand completly removes the <select> tag with the option tags. Commented Apr 5, 2016 at 7:08
  • I figured it out by myself - thank you very much for your time and effort. Commented Apr 5, 2016 at 8:52
0

The drupal core ajax.js will check the number of elements inside the string you pass to the response. The div container will only be added if you pass more than 1 element. Adding one option at a time will prevent this behaviour. In your case the correct way to go by ajax would be:

$response = new AjaxResponse();
if($maxDurationYears != 0) {
  for($i = $minLoanDurationYears-1; $i < $maxDurationYears; $i++) {
    $option = "<option value='" . (string)($i+1) . "'>" . (string)($i+1) . " år</option>";
    $response->addCommand(new AppendCommand('#edit-loandurationyears', $option));
  }
}
return $response;

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.