blazorbootstrap-5blazor-webassemblysidebarblazor-rendermode

How can I create a new layout using Blazor Bootstrap?


I want to use Blazor Bootstrap's SideBar. NewLayout.razor:

@inherits LayoutComponentBase

<div class="bb-page">
    <Sidebar2 Href="/"
              IconName="IconName.BootstrapFill"
              Title="Blazor Bootstrap"
              BadgeText="v2.1.0"
              DataProvider="Sidebar2DataProvider" />

    <main>
        <div class="bb-top-row px-4 d-flex justify-content-end">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4" style="position: relative;">
            <div class="py-2">
                @Body
            </div>
        </article>
    </main>
</div>

<style>
    .bb-page {
        display: flex;
        width: 100%;
        height: 100vh;
    }

    main {
        flex: 1;
        overflow: auto;
        min-width: 0;
    }
</style>

@code {

    IEnumerable<NavItem>? navItems;

    private async Task<Sidebar2DataProviderResult> Sidebar2DataProvider(Sidebar2DataProviderRequest request)
    {
        if (navItems is null)
            navItems = GetNavItems();

        return await Task.FromResult(request.ApplyTo(navItems));
    }

    private IEnumerable<NavItem> GetNavItems()
    {
        navItems = new List<NavItem>
        {
            new NavItem { Id = "1", Href = "/getting-started", IconName = IconName.HouseDoorFill, Text = "Getting Started"},

            new NavItem { Id = "2", IconName = IconName.LayoutSidebarInset, Text = "Content" },
            new NavItem { Id = "3", Href = "/icons", IconName = IconName.PersonSquare, Text = "Icons", ParentId="2"},

            new NavItem { Id = "4", IconName = IconName.ExclamationTriangleFill, Text = "Components" },
            new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"},
            new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"},

            new NavItem { Id = "7", IconName = IconName.ListNested, Text = "Sidebar 2", ParentId="4"},
            new NavItem { Id = "701", Href = "/sidebar2", IconName = IconName.Dash, Text = "How to use", ParentId="7"},
            new NavItem { Id = "702", Href = "/sidebar2-examples", IconName = IconName.Dash, Text = "Examples", ParentId="7"},

            new NavItem { Id = "8", IconName = IconName.WindowPlus, Text = "Forms" },
            new NavItem { Id = "9", Href = "/autocomplete", IconName = IconName.InputCursorText, Text = "Auto Complete", ParentId="8"},
            new NavItem { Id = "10", Href = "/currency-input", IconName = IconName.CurrencyDollar, Text = "Currency Input", ParentId="8"},
            new NavItem { Id = "11", Href = "/number-input", IconName = IconName.InputCursor, Text = "Number Input", ParentId="8"},
            new NavItem { Id = "12", Href = "/switch", IconName = IconName.ToggleOn, Text = "Switch", ParentId="8"},
        };

        return navItems;
    }

}

I want to use it as a new Layout on my Client-side page. But it keep show me that 3 dot loading thing.(https://i.sstatic.net/Jp3jQFK2.png). There is a question about it link but App.razor in server project and it doesnt work for me.

I want to use it as a new Layout on my Client-side page. I found this video link2 as the closest thing to what I want to do, but it runs the pages on the server side.

In order to create "@layout NewLayout", the layout must be on the client-side, but even so, I cannot write @rendermode InteractiveWebAssembly into the layout. gives the following error:

"InvalidOperationException: Cannot pass the parameter 'Body' to component 'NewLayout' with rendermode 'InteractiveWebAssemblyRenderMode'. This is because the parameter is of the delegate type 'Microsoft.AspNetCore.Components.RenderFragment', which is arbitrary code and cannot be serialized."


Solution

  • Based on your another question,you have to set InteractiveWebAssembly render-mode gobally for your project

    When you create a new project,select as below: enter image description here

    and follow the steps in the doc for interactive auto mode

    but you have to keep the render mode as InteractiveWebAssembly in app.razor

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <base href="/" />
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" />
        <link href="_content/Blazor.Bootstrap/blazor.bootstrap.css" rel="stylesheet" />
        
        <link rel="stylesheet" href="app.css" />
        <link rel="stylesheet" href="BlazorWasmGobal.styles.css" />
        <link rel="icon" type="image/png" href="favicon.png" />
        <HeadOutlet @rendermode="InteractiveWebAssembly" />
    </head>
    
    <body>
        <Routes @rendermode="InteractiveWebAssembly" />
        <script src="_framework/blazor.web.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
        <!-- Add chart.js reference if chart components are used in your application. -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.0.1/chart.umd.js" integrity="sha512-gQhCDsnnnUfaRzD8k1L5llCCV6O9HN09zClIzzeJ8OJ9MpGmIlCxm+pdCkqTwqJ4JcjbojFr79rl2F1mzcoLMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
        <!-- Add chartjs-plugin-datalabels.min.js reference if chart components with data label feature is used in your application. -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js" integrity="sha512-JPcRR8yFa8mmCsfrw4TNte1ZvF1e3+1SdGMslZvmrzDYxS69J7J49vkFL8u6u8PlPJK+H3voElBtUCzaXj+6ig==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
        <!-- Add sortable.js reference if SortableList component is used in your application. -->
        <script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
        <script src="_content/Blazor.Bootstrap/blazor.bootstrap.js"></script>
    </body>
    
    </html>
    

    The reason that I suggest you select interactive location as gobal is that the nav items would only be load during OnAfterRenderAsync lifecycle event .

    If you set Interactive location as per component,the layout would be rendered as static and OnAfterRenderAsync event won't be triggered,and the side bar will keep loading

    public class Sidebar : BlazorBootstrapComponentBase
    {
        private bool collapseNavMenu = true;
    
        private bool collapseSidebar;
    
        private bool isMobile;
    
        private IEnumerable<NavItem>? items;
    
        private DotNetObjectReference<Sidebar> objRef;
    
        private bool requestInProgress;
    
        protected override string? ClassNames => BlazorBootstrapComponentBase.BuildClassNames(base.Class, ("bb-sidebar", true), ("collapsed", collapseSidebar), ("expanded", !collapseSidebar));
    
        protected override string? StyleNames => BlazorBootstrapComponentBase.BuildStyleNames(base.Style, ("--bb-sidebar-width: " + Width.ToString(CultureInfo.InvariantCulture) + WidthUnit.ToCssString() + ";", Width > 0f));
    
        [Parameter]
        public string? BadgeText { get; set; }
    
        [Parameter]
        public string? CustomIconName { get; set; }
    
        [Parameter]
        [EditorRequired]
        public SidebarDataProviderDelegate? DataProvider { get; set; }
    
        [Parameter]
        public string? Href { get; set; } = string.Empty;
    
    
        [Parameter]
        public IconName IconName { get; set; }
    
        [Parameter]
        public string? ImageSrc { get; set; }
    
        private string? navMenuCssClass => GetNavMenuCssClass();
    
        [Parameter]
        [EditorRequired]
        public string? Title { get; set; }
    
        [Parameter]
        public float Width { get; set; } = 270f;
    
    
        [Parameter]
        public Unit WidthUnit { get; set; } = Unit.Px;
    
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await base.JSRuntime.InvokeVoidAsync("window.blazorBootstrap.sidebar.initialize", base.Id, objRef);
                bsWindowResize(await JSRuntimeExtensions.InvokeAsync<int>(base.JSRuntime, "window.blazorBootstrap.sidebar.windowSize", Array.Empty<object>()));
                await RefreshDataAsync(firstRender);
            }
    
            await base.OnAfterRenderAsync(firstRender);
        }
    
        protected override async Task OnInitializedAsync()
        {
            if (objRef == null)
            {
                objRef = DotNetObjectReference.Create(this);
            }
    
            if (base.AdditionalAttributes == null)
            {
                base.AdditionalAttributes = new Dictionary<string, object>();
            }
    
            await base.OnInitializedAsync();
        }
    
        [JSInvokable]
        public void bsWindowResize(int width)
        {
            if (width < 641)
            {
                isMobile = true;
            }
            else
            {
                isMobile = false;
            }
        }
    
        public async Task RefreshDataAsync(bool firstRender = false)
        {
            if (requestInProgress)
            {
                return;
            }
    
            requestInProgress = true;
            if (DataProvider != null)
            {
                SidebarDataProviderRequest request = new SidebarDataProviderRequest();
                SidebarDataProviderResult sidebarDataProviderResult = await DataProvider(request);
                Sidebar sidebar = this;
                IEnumerable<NavItem>? enumerable2;
                if (sidebarDataProviderResult == null)
                {
                    IEnumerable<NavItem> enumerable = new List<NavItem>();
                    enumerable2 = enumerable;
                }
                else
                {
                    enumerable2 = sidebarDataProviderResult.Data;
                }
    
                sidebar.items = enumerable2;
            }
    
            requestInProgress = false;
            await InvokeAsync((Action)base.StateHasChanged);
        }
    
        public void ToggleSidebar()
        {
            collapseSidebar = !collapseSidebar;
            StateHasChanged();
        }
    
        internal void HideNavMenuOnMobile()
        {
            if (isMobile && !collapseNavMenu)
            {
                collapseNavMenu = true;
            }
        }
    
        private string GetNavMenuCssClass()
        {
            HashSet<string> hashSet = new HashSet<string>();
            if (collapseNavMenu)
            {
                hashSet.Add("collapse");
            }
    
            hashSet.Add("bb-sidebar-content nav-scrollable bb-scrollbar");
            if (collapseSidebar)
            {
                hashSet.Add("bb-scrollbar-hidden");
            }
    
            return string.Join(" ", hashSet);
        }
    
        private void ToggleNavMenu()
        {
            collapseNavMenu = !collapseNavMenu;
        }
    
        protected override void BuildRenderTree(RenderTreeBuilder __builder)
        {
            TypeInference.CreateCascadingValue_0(__builder, 0, 1, __arg0: true, 2, this, 3, delegate (RenderTreeBuilder __builder2)
            {
                TypeInference.CreateCascadingValue_1(__builder2, 4, 5, collapseSidebar, 6, delegate (RenderTreeBuilder __builder3)
                {
                    __builder3.OpenElement(7, "aside");
                    __builder3.AddAttribute(8, "id", base.Id);
                    __builder3.AddAttribute(9, "class", ClassNames);
                    __builder3.AddAttribute(10, "style", StyleNames);
                    __builder3.AddAttribute(11, "role", "navigation");
                    __builder3.AddMultipleAttributes(12, RuntimeHelpers.TypeCheck((IEnumerable<KeyValuePair<string, object>>)base.AdditionalAttributes));
                    __builder3.AddAttribute(13, "b-h9l5f7lx3r");
                    __builder3.AddElementReferenceCapture(14, delegate (ElementReference __value)
                    {
                        base.Element = __value;
                    });
                    __builder3.OpenElement(15, "div");
                    __builder3.AddAttribute(16, "class", "bb-sidebar-top-row navbar");
                    __builder3.AddAttribute(17, "b-h9l5f7lx3r");
                    __builder3.OpenElement(18, "div");
                    __builder3.AddAttribute(19, "class", "container-fluid ps-3");
                    __builder3.AddAttribute(20, "b-h9l5f7lx3r");
                    __builder3.OpenElement(21, "a");
                    __builder3.AddAttribute(22, "class", "navbar-brand d-flex align-items-center");
                    __builder3.AddAttribute(23, "href", Href);
                    __builder3.AddAttribute(24, "b-h9l5f7lx3r");
                    if (!string.IsNullOrWhiteSpace(ImageSrc))
                    {
                        __builder3.OpenElement(25, "span");
                        __builder3.AddAttribute(26, "class", "navbar-brand-image me-2");
                        __builder3.AddAttribute(27, "b-h9l5f7lx3r");
                        __builder3.OpenElement(28, "img");
                        __builder3.AddAttribute(29, "src", ImageSrc);
                        __builder3.AddAttribute(30, "alt", Title);
                        __builder3.AddAttribute(31, "b-h9l5f7lx3r");
                        __builder3.CloseElement();
                        __builder3.CloseElement();
                    }
                    else
                    {
                        __builder3.OpenElement(32, "span");
                        __builder3.AddAttribute(33, "class", "navbar-brand-icon");
                        __builder3.AddAttribute(34, "b-h9l5f7lx3r");
                        __builder3.OpenComponent<Icon>(35);
                        __builder3.AddComponentParameter(36, "Name", RuntimeHelpers.TypeCheck(IconName));
                        __builder3.AddComponentParameter(37, "CustomIconName", RuntimeHelpers.TypeCheck(CustomIconName));
                        __builder3.AddComponentParameter(38, "Class", "fs-4 me-2");
                        __builder3.CloseComponent();
                        __builder3.CloseElement();
                    }
    
                    __builder3.OpenElement(39, "span");
                    __builder3.AddAttribute(40, "class", "navbar-brand-text fw-semibold expanded-only me-2");
                    __builder3.AddAttribute(41, "b-h9l5f7lx3r");
                    __builder3.AddContent(42, Title);
                    __builder3.CloseElement();
                    if (!string.IsNullOrWhiteSpace(BadgeText))
                    {
                        __builder3.OpenElement(43, "span");
                        __builder3.AddAttribute(44, "class", "navbar-brand-badge badge expanded-only");
                        __builder3.AddAttribute(45, "b-h9l5f7lx3r");
                        __builder3.AddContent(46, BadgeText);
                        __builder3.CloseElement();
                    }
    
                    __builder3.CloseElement();
                    __builder3.AddMarkupContent(47, "\r\n                    ");
                    __builder3.OpenElement(48, "button");
                    __builder3.AddAttribute(49, "title", "Navigation menu");
                    __builder3.AddAttribute(50, "class", "navbar-toggler px-2");
                    __builder3.AddAttribute(51, "onclick", EventCallback.Factory.Create<MouseEventArgs>((object)this, (Action)ToggleNavMenu));
                    __builder3.AddAttribute(52, "b-h9l5f7lx3r");
                    __builder3.AddMarkupContent(53, "<span class=\"navbar-toggler-icon bi bi-list\" b-h9l5f7lx3r></span>");
                    __builder3.CloseElement();
                    __builder3.CloseElement();
                    __builder3.CloseElement();
                    __builder3.AddMarkupContent(54, "\r\n\r\n            ");
                    __builder3.OpenElement(55, "div");
                    __builder3.AddAttribute(56, "class", navMenuCssClass);
                    __builder3.AddAttribute(57, "b-h9l5f7lx3r");
                    if (items == null)
                    {
                        __builder3.OpenElement(58, "div");
                        __builder3.AddAttribute(59, "class", "text-center my-2");
                        __builder3.AddAttribute(60, "b-h9l5f7lx3r");
                        __builder3.OpenComponent<Spinner>(61);
                        __builder3.AddComponentParameter(62, "Type", RuntimeHelpers.TypeCheck(SpinnerType.Dots));
                        __builder3.AddComponentParameter(63, "Color", RuntimeHelpers.TypeCheck(SpinnerColor.Secondary));
                        __builder3.CloseComponent();
                        __builder3.CloseElement();
                    }
                    else
                    {
                        __builder3.OpenComponent<SidebarItemGroup>(64);
                        __builder3.AddComponentParameter(65, "NavItems", RuntimeHelpers.TypeCheck(items));
                        __builder3.CloseComponent();
                    }
    
                    __builder3.CloseElement();
                    __builder3.CloseElement();
                });
            });
        }
    }