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;
1

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! ;-)

  • I think you shoud mark this (your own) answer as accepted ... – Pierre.Vriens Aug 26 '17 at 11:14
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>',
);
  • it still gives the DIV tag inside the SELECT tag? The OPTION tags are there - but the DIV messes it up :-( – Lars Hansen Apr 5 '16 at 6:54
  • Do you get the same results if you use ReplaceCommand instead of AppendCommand? – Yusuf Apr 5 '16 at 6:58
  • The ReplaceCommand completly removes the <select> tag with the option tags. – Lars Hansen Apr 5 '16 at 7:08
  • I figured it out by myself - thank you very much for your time and effort. – Lars Hansen Apr 5 '16 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, privacy policy and cookie policy

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