Description
Hello,
Currently, imagine you have a page with a FacetMenu LC and another ArticleResult LC. FacetMenu write and read the URL query params (searchTerm, status, page, ...), and ArticleResult read them.
When you first load your page with some query params, everything is OK; Both components are able to read the query params. But when I modify an input in the facet menu, here how I make it work for now:
#[AsLiveComponent]
class FacetMenu
{
use DefaultActionTrait;
use ComponentToolsTrait;
#[LiveProp(writable: true, url: true, onUpdated: 'onChange')]
public string $name = '';
#[LiveProp(writable: true, url: true, onUpdated: 'onChange')]
public string $status = '';
#[LiveProp(writable: true, url: true, onUpdated: 'onChange')]
public int $page = 1;
#[LiveAction]
public function reset(): void
{
$this->name = '';
$this->status = '';
$this->page = 1;
$this->onChange();
}
#[PostMount]
public function onChange(): void
{
$this->page = 1;
$this->emit(
'facetSetted',
array_filter(
get_object_vars($this),
fn($value, $key) => in_array($key, ['name', 'status', 'page']),
ARRAY_FILTER_USE_BOTH
)
);
}
}
#[AsLiveComponent]
class ArticleResults
{
use DefaultActionTrait;
use ComponentToolsTrait;
#[LiveProp(url: true)]
public ?string $name = null;
#[LiveProp(url: true)]
public ?string $status = null;
#[LiveProp(url: true)]
public ?int $page = 1;
private ItemsPage $articlesPage;
public function __construct(private readonly QueryBus $queryBus) {}
#[LiveListener('facetSetted')]
public function reload(
#[LiveArg] string $name,
#[LiveArg] string $status,
#[LiveArg] int $page,
): void {
$this->name = $name;
$this->status = $status;
$this->page = $page;
$this->getArticlesPage();
}
public function getArticlesPage(): ItemsPage
{
return $this->articlesPage ??= $this->searchArticles();
}
private function searchArticles(): ItemsPage
{
$filter = new Filter(
$this->page,
$this->name,
$this->status
);
return $this->queryBus->query(new GetArticlesPaginated($filter));
}
}
- a
#[PostMount] public function onChange(): void
method emits an event with the whole inputs as an associative array, - the ArticleResult LC has a method with
#[LiveListener('emitedFromFacet')]
method, that welcome all the parameters with #[LiveArg]. properties. Then, it defines each $this->givenProperty to force the LC at the same state than when it reads the URL (example of property:#[LiveProp(writable: true, url: true)] public ?string $status = null;
), then call the method to do the logic.
I feel like packing properties from SearchMenu, serializing them to send them through JS, then recall them one by one as method parameters, and reallocate them before doing logic, is rewriting each property basically 3 times, for components that already know about the properties, as they welcome them from URL when first loading.
So do you know a way to tell, before doing logic in a given method, to "re-read" the url as it can have changed? Or do you see another way to achieve this? I know about the UX icons implementation, but the search bar AND the results div are on the same component; So another way to ask my question is "how would you design the icons page if you have to do 2 separate components for SearchBar and IconResults? How would you pass the parameters between them?"
- change the behavior of "url:true" LiveProps to check again the values from the URL when re-render?
- propose a readUrl() method (maybe make a UrlTrait) that will make the component re-read the URL and re-hydrate the LiveProps?
Part of the discussion about #2212 (challenge point 2).