What I want to do
I want to display a custom form with a custom template and use ajax in it to change values in the form.
Problem
Custom template notation prevents ajax from working.
I didn't change anything in php, just twig, and tried 2 patterns as shown below.
In twig1, when I changed the value of "a", the value of "b" became "hogehoge" and the log was output.
However, in twig2, the value of b was not changed even if the value of a was changed, and there was no "update" in the log.
!!Both of the name of templates are "sampleexample.html.twig", and both of them are rendered.
SampleForm2.php
<?php
namespace Drupal\sampleexample\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Ajax\ReplaceCommand;
class SampleForm2 extends FormBase {
/**
* Current user account.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* Node storage.
*
* @var \Drupal\node\NodeStorageInterface
*/
protected $nodeManager;
protected $taxonomanager;
/**
* {@inheritdoc}
*/
public function __construct(
EntityTypeManager $entity_type_manager,
AccountProxyInterface $current_user
) {
$this->currentUser = $current_user;
$this->nodeManager = $entity_type_manager->getStorage('node');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
$container->get('current_user')
);
}
/**
* {@inheritdoc}
*/
public function getFormId(){
return 'sampleform2';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['#theme'] = 'sampleexample';
$form['a'] = [
'#type' => 'textfield',
'#size' => '60',
'#ajax' => [
'callback' => '::myAjaxCallback', // don't forget :: when calling a class method.
'disable-refocus' => FALSE, // Or TRUE to prevent re-focusing on the triggering element.
'event' => 'change',
'progress' => [
'type' => 'throbber',
'message' => $this->t('Verifying entry...'),
],
]
];
$form['b'] = [
'#type' => 'textfield',
'#size' => '60',
];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Save data'),
];
return $form;
}
function myAjaxCallback(array &$form, FormStateInterface $form_state, Request $request) {
/** @var \Drupal\Core\Ajax\AjaxResponse $response */
$response = new AjaxResponse();
\Drupal::logger('b')->notice('update');
$form['b']['#value'] = $this->t('hogehoge');
$response
->addCommand(new ReplaceCommand(".form-item--b", $form['b']));
return $response;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
}
twig1
{{ form_build_id }}
{{ form_token }}
{{ form_id }}
{{ form }}
twig2
{{ form_build_id }}
{{ form_token }}
{{ form_id }}
{{ form.a }}
{{ form.b }}
{{ form.actions.submit }}
Points of concern
I checked if there is any difference in the dom displayed on the page when using twig1 and twig2 respectively. I found that
<input autocomplete="off" data-drupal-selector="form-if-9dbyv7ohy9odmuog4qlckk6aemou8w5bnljfhobi"
type="hidden" name="form_build_id" value="form-If-9Dbyv7ohY9oDmUOG4qLCkk6AemOu8w5bnlJFHObI">
<input data-drupal-selector="edit-sampleform2-form-token" type="hidden" name="form_token"
value="gjDpTprqywwq9hMaizsiaL6YU300vcJJ36FRW_o2sFM">
<input data-drupal-selector="edit-sampleform2" type="hidden" name="form_id" value="sampleform2">
And the callback is written differently.
twig1
"ajax":{"edit-a":{"callback":"::myAjaxCallback","disable-refocus":false,"event":"change","progress":{"type":"throbber","message":"Verifying entry..."},
twig2
"ajax":{"edit-a":{"callback":"Drupal\\sampleexample\\Form\\SampleForm2::myAjaxCallback","disable-refocus":false,"event":"change","progress":{"type":"throbber","message":"Verifying entry..."},