Issue: Routes showing wrong active #20
Replies: 2 comments 2 replies
-
I have the same 'problem', but this is how it was designed. On What I did is extending the Navigation class and inject a custom <?php
namespace App\Helpers;
use Spatie\Navigation\Helpers\ActiveUrlChecker;
class Navigation extends \Spatie\Navigation\Navigation
{
/**
* Override the constructor to inject a custom ActiveUrlChecker.
*/
public function __construct()
{
$activeUrlChecker = new ActiveUrlChecker(request()->url(), '/admin');
return parent::__construct($activeUrlChecker);
}
} |
Beta Was this translation helpful? Give feedback.
-
For resources this happens too 😕 SetupFor example: // web.php
Route::resource('products', 'ProductController'); Which results in:
I render the navigation like this: Navigation::make()
->add('Home', route('home'))
->add('Product', '', function (Section $section) {
// or
->add('Product', route('products.index'), function (Section $section) { // Same result
$section->add('Index', route('products.index'));
$section->add('Create', route('products.create'));
}); The problemBut no matter if I navigate to
Unless I do it like this: $navigation = new Navigation(new ActiveUrlChecker($request->url(), '/products')); But that would make no sense, because "/products" is only the root for this resource. That would mean I need to make a script to dynamically resolve the route resource prefix and apply that to the ActiveUrlChecker.... After some digging around I found out that this is caused by this part: When removing WorkaroundThe workaround for this appears to be to copy the // app\Support\ActiveUrlChecker.php
// Copy of Spatie\Navigation\Helpers\ActiveUrlChecker with changes:
-if ($matchPath === $itemPath || Str::startsWith($matchPath, $itemPath)) {
+if ($matchPath === $itemPath) { Full example: Click to expand// app\Support\ActiveUrlChecker.php
namespace App\Support;
use Spatie\Navigation\Helpers\ActiveUrlChecker as BaseActiveUrlChecker;
use Spatie\Url\Url;
use Spatie\Navigation\Helpers\Str;
class ActiveUrlChecker extends BaseActiveUrlChecker
{
private string $requestUrl;
private string $rootPath;
public function __construct(string $requestUrl, string $rootPath = '/')
{
$this->requestUrl = $requestUrl;
$this->rootPath = $rootPath;
}
public function check(string $url): bool
{
$url = Url::fromString($url);
$requestUrl = Url::fromString($this->requestUrl);
// If the hosts don't match, this url isn't active.
if ($url->getHost() !== $requestUrl->getHost()) {
return false;
}
$rootPath = Str::ensureLeft('/', $this->rootPath);
// All paths used in this method should be terminated by a /
// otherwise startsWith at the end will be too greedy and
// also matches items which are on the same level
$rootPath = Str::ensureRight('/', $rootPath);
$itemPath = Str::ensureRight('/', $url->getPath());
// If this url doesn't start with the rootPath, it's inactive.
if (! Str::startsWith($itemPath, $rootPath)) {
return false;
}
$matchPath = Str::ensureRight('/', $requestUrl->getPath());
// For the next comparisons we just need the paths, and we'll remove
// the rootPath first.
$itemPath = Str::removeFromStart($rootPath, $itemPath);
$matchPath = Str::removeFromStart($rootPath, $matchPath);
dump([$matchPath, $itemPath], ($matchPath === $itemPath));
// If this url starts with the url we're matching with, it's active.
if ($matchPath === $itemPath) {
return true;
}
return false;
}
} Making use of this class: use App\Support\ActiveUrlChecker;
$navigation = new Navigation(new ActiveUrlChecker($request->url(), $optionalPrefix = '/')); or use @jeffreyvanhees's answer with the local class. ConclusionIf this isn't intended behavior or if this behavior should be preferred to be optional (by adding something like an |
Beta Was this translation helpful? Give feedback.
-
Sorry for posting this here, but I can't post an issue on this repo without it wanting me to open a pull request.
I'm having an issue with the plugin reporting the incorrect active element.
Say I have two top-level menu options (no child objects):
Admin (url: /admin)
User Management (url: /admin/users)
$nav = Navigation::make() ->add('Dashboard', route('admin.dash'), fn($s) => $s->attributes(['icon' => 'fa-duotone fa-house-tree'])) ->add('User Management', route('admin.show.users'), fn($s) => $s->attributes(['icon' => 'fa-duotone fa-users-gear'])) ->tree(); return view('livewire.component.admin.dash-nav', ['navbar' => $nav]);
If I'm on the user management page, it always shows admin as active=true, but User Management is active=false.
If I add the User Management menu item first, then the Admin item, it works as expected, though I need to output the navigation item to my controller with array_reverse() -- which isn't ideal.
$nav = Navigation::make() ->add('User Management', route('admin.show.users'), fn($s) => $s->attributes(['icon' => 'fa-duotone fa-users-gear'])) ->add('Dashboard', route('admin.dash'), fn($s) => $s->attributes(['icon' => 'fa-duotone fa-house-tree'])) ->tree(); return view('livewire.component.admin.dash-nav', ['navbar' => array_reverse($nav)]);
Beta Was this translation helpful? Give feedback.
All reactions