Ncw007
Ncw007

Reputation: 21

No-reload navigation using modals in Blazor Server Side

I'm trying to build a web application using Blazor server side. I would like to provide a no-reload navigation system using modals, so the user won't have to reload the page.

If a user lands directly to www.host.com/login, the main page will load and the login modal should open, and the url be www.host.com/login. If a user closes the modal, the url is updated, the modal closed, but no reload should happen.

Is that possible in Blazor? From what I understand, modals have to be in the same page as the caller is. From what I succeeded about modals with Blazorstrap's modals, I have:

<BSNavLink Href="javascript:void(0);" id="username" @onclick="@(() => LoginRegisterModal.Show())">
    <i class="fas fa-user icon-padding-right" />
    USERNAME
</BSNavLink>

<BSModal @ref="LoginRegisterModal">
    <BSModalHeader OnClick="@(() => LoginRegisterModal.Hide())">Login - Register</BSModalHeader>
    <BSModalBody><p>Login / Register form goes here</p></BSModalBody>
</BSModal>

Which opens a modal, but will not update the url nor be opened when an user lands on it.

I tried putting my modal in a separate file and set a @page "/login" on it, but haven't succeeded. Also I checked how I could change the default App.razor to achieve this, but again haven't succeeded.

Is there any way to achieve this kind of navigation in blazor?

Upvotes: 0

Views: 2345

Answers (3)

Ncw007
Ncw007

Reputation: 21

I found how to change the url without reloading the page when a modal opens or closes. As I said in the question, I used BlazorStrap to create the modals. Here are the steps to reproduce:

  • Add @page "/yourmodal" for each modal you want, in any .razor file

  • Add Href="/yourmodal" on the NavLink or Button that opens the modal. This will change the url when opening a modal. For example:

    <BSNavLink Href="/login" @onclick="@(() => LoginRegisterModal.Show())">
    USERNAME
    </BSNavLink>
    
  • Add a function to the IsOpenChanged attribute on the BSModal element. This function will be called each time the modal opens or closes, in any way (closing from button, backdrop click or pressing the escape button). It will be triggered with a boolean as parameter, telling if the modal is now closed or opened.

    <BSModal @ref="LoginRegisterModal" IsOpenChanged="@((e) => ModalIsOpenChanged(e))">
    
  • In this function, check if the modal is now closed, if it is, call NavigationManager.NavigateTo("/", false) to go back to your previous page. This will change the URL when closing a modal.

Now any modal that opens or closes will update the URL without reloading the page. What is still missing from the original question, is when landing on a modal. For example navigating manually to https://localhost/login won't open the login modal. I will update this answer when I have the solution.

Upvotes: 0

Vi100
Vi100

Reputation: 4203

I think you have a little missconception about what a blazor server app is... Once you access the route enpoint you have defined for the "_Host.cshtml" file and the application loads on the client's browser it behaves like a SPA (Single Page Application) and since that moment the routes you observe on the browser aren't real http requests and no reload happens when you change from on page to another.

That said, managing the modals will be your smallest problem. You are about to mess with the Authentication and Authorization systems that are a pain to adjust on blazor, because once you validate the credentials on the login page you have to NavigateTo the Home or root page that should not be accessible to non authenticated/authorized users. Good luck!

As per comments

No, what I'm trying to say is that you can't manipulate urls directly on your browser. If the only problem is that you want the modal open from beginnig then create it already open. You can use bootstrap for that or any other css library you want for that, but you also can do it creating an overlay layer and wrapping the rest of the contents into a div and put all this inside an if block whose condition is a boolean variable that you can toggle when you want (initialized to true), thats all.

Upvotes: 1

user12228709
user12228709

Reputation:

I have an open source project and live site, maybe this code will give you a better idea how to login a user, persist it with Microsoft.AspNetCore.ProtectedBrowserStorage, and then log the user back in when they return (if they chose Remember Password):

This is part of the Index.razor from BlazorChat. The top part tests for if a user is logged in, if yes the user name is displayed and a Sign Out button. If not, the Login and Join buttons are shown.

The bottom section uses an Enumeration I created called ScreenTypeEnum:

/// <summary>
/// This enum is used to determine which part of the screen is visible at any time
/// </summary>
public enum ScreenTypeEnum : int
{
    Main = 0,
    Join = 1,
    Login = 2
}

@if (HasLoggedInUser)
{
    <div class="welcome">Welcome @LoggedInUser.UserName</div>
    <button class="greenbutton2">
        <span class="moveup4" @onclick="SignOutButton_Click">Sign Out</span>
    </button>
}
else
{ 
    <button class="greenbutton2">
        <span class="moveup4" @onclick="LoginButton_Click">Login</span>
    </button>
    <button class="greenbutton3">
        <span class="moveup4" @onclick="SignUpButton_Click">Join Free</span>
    </button>
}

@if (ScreenType == ScreenTypeEnum.Join)
{ 
    <Join Parent=this></Join>
}
else if (ScreenType == ScreenTypeEnum.Login)
{
    <Login Parent=this></Login>
}
else
{
    <Chat Parent=this></Chat>
    @if (TextHelper.Exists(Message))
    {  
        <div class="message">
            @Message
        </div>
    }
}    

Not saying this is the only way, but this has worked for me in a couple of sites now.

enter image description here

Sample Uses SQL Server Express https://github.com/DataJuggler/BlazorChat

Live site, not very many people: https://blazorchat.com

I am working on a component for the chat, so any Blazor site can add it.

Upvotes: 0

Related Questions