I have created a recursive category display using Livewire 3.x and AlpineJS 3.x The categories are stored in the database. Everything is working except for the activeDropdown function. When I open a parent category and click on a child category inside it, the parent category does not remain open.
How can I solve this so that it stays open?
Thank you.
Source code:
resources\views\livewire\category-navigation.blade.php
<div x-data="sidebar" class="sidebar z-50 transition-all duration-300">
<div class="bg-white">
<ul class="p-4 py-0" x-data="{ activeDropdown: null }">
@foreach ($categories as $category)
@if ($category->children->count() > 0)
<li class="nav-item">
<ul>
<li class="nav-item">
<button type="button" class="nav-link group"
:class="{ 'active': activeDropdown === '{{ $category->slug }}' }"
@click="activeDropdown === '{{ $category->slug }}' ? activeDropdown = null : activeDropdown = '{{ $category->slug }}'">
<div class="flex items-center">
<span class="text-black">
{{ $category->name }}
</span>
</div>
<div class="" :class="{ '!rotate-90': activeDropdown === '{{ $category->slug }}' }">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
xmlns=";>
<path d="M9 5L15 12L9 19" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</div>
</button>
<ul x-cloak x-show="activeDropdown === '{{ $category->slug }}'" x-collapse class="sub-menu text-gray-500" @click.away="activeDropdown = null" @click.stop>
@foreach ($category->children as $child)
@include('livewire.category-item', ['category' => $child])
@endforeach
</ul>
</li>
</ul>
</li>
@else
<li class="nav-item">
<a href="{{ url($category->full_path) }}" wire:click.prevent="navigateToCategory('{{ $category->full_path }}')" class="nav-link group"
:class="{ 'active': '{{ request()->routeIs("products.byCategory") && request()->route("slug") == $category->slug ? "active" : "" }}'}">
<div class="flex items-center">
<span class="text-black">{{ $category->name }} ({{ $category->products()->count() }})</span>
</div>
</a>
</li>
@endif
@endforeach
</ul>
</div>
</div>
resources\views\livewire\category-item.blade.php
@if ($category->children->count() > 0)
<li x-data="{ subActive: null }">
<button type="button"
class="before:bg-gray-300 before:w-[5px] before:h-[5px] before:rounded before:mr-2 hover:bg-gray-100"
:class="{ 'active': subActive === '{{ $category->slug }}' }"
@click.stop="subActive === '{{ $category->id }}' ? subActive = null : subActive = '{{ $category->slug }}'">
{{ $category->name }}
<div class="ml-auto" :class="{ '!rotate-90': subActive === '{{ $category->slug }}' }">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
xmlns=";>
<path d="M9 5L15 12L9 19" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</div>
</button>
<ul class="sub-menu text-gray-500 ml-4" x-show="subActive === '{{ $category->slug }}'" x-collapse>
@foreach ($category->children as $child)
@include('livewire.category-item', ['category' => $child]) <!-- REKURZÍV hívás -->
@endforeach
</ul>
</li>
@else
<li>
<a href="{{ url($category->full_path) }}" wire:click.prevent="navigateToCategory('{{ $category->full_path }}')">{{ $category->name }} ({{ $category->products()->count() }})</a>
</li>
@endif
Js code:
document.addEventListener("alpine:init", () => {
Alpine.data("sidebar", () => ({
init() {
const selector = document.querySelector('.sidebar ul a[href="' + window.location.href + '"]');
if (selector) {
selector.classList.add('active');
const ul = selector.closest('ul.sub-menu');
if (ul) {
let ele = ul.closest('li.menu').querySelectorAll('.nav-link');
if (ele) {
ele = ele[0];
setTimeout(() => {
ele.click();
});
}
}
}
},
}));
});