Email us at info@henrytech.org to discuss your Drupal Migration today!
In the case that you need to have a form contained in a popup/modal window, that you also need to pass a parameter to, such as a specific node or entity id. In this case we are clicking on a link in a template file to open the form, and the entity id is available in the template file that has the link. You can also put such a link in a view, and pass it an id from the view. So you can have a view with a button for each row that references the ID from that row, that has a form that does something.
In your custom-template.html.twig file:
You can pass an ID here from the node or from a preprocess function.
<a class="custom-class use-ajax"
href="{{ path('your_custom_module.custom_form',
{'custom_parameter': fields.id.content|render|striptags|trim }) }}">
</a>
In your custom_module.routing.yml:
your_custom_entity_type here would be the entity type of the ID you are passing, i.e, node, etc.
your_custom_module.custom_form:
path: '/ajax/something/custom-form/{custom_parameter}'
defaults:
_controller: '\Drupal\your_custom_module\Controller\CustomController::customForm'
methods: ['POST']
requirements:
_access: 'TRUE'
options:
parameters:
custom_parameter:
type: entity:your_custom_entity_type
In your CustomController.php:
Here, the customForm function, referenced in the routing file, is defined, and the ajax response. We pass it the ID of the entity that we need for the form.
<?php
namespace Drupal\your_custom_module\Controller;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AppendCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\RemoveCommand;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityFormBuilderInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Session\AccountInterface;
class CustomController extends ControllerBase {
private function prepareFormResponse(int $id = 0): AjaxResponse {
$response = new AjaxResponse();
$form_state = new FormState();
$form_state->addBuildInfo('args', [$id]);
$form = $this->formBuilder->buildForm(CustomTrainingForm::class, $form_state);
$build = [
'#theme' => 'custom_theme',
'#title' => 'Your form Title',
'#body' => $form,
];
$response->addCommand(new RemoveCommand('.modal-ajax'));
$response->addCommand(new AppendCommand('body', $build));
$response->addCommand(new InvokeCommand('.modal-ajax', 'modal', ['show']));
return $response;
}
}
public function customForm(EntityClass $entity): AjaxResponse {
$id = (int) $entity->id();
return $this->prepareFormResponse($id);
}
In your CustomForm.php:
This is the actual form that is rendered inside the modal window.
<?php
namespace Drupal\your_custom_module\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\RedirectCommand;
use Drupal\Core\Ajax\AppendCommand;
use Drupal\Core\Ajax\RemoveCommand;
use Drupal\Core\Ajax\ReplaceCommand;
class CustomForm extends FormBase {
public function getFormId() {
return 'custom_form_id';
}
public function buildForm(array $form, FormStateInterface $form_state, int $id = 0) {
$user = \Drupal::currentUser();
$form['some_users_form_field'] = array(
'#type' => 'entity_autocomplete',
'#title' => t('Users'),
'#target_type' => 'user',
'#default_value' => '',
'#tags' => TRUE,
'#cache' => ['contexts' => ['user']],
);
// Actions.
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => 'Submit Form',
'#ajax' => [
'callback' => '::ajaxSubmit',
],
'#attributes' => [
'class' => ['use-ajax-submit'],
],
];
return $form;
}

Comments1
Thanks, very helpful
Thank you for posting, this saved me some time.