How to update the browser's query string with nested properties in a Livewire component

Viewed 1354

Here is an example of my component:

class ProductCatalogue extends Component
{
    public array $filters = [
        'search' => '',
        'product-category' => '',
        'product-type' => '',
        'product-composition' => '',
        'product-size' => '',
        'min-price' => null,
        'max-price' => null,
    ];

    protected $queryString = ['filters'];

    public function render()
    {
        return view('livewire.product-catalogue', [
            'products' => Product::query()
                ->when($this->filters['product-category'], function ($query) { ... }
                ->when($this->filters['product-type'], function ($query) { ... }
                ->when($this->filters['product-composition'], function ($query) { ... }
                ->when($this->filters['product-size'], function ($query) { ... }
                ->when($this->filters['min-price'], function ($query) { ... }
                ->when($this->filters['max-price'], function ($query) { ... }
                ->when($this->filters['search'], function ($query) { ... }
                ->paginate(10)
        ]);
    }
}

This works but then the query parameters are:

?filters%5Bsearch%5D=&filters%5Bproduct-category%5D=&filters%5Bproduct-type%5D=&filters%5Bproduct-composition%5D=&filters%5Bproduct-size%5D=&filters%5Bmin-price%5D=&filters%5Bmax-price%5D=

How can the $queryString property be set to output the following query parameters:

?search=&product-category=&product-type=&product-composition=&product-size=&min-price=&max-price

I've tried setting the $queryString property to:

protected $queryString = [
    'filters.search' => ['except' => ''],
    'filters.product-category' => ['except' => ''],
    'filters.product-type' => ['except' => ''],
    'filters.product-composition' => ['except' => ''],
    'filters.product-type' => ['except' => ''],
    'filters.min-price' => ['except' => null],
    'filters.max-price' => ['except' => null],
];

But that throws the following PropertyNotFoundException: Property [$filters.search] not found on component

Is it possible to do this or must each property be defined separately i.e. public string $search; etc.?

2 Answers

the best solution I found was:

protected $queryString = [
    'filters' => ['except' => [
        'search' => '',
        'product-category' => '',
        'product-composition' => '',
        'product-type' => '',
        'min-price' => '',
        'max-price' => '',
    ]],
];

This results in having a clean queryString as long as non of the nested properties is set. The other way around seams to be not supported (yet) or I simply didn't figured out how to do it.

Ther're a couple of discussions on GitHub around this topic.

https://github.com/livewire/livewire/discussions/2036

https://github.com/livewire/livewire/issues/1909

At this point, I suggest to stick with creating individual variables. Use camelCase

e.g.

public $search = '';
public $productCategory = '';
public $productType = '';
public $productComposition = '';
public $productSize = '';
public $minPrice = null;
public $maxPrice = null;


protected $queryString = [
    'search' => ['except' => ''],
    'productCategory' => ['except' => ''],
    'productType' => ['except' => ''],
    'productComposition' => ['except' => ''],
    'productSize' => ['except' => ''],
    'minPrice' => ['except' => null],
    'maxPrice' => ['except' => null],
];

This will give you expected result.

Related