dotnet / AspNetCore.Docs

Documentation for ASP.NET Core
https://docs.microsoft.com/aspnet/core
Creative Commons Attribution 4.0 International
12.61k stars 25.3k forks source link

Guidance on Blazor wasm app that uses some bootstrap.js functionality #22213

Closed angelotrivelli closed 3 years ago

angelotrivelli commented 3 years ago

Just need some guidance here about working with the "javascript parts" of bootstrap.

I've been studying the bootstrap 4.3.1 docs so that I can figure out layout and styling for a blazor webassembly application idea. The bootstrap docs recommend using their "Starter Template" which includes not only bootstrap.css, but also jquery.js, popper.js, and bootstrap.js. I've been able to make some progress in the layout/styling I want to have by burying my face in the bootstrap docs and trying stuff out on vs-code LiveServer. It works.

More recently, I've tried to start on the actual Blazor wasm pages. Right off the bat, I notice that the default project does not include bootstrap.js/jquery/popper. It just includes bootstrap.css and of course the blazor.webassembly.js. The top of the page just has the usual hamburger button (navbar-toggler-icon) which displays/hides nav-items when the window is narrow enough. Since there's no bootstrap.js the collapsing toggle needs to be implemented in a c# @Code block. Like this (it's literally just the NavMenu.razor file for the default Blazor Webassemby project)...

<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">bwasm1</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <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>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
            </NavLink>
        </li>
    </ul>
</div>

@code {
    private bool collapseNavMenu = true;
    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

That's nice and it works, but I would prefer to use bootstrap javascript functionality for something that low-level.

So, I modified the index.html to include jquery, popper, boostrap.js just like in the bootstrap starter template. Like this...

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>bwasm3</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="bwasm3.styles.css" rel="stylesheet" />
</head>

<body>
    <div id="app">Loading...</div>
    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">šŸ—™</a>
    </div>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

I then modified the NavMenu.razor file, getting rid of the @Code block and tried using only the bootstrap stuff (eg data-toggle and data-target) for collapse functionality. Like this...

<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">bwasm3</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="collapse navbar-collapse" id="ToggleNavMenu">
    <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>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
            </NavLink>
        </li>
    </ul>
</div>

When I do that, the nav-items dissapear and hamburger appears when the window is narrow-enough (as expected). But the hamburger button does not toggle visibility of the nav items! Not sure if I just messed it up or if there's something else going on.

Questions

Assuming I didn't just botch something dumb in the previous code block, at this point I just need a little guidance.


Document Details

āš  Do not edit this section. It is required for docs.microsoft.com āžŸ GitHub issue linking.

guardrex commented 3 years ago

Hello @angelotrivelli ...

Generally, avoid the use of JS in favor of Blazor/C# when working with the DOM. Keep in mind when using JS directly with the DOM that Blazor's diff engine is also interacting with the DOM at the same time. If you mutate an element that Blazor is also interacting with, it can have unpredictable consequences for the behavior of the app ... even to the point of creating šŸ’€ security risks šŸ’€.

Having said that, JS interaction with the DOM isn't ruled out in cases where there's no potential conflict between what a JS lib does and Blazor's work with the DOM. Consider the example in ...

https://docs.microsoft.com/en-us/aspnet/core/blazor/call-javascript-from-dotnet?view=aspnetcore-5.0#use-of-javascript-libraries-that-render-ui-dom-elements

... Blazor doesn't work with the <div> for the map. There's no conflict between the Mapbox/JS interop and Blazor's diff engine, so that's a supported scenario.

WRT your second question: Yes, you can work with Blazor/C# and your own styles. In fact, some devs are very annoyed by various Bootstrap conventions and refuse to use it. I would expect that group of devs to absolutely yank it in favor of some other styles by using a 3rd party framework or their own bits.

btw WRT ...

That doc is really complex

I agree, and I'm working on that doc at this very instant (the PR will be up on Friday or early next week) as part of https://github.com/dotnet/AspNetCore.Docs/issues/19286. I'm performing set of UE passes ("user experience" passes ... i.e., total overhauls) on most of the Blazor topics. They were nice topics when there were fewer features and less content. Over the last few years, most of the Blazor topics became rather messy ... hacked to death with new bits and updates. The first of the two JS interop topics, the one that deals with calling JS from .NET, will be updated by the end of next week. The other JS interop topic, calling .NET from JS, will receive updates a week or so after that. Check back in a couple of weeks for better docs :+1:.

I've also added a note to that UE pass tracking issue about your ask. I think we need a little more guidance on this scenario with Bootstrap given, as you say, that Blazor uses Bootstrap styling. It's a good question that we don't directly address. I'll take a look at where and how to cover it when I get to that entry on the UE tracking issue. I'll work with the PU ("product unit") on it to make sure that we have the best coverage. Thanks for asking about this.

guardrex commented 3 years ago

I'd be remiss here, too, if I didn't mention the community support channels that we recommend. If you need to chat with other devs about this ... or anything really, try the following. I know ur probably aware of at least one or two of these, but just in case ...

angelotrivelli commented 3 years ago

Thank you very much for the thorough answer, I appreciate it!