Course contentsShow
← C#
Lesson 1321 of 1,90812. Modern Frontend with Razor and BlazorFree lesson

Developing SPA-like Navigation

Use client-side JS hooks to augment server-side navigation for a smoother user experience.

In this lesson, you will learn how to intercept standard browser navigation to provide a smoother, "SPA-like" experience using JavaScript hooks within your Razor Pages application.

The Problem with Traditional Navigation

By default, when a user clicks a link in a Razor Pages application, the browser performs a full page reload. This causes a "flash" of white space as the browser discards the current DOM and fetches a brand-new page from the server, which can feel jarring and slow.

Intercepting with JavaScript Hooks

To achieve an SPA-like feel, we want to intercept the click event on navigation links, fetch the target URL content via fetch(), and swap out only the relevant content container (like a main <div id="app">).

By using a simple JavaScript hook, we can keep the header and footer intact while updating the page content dynamically.

document.addEventListener('click', function(e) {
    // Ensure the link is intended for our SPA container
    if (e.target.matches('a.spa-link')) {
        e.preventDefault();
        const url = e.target.href;

        // Fetch the new content
        fetch(url)
            .then(response => response.text())
            .then(html => {
                const parser = new DOMParser();
                const doc = parser.parseFromString(html, 'text/html');
                // Replace only the main content area
                document.getElementById('app').innerHTML = 
                    doc.getElementById('app').innerHTML;
                
                // Update URL without a full reload
                history.pushState(null, '', url);
            });
    }
});

Server-Side Considerations

Because your server-side Razor views typically return a full HTML document (including _Layout.cshtml), a naive fetch will return the entire page. To make this efficient, you can modify your Razor Pages to return only a specific partial view if a custom header is detected:

public IActionResult OnGet()
{
    if (Request.Headers["X-Requested-With"] == "XMLHttpRequest")
    {
        return Partial("_ContentPartial", Model);
    }
    return Page();
}

By conditionally returning a PartialView when the request originates from your JavaScript hook, you minimize the payload size and ensure the browser only re-renders the part of the page that actually changed.

Key Takeaway: By intercepting link clicks with JavaScript and conditionally returning partial views from the server, you eliminate full page reloads and create a seamless, fluid navigation experience.