@@ -2083,6 +2083,8 @@ then render it manually after:
20832083
20842084 {{ form_widget(form.todoItems.vars.button_add, { label: '+ Add Item', attr: { class: 'btn btn-outline-primary' } }) }}
20852085
2086+ .. _validation :
2087+
20862088Validation (without a Form)
20872089---------------------------
20882090
@@ -2304,6 +2306,130 @@ You can also trigger a specific "action" instead of a normal re-render:
23042306 #}
23052307 >
23062308
2309+ Changing the URL when a LiveProp changes
2310+ ----------------------------------------
2311+
2312+ .. versionadded :: 2.14
2313+
2314+ The ``url `` option was introduced in Live Components 2.14.
2315+
2316+ If you want the URL to update when a ``LiveProp `` changes, you can do that with the ``url `` option::
2317+
2318+ // src/Components/SearchModule.php
2319+ namespace App\Components;
2320+
2321+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
2322+ use Symfony\UX\LiveComponent\Attribute\LiveProp;
2323+ use Symfony\UX\LiveComponent\DefaultActionTrait;
2324+
2325+ #[AsLiveComponent]
2326+ class SearchModule
2327+ {
2328+ use DefaultActionTrait;
2329+
2330+ #[LiveProp(writable: true, url: true)]
2331+ public string $query = '';
2332+ }
2333+
2334+ Now, when the user changes the value of the ``query `` prop, a query parameter in the URL will be updated to reflect the
2335+ new state of your component, for example: ``https://my.domain/search?query=my+search+string ``.
2336+
2337+ If you load this URL in your browser, the ``LiveProp `` value will be initialized using the query string
2338+ (e.g. ``my search string ``).
2339+
2340+ .. note ::
2341+
2342+ The URL is changed via ``history.replaceState() ``. So no new entry is added.
2343+
2344+ .. warning ::
2345+
2346+ You can use multiple components with URL bindings in the same page, as long as bound field names don't collide.
2347+ Otherwise, you will observe unexpected behaviors.
2348+
2349+ Supported Data Types
2350+ ~~~~~~~~~~~~~~~~~~~~
2351+
2352+ You can use scalars, arrays and objects in your URL bindings:
2353+
2354+ ============================================ =================================================
2355+ JavaScript ``prop `` value URL representation
2356+ ============================================ =================================================
2357+ ``'some search string' `` ``prop=some+search+string ``
2358+ ``42 `` ``prop=42 ``
2359+ ``['foo', 'bar'] `` ``prop[0]=foo&prop[1]=bar ``
2360+ ``{ foo: 'bar', baz: 42 } `` ``prop[foo]=bar&prop[baz]=42 ``
2361+
2362+
2363+ When a page is loaded with a query parameter that's bound to a ``LiveProp`` (e.g. ``/search?query=my+search+string``),
2364+ the value - ``my search string `` - goes through the hydration system before it's set onto the property. If a value can't
2365+ be hydrated, it will be ignored.
2366+
2367+ Multiple Query Parameter Bindings
2368+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2369+
2370+ You can use as many URL bindings as you want in your component. To ensure the state is fully represented in the URL,
2371+ all bound props will be set as query parameters, even if their values didn't change.
2372+
2373+ For example, if you declare the following bindings::
2374+
2375+ // ...
2376+ #[AsLiveComponent]
2377+ class SearchModule
2378+ {
2379+ #[LiveProp(writable: true, url: true)]
2380+ public string $query = '';
2381+
2382+ #[LiveProp(writable: true, url: true)]
2383+ public string $mode = 'fulltext';
2384+
2385+ // ...
2386+ }
2387+
2388+
2389+ And you only set the ``query `` value, then your URL will be updated to
2390+ ``https://my.domain/search?query=my+query+string&mode=fulltext ``.
2391+
2392+ Validating the Query Parameter Values
2393+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2394+
2395+ Like any writable ``LiveProp ``, because the user can modify this value, you should consider adding
2396+ :ref: `validation <validation >`. When you bind a ``LiveProp `` to the URL, the initial value is not automatically
2397+ validated. To validate it, you have to set up a `PostMount hook `_::
2398+
2399+ // ...
2400+ use Symfony\Component\Validator\Constraints as Assert;
2401+ use Symfony\UX\LiveComponent\ValidatableComponentTrait;
2402+ use Symfony\UX\TwigComponent\Attribute\PostMount;
2403+
2404+ #[AsLiveComponent]
2405+ class SearchModule
2406+ {
2407+ use ValidatableComponentTrait;
2408+
2409+ #[LiveProp(writable: true, url: true)]
2410+ public string $query = '';
2411+
2412+ #[LiveProp(writable: true, url: true)]
2413+ #[Assert\NotBlank]
2414+ public string $mode = 'fulltext';
2415+
2416+ #[PostMount]
2417+ public function postMount(): void
2418+ {
2419+ // Validate 'mode' field without throwing an exception, so the component can be mounted anyway and a
2420+ // validation error can be shown to the user
2421+ if (!$this->validateField('mode', false)) {
2422+ // Do something when validation fails
2423+ }
2424+ }
2425+
2426+ // ...
2427+ }
2428+
2429+ .. note ::
2430+
2431+ You can use `validation groups `_ if you want to use specific validation rules only in the PostMount hook.
2432+
23072433.. _emit :
23082434
23092435Communication Between Components: Emitting Events
@@ -3317,3 +3443,5 @@ bound to Symfony's BC policy for the moment.
33173443.. _`Symfony's built-in form theming techniques` : https://symfony.com/doc/current/form/form_themes.html
33183444.. _`pass content to Twig Components` : https://symfony.com/bundles/ux-twig-component/current/index.html#passing-blocks
33193445.. _`Twig Component debug command` : https://symfony.com/bundles/ux-twig-component/current/index.html#debugging-components
3446+ .. _`PostMount hook` : https://symfony.com/bundles/ux-twig-component/current/index.html#postmount-hook
3447+ .. _`validation groups` : https://symfony.com/doc/current/form/validation_groups.html
0 commit comments