I have a custom module that uses a form in a block that will be displayed on a node page. This form is used to retrieve datas from a custom table. What I want to achieve is :
- The user arrives on the page : the form is displayed and the 10 lasts items retrieved from the database are also displayed
- The user selects a data via the form
- The user submits the form
- The node page containing the block is refresehed with the 10 new items retrieved from database. I also need the form to be displayed on top of the block with previously selected values selected
I've been able to create a form class extending the FormBase class. Then I've created a block extending BlockBase class. In the build method I get the form using the Drupal::formBuilder()->getForm() method
public function build(){
$form = \Drupal::formBuilder()->getForm('Drupal\my_module\Form\my_form');
return array(
'#theme' => 'my_theme',
'#form' => $form,
);
}
At that step, my node page + the block containing the form is correctly displayed, but I've not been able to render the default 10 last items. I've no idea on how to achieve this since the buildForm method of the form class is supposed to return an array to render the form. I've tried to implement it in the build method of my block :
return array(
'#theme' => 'my_theme',
'#items' => $items,
'#form' => $form,
);
It works, but after form submission, those first 10 default items are always displayed because the block build them on every refresh. Is there a way to know if the included form has been submitted ?
Concerning the form validation, redirection is definitly not the way I should go since a need the results of the database query to be displayed in the same page / block.
Based on this topic, I feel the $form_state->setRebuild() / $form_state->isRebuilding() methods are the way to go. Do you confirm ?
I've been able to refresh the item list after form submission doing so :
if ($form_state->isRebuilding()) {
$myfield_value = $form_state->getValue('myfield ');
$model = Drupal::service('my_module.model');
$items = $model->getLastItems(10, $myfield_value );
return array(
'#theme' => 'my_theme',
'#form' => $form,
'#items' => $items,
);
}
This works, but only half of the time the form is submitted. The second time it's like it never passes in the if($form_state->isRebuilding()) {} statement. Moreover, the results are nested in the form markup. Maybe it's not the proper way to inject the form...
For information here is an example of my twig markup :
{{ form }}
<div class="row">
{% for track in tracks %}
{# print stuff...#}
{% endfor %}
</div>
To be able to inject the form in the if($form_state->isRebuilding()) statement of the buildForm of the form class, I must wait the form array is completly defined in code... Doing so, I'm unable to set fields values to the ones the user has submitted.
In brief, my questions are :
- How can I populate the default items list before the form is submitted ?
- How can I properly inject the form from the if($form_state->isRebuilding() statement, so that everything works
- How can I set the fields selected values after form submission.
Sorry for this long post, but I'm quite new to the drupal ecosystem, so any help would be greatly appreciated !...
Cheers
PS : I've also read about the BlockBase::blockForm and BlockBase::blockSubmit methods, but as far as I understand, it's more about block configuration froms. Does somebody confirm that ?