I’ve created a module which defines a Form, but when I try to add a column of links, it is empty when I set the '#type'
to 'link'
. I am testing this on Drupal 9.3.x.
On the surface, this is the same as this question, but the answer posted there does not contain the full working code, and I’m fairly sure the solution in my context is going to differ from the one posted there.
Here is the full code of my class which extends FormBase:
use DrupalCoreFormFormBase; use DrupalCoreFormFormStateInterface; class MyForm extends FormBase { public function buildForm(array $form, DrupalCoreFormFormStateInterface $form_state) { // Build the fileNameOptions $privatePath = 'private://webform/upload/'; $linkPath = '/system/files/webform/upload/'; $templatePath = Drupal::service('file_system')->realpath($privatePath); $fileList = glob($templatePath.'/*'); $fileNameOptions = []; $pathLength = strlen($templatePath); foreach ($fileList as $filePath) { $fileName = substr($filePath, $pathLength + 1); $fileNameOptions[$fileName] = [ 'filename' => $fileName, 'link' => [ 'data' => [ '#type' => 'link', '#url' => $linkPath . $fileName, '#title' => $fileName, ], ], ]; } //Build the tableSelect. $form['templates'] = [ '#type' => 'tableselect', '#header' => ['filename' => 'File name', 'link' => 'Link'], '#options' => $fileNameOptions, '#empty' => t('No files were found.'), '#weight' => 40, '#js_select' => FALSE, ]; return $form; } /** * {@inheritdoc} */ public function getFormId() { return 'my_form'; } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { parent::submitForm($form, $form_state); } }
For some context, this form is attempting to show the admin a list of private files uploaded from webforms, plus links enabling them to inspect each file. The intent is to use the tableselect
to allow the admin to delete unwanted files. I understand that there are security implications, and that this form should only be accessible to trusted admins. Showing the list of files works, and I’m fairly sure I can get the file deletion working. I have a webform which displays the links correctly, but it would be a better user experience if the deletion form also allows the admin to view the files through links.
If I change the '#type'
of the link field from 'link'
to 'textfield'
or 'textarea'
, the column contains the elements I would expect – the title followed by a textfield or textarea. When I change the '#type'
back to 'link'
(as shown in the code above), the column is completely empty. When I view the page source, that column contains empty td
tags:
<td></td>
It’s exactly the same as if I change the '#type'
to 'foo'
. This implies to me that the 'link'
field type is not available in the context of this form. To test this, I tried to adapt this answer to the Drupal 9 context, something like:
$all_types = Drupal::moduleHandler()->invokeAll('hook_elements'); Drupal::messenger()->addMessage(json_encode($all_types));
However, hook_elements
does not seem to exist any more, so this doesn’t work.
This document appears to show 'link'
as a valid "form and render element" in Drupal 9.4.x, so my understanding is that it should be available in forms created by a custom module.
This code from the CommentAdminOverview core module appears to show very similar use of '#type' => 'link'
.
I would post a comment on the existing question, but I don’t have enough reputation on this site to do so. Also, my reading of that answer indicates that the problem there was that the column was not added to the '#header'
array (not visible in the code posted).
My questions are:
- Have I missed some simple detail in the code I’ve posted above, which causes
'link'
fields to be empty, while changing the'#type'
to'textfield'
produces the expected result? - Is there some way to verify the set of valid
'#type'
strings in my context? - If the
'link'
field type is not available in my context, how can I make it available?
Edit: Nothing is added to the Drupal log when I load this form.
Any help would be appreciated, and I’m happy to add more information if I’ve missed anything.