Skip to content

Commit 4f0d313

Browse files
squriousweaverryan
authored andcommitted
Add doc for URL binding feature
1 parent 524ac5a commit 4f0d313

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

src/LiveComponent/doc/index.rst

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,6 +2081,8 @@ then render it manually after:
20812081

20822082
{{ form_widget(form.todoItems.vars.button_add, { label: '+ Add Item', attr: { class: 'btn btn-outline-primary' } }) }}
20832083

2084+
.. _validation:
2085+
20842086
Validation (without a Form)
20852087
---------------------------
20862088

@@ -2302,6 +2304,130 @@ You can also trigger a specific "action" instead of a normal re-render:
23022304
#}
23032305
>
23042306

2307+
Changing the URL when a LiveProp changes
2308+
----------------------------------------
2309+
2310+
.. versionadded:: 2.14
2311+
2312+
The ``url`` option was introduced in Live Components 2.14.
2313+
2314+
If you want the URL to update when a ``LiveProp`` changes, you can do that with the ``url`` option::
2315+
2316+
// src/Components/SearchModule.php
2317+
namespace App\Components;
2318+
2319+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
2320+
use Symfony\UX\LiveComponent\Attribute\LiveProp;
2321+
use Symfony\UX\LiveComponent\DefaultActionTrait;
2322+
2323+
#[AsLiveComponent]
2324+
class SearchModule
2325+
{
2326+
use DefaultActionTrait;
2327+
2328+
#[LiveProp(writable: true, url: true)]
2329+
public string $query = '';
2330+
}
2331+
2332+
Now, when the user changes the value of the ``query`` prop, a query parameter in the URL will be updated to reflect the
2333+
new state of your component, for example: ``https://my.domain/search?query=my+search+string``.
2334+
2335+
If you load this URL in your browser, the ``LiveProp`` value will be initialized using the query string
2336+
(e.g. ``my search string``).
2337+
2338+
.. note::
2339+
2340+
The URL is changed via ``history.replaceState()``. So no new entry is added.
2341+
2342+
.. warning::
2343+
2344+
You can use multiple components with URL bindings in the same page, as long as bound field names don't collide.
2345+
Otherwise, you will observe unexpected behaviors.
2346+
2347+
Supported Data Types
2348+
~~~~~~~~~~~~~~~~~~~~
2349+
2350+
You can use scalars, arrays and objects in your URL bindings:
2351+
2352+
============================================ =================================================
2353+
JavaScript ``prop`` value URL representation
2354+
============================================ =================================================
2355+
``'some search string'`` ``prop=some+search+string``
2356+
``42`` ``prop=42``
2357+
``['foo', 'bar']`` ``prop[0]=foo&prop[1]=bar``
2358+
``{ foo: 'bar', baz: 42 }`` ``prop[foo]=bar&prop[baz]=42``
2359+
2360+
2361+
When a page is loaded with a query parameter that's bound to a ``LiveProp`` (e.g. ``/search?query=my+search+string``),
2362+
the value - ``my search string`` - goes through the hydration system before it's set onto the property. If a value can't
2363+
be hydrated, it will be ignored.
2364+
2365+
Multiple Query Parameter Bindings
2366+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2367+
2368+
You can use as many URL bindings as you want in your component. To ensure the state is fully represented in the URL,
2369+
all bound props will be set as query parameters, even if their values didn't change.
2370+
2371+
For example, if you declare the following bindings::
2372+
2373+
// ...
2374+
#[AsLiveComponent]
2375+
class SearchModule
2376+
{
2377+
#[LiveProp(writable: true, url: true)]
2378+
public string $query = '';
2379+
2380+
#[LiveProp(writable: true, url: true)]
2381+
public string $mode = 'fulltext';
2382+
2383+
// ...
2384+
}
2385+
2386+
2387+
And you only set the ``query`` value, then your URL will be updated to
2388+
``https://my.domain/search?query=my+query+string&mode=fulltext``.
2389+
2390+
Validating the Query Parameter Values
2391+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2392+
2393+
Like any writable ``LiveProp``, because the user can modify this value, you should consider adding
2394+
:ref:`validation <validation>`. When you bind a ``LiveProp`` to the URL, the initial value is not automatically
2395+
validated. To validate it, you have to set up a `PostMount hook`_::
2396+
2397+
// ...
2398+
use Symfony\Component\Validator\Constraints as Assert;
2399+
use Symfony\UX\LiveComponent\ValidatableComponentTrait;
2400+
use Symfony\UX\TwigComponent\Attribute\PostMount;
2401+
2402+
#[AsLiveComponent]
2403+
class SearchModule
2404+
{
2405+
use ValidatableComponentTrait;
2406+
2407+
#[LiveProp(writable: true, url: true)]
2408+
public string $query = '';
2409+
2410+
#[LiveProp(writable: true, url: true)]
2411+
#[Assert\NotBlank]
2412+
public string $mode = 'fulltext';
2413+
2414+
#[PostMount]
2415+
public function postMount(): void
2416+
{
2417+
// Validate 'mode' field without throwing an exception, so the component can be mounted anyway and a
2418+
// validation error can be shown to the user
2419+
if (!$this->validateField('mode', false)) {
2420+
// Do something when validation fails
2421+
}
2422+
}
2423+
2424+
// ...
2425+
}
2426+
2427+
.. note::
2428+
2429+
You can use `validation groups`_ if you want to use specific validation rules only in the PostMount hook.
2430+
23052431
.. _emit:
23062432

23072433
Communication Between Components: Emitting Events
@@ -3315,3 +3441,5 @@ bound to Symfony's BC policy for the moment.
33153441
.. _`Symfony's built-in form theming techniques`: https://symfony.com/doc/current/form/form_themes.html
33163442
.. _`pass content to Twig Components`: https://symfony.com/bundles/ux-twig-component/current/index.html#passing-blocks
33173443
.. _`Twig Component debug command`: https://symfony.com/bundles/ux-twig-component/current/index.html#debugging-components
3444+
.. _`PostMount hook`: https://symfony.com/bundles/ux-twig-component/current/index.html#postmount-hook
3445+
.. _`validation groups`: https://symfony.com/doc/current/form/validation_groups.html

0 commit comments

Comments
 (0)