简体   繁体   中英

Change visibility of nav item in blazor menu

I'm using Blazor with .NET Core 3.0. I want to show a login in my menu, when the user isn't logged in yet. When he is logged in, then the login nav item should be hidden. How can I do this?

EDIT: I changed the OnInitializedAsync method by using async Task, but this is not the problem. For the first load, it works correctly. But then i go to the login page, log me in and Navigate to the home page via NavigationManager, the menu will not be "refreshed". How can I solve this?

Following code is not working...

<div>
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        @if (!_isLoggedIn)
        {
            <li class="nav-item px-3">
                <NavLink class="nav-link" href="login">
                    <span class="oi oi-person" aria-hidden="true"></span> <LocalizedString Key="NavMenuLogin" />
                </NavLink>
            </li>
            <li class="nav-item px-3">
                <NavLink class="nav-link" href="licenseedit">
                    <span class="oi oi-spreadsheet" aria-hidden="true"></span> <LocalizedString Key="NavMenuRegistration" />
                </NavLink>
            </li>
        }
    </ul>
</div>

@code{

    private bool _isLoggedIn;

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        await TokenExistAsync();
    }

    private async Task TokenExistAsync()
    {
        var retVal = await Http.GetStringAsync("api/Login/ExistToken");
        _isLoggedIn = retVal == "yes";
    }

}

I changed my code above, but still not working

I think I understand what you want... The following is the code to achieve that, provided that I'm right... You want to refresh the content of the NavMenu component, which is embedded in the MainLayout component, from the login page, right?

You can use various methods to achieve this. The following solution is based on the App State Pattern.

First off, we have to create a service class that can be accessed from both, the NavMenu component and the Login component. Here's the class:

public class AppState
{
    private bool _loggedIn;
    public event Action OnChange;
    public bool LoggedIn
    {
        get { return _loggedIn; }
        set {
            if (_loggedIn != value)
            {
                _loggedIn = value;
                NotifyStateChanged();
            }
        }
    }

    private void NotifyStateChanged() => OnChange?.Invoke();
}

This class defines an event delegate, named OnChange, which should encapsulate the method that will refresh the NavMenu. This delegate is invoked when the boolean property LoggedIn's value changes. The LoggedIn property's value may change in the Login page, when the user has been logged in, thus any subscriber to this delegate, in our case, the NavMenu, will be notified of this.

Login Page

  • @inject AppState AppState Note the above inject the AppState to the Login Page. Put it at the top of the page

  • AppState.LoggedIn = true; that code should be place at the end of the log in procedure. This will initiate the triggering of the OnChange delegate.

NavMenu component

  • @inject AppState AppState
  • @implements IDisposable

*

protected override void OnInitialized()
{
    AppState.OnChange += StateHasChanged;
}

public void Dispose()
{
    AppState.OnChange -= StateHasChanged;
}

Now, whenever you log in, the AppState service notifies the NavMenu component to re-render so that the login link is not visible (not rendered)

Startup class

services.AddSingleton<AppState>();

You have

protected override async void OnInitialized()

make that

protected override async Task OnInitializedAsync()

Almost always avoid async void . In this case your app could run the logic to update the UI before TokenExistAsync() is finished. The void version is not meant to be used async, the names are a guideline.

In addition, Blazor has special support for hidden and similar on/off attributes. You can use:

<li class="nav-item px-3" hidden="@hideLogin">

With reversed logic you would need () as in hidden=@(!showLogin)
and in your code block:

bool hideLogin = false;

...

  // _loginVisibility = "hidden";
  hideLogin = true;

I've altered your code a little bit... Use Task instead of void. Try this code snippet instead:

@code{

private string _loginVisibility = "visible";

protected override async Task OnInitializedAsync()
{
    await TokenExistAsync();
}

private async Task TokenExistAsync()
{
    var retVal = await Http.GetStringAsync("api/Login/ExistToken");
    if (retVal == "yes")
    {
        _loginVisibility = "hidden";
    }
}

}

If this change does not work, check your CSS classes

Note: I'm of the opinion that using a string value to either hide or display the li element is wrong. You don't have to hide the li element. It should not be rendered at all. you can define a boolean variable like this:

public bool ShowLink {get; set;} = true;

As you can see the property is set to the default value true, and thus the li element is rendered:

 @if ( ShowLink )
 {
 <li class="nav-item px-3">
        <NavLink class="nav-link" href="login">
            <span class="oi oi-person" aria-hidden="true"></span> 
 Login
        </NavLink>
    </li>
 }

And in the TokenExistAsync method it should be set to false if this method returns "yes". And thus the li element is not rendered.

I think I know what is the problem. The code above is fine and will work. The possible problem could be in login page. In case of something like navigationManager.NavigateTo("/client/home") the NavMenu code will not hit. To do that you should use second parameter: navigationManager.NavigateTo("/client/home", true); I hope this would help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM