This Bundle provides Twig and Symfony form helper functions for Stimulus.js.
- Twig helper functions
- Symfony Forms helper functions
Open a command console, enter your project directory and execute the following command to download this bundle:
$ composer require hello-sebastian/hello-stimulus-bundle
Then, enable the bundle by adding it to the list of registered bundles in the config/bundles.php
file of your project:
// config/bundles.php
return [
// ...
HelloSebastian\HelloStimulusBundle\HelloStimulusBundle::class => ['all' => true],
];
Render value controller attribute. Optional with values.
controllerName: name of the controller
values: array of stimulus values (optional)
<div {{ hello_stimulus_controller('hello') }}></div>
<div {{ hello_stimulus_controller('hello', [
{name: 'myValue', value: 'Hey!'},
{name: 'myNumber', value: 1234}
]) }}></div>
is rendered to
<div data-controller="hello"></div>
<div data-controller="hello" data-hello-my-value-value="Hey!" data-hello-my-number-value="1234"></<div>
You can use two ways to specify the controller:
Assuming the controller is located at assets/controllers/user/user_form_controller.js
-
the "HTML" stimulus type
<div {{ hello_stimulus_controller('user--user-form') }}></div> {# rendered to data-controller="user--user-form" #}
-
the "JavaScript" type
<div {{ hello_stimulus_controller('user/user_form') }}></div> {# rendered to data-controller="user--user-form" #}
Both variants give the same result.
Render value target attribute.
controllerName: name of controller for this target
target: name of the target attribute
<h1 {{ hello_stimulus_target('hello', 'greeting') }}></h1>
is rendered to
<div data-hello-target="greeting"></div>
Render action data attribute.
controllerName: name of controller for this action
event: DOM event to listen for
method: name of the JavaScript method inside the controller class
<button type="button" {{ hello_stimulus_action('hello', 'click', 'handleBtnClick') }}>
Hey!
</button>
is rendered to
<button type="button" data-action="click->hello#handleBtnClick">
Hey!
</button>
Render value data attribute.
controllerName: name of controller for this value
name: name of this value
value: value of this value
<div {{ hello_stimulus_value('hello', 'username', 'hello_sebastian') }}></div>
is rendered to
<div data-hello-username-value="hello_sebastian"></div>
In Symfony Forms it is helpful to pass attributes of stimulus directly to the types. For this purpose, this bundle provides a helper class with two methods (target()
and value()
).
Full example of StimulusFormHelper
controllerName: name (and location) of the JavaScript controller class
defaultEvent: (optional): default DOM event to listen for (default is the "click" event)
You can use two ways to specify the controller:
Assuming the controller is located at assets/controllers/user/user_form_controller.js
-
the "HTML" stimulus type
$this->formController = new StimulusFormHelper('user--user-form'); // rendered to data-controller="user--user-form" to the form tag
-
the "JavaScript" type
$this->formController = new StimulusFormHelper('user/user_form'); // rendered to data-controller="user--user-form" to the form tag
Both variants give the same result.
target: name of target property inside stimulus controller
array("data-[controllerName]-target" => "[target]");
->add('firstName', TextType::class, array(
'label' => 'First name',
'attr' => $this->formController->target('firstNameInput')
))
method: name of JavaScript method inside stimulus controller
event: (optional) DOM event to listen for (if null, default event from constructor is taken)
array("data-action" => "[event]->[controllerName]#[method]");
->add('isActive', CheckboxType::class, array(
'label' => 'is Active',
'required' => false,
'attr' => $this->formController->action("handleIsActive", "change")
))
//src/Form
namespace App\Form;
use App\Entity\User;
use HelloSebastian\HelloStimulusBundle\Form\StimulusFormHelper; // <-- don't forget this use statement
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserType extends AbstractType
{
private $userFormController;
public function __construct()
{
$this->formController = new StimulusFormHelper('user-form');
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstName', TextType::class, array(
'label' => 'First name',
'attr' => $this->formController->target('firstNameInput')
))
->add('lastName', TextareaType::class, array(
'label' => 'Last name',
'label_attr' => $this->formController->target('lastNameLabel')
'attr' => $this->formController->target('lastNameInput')
))
->add('email', TextareaType::class, array(
'label' => 'Email'
))
->add('isActive', CheckboxType::class, array(
'label' => 'is Active',
'required' => false,
// if you want to use both inside the same attr, you can use array_merge()
'attr' => array_merge(
$this->formController->action("handleIsActive", "change"),
$this->formController->target("isActiveCheckbox"),
array('class' => 'my-checkbox-class')
)
))
;
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$this->formController->setControllerNameToFormView($view);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
));
}
}
action
and traget
return an array. If you want to use both inside the same attr
, you can use array_merge()
.