Bootstrap+Blazor essentials
Tags: dotnet, blazor, bootsrap, beginners
Published: 2020-10-13 15:09:24

When you start a new Blazor project it will quickstart you with a default Bootstrap template. But when you spent several weeks or months on the project you starting to notice that there is a lot of duplicate HTML code that can be refactored and moved into components.

In this post, I want to give you some advice on how and which Bootstrap components you can wrap into `.razor` components to make your code simpler, easier to maintain, and expandable.

{% github xakpc/Xakpc.BlazorBits.Bootstrap %}

All these components are alterations of what I use every day in my projects. Why not share the same? In real projects, there is usually some CSS template used that could alter the component significantly.

These examples use clean Bootstrap and can be the foundation that could be altered for your CSS template. That's why I usually just copy-paste them across projects and tune to fit the current CSS template, instead of moving them to separate NuGet package;

Bootstrap has more than 20 components, but for this article, I keep only the ones that used very often and make a great example for you where to go from hereby.
* Button
* Button Group
* Card
* Progress
* Spinner
* Toast
* Modals

**Next time** - Form and Form Components in Blazor with MVVM

# Button
The most basic component is a button. Because I use [MVVM](https://dev.to/xakpc/using-blazor-consider-mvvm-59dm) my button is based on the `ICommand` interface

{% gist https://gist.github.com/xakpc/5edb41886f12b695edfc694a54280360 file=CommandButton.razor %}

When you add action to button's ICommand `AddCommand = new Command<int>(DoAdd); ` take notice of the action
```
private void DoAdd(int p)
{
    Value += p;
    StateHasChanged(); // <--- not gonna work without it
}
```
I [found out](https://twitter.com/xakpc/status/1314235866605379585) that `onaction` will re-render only the component it belongs to. Even if actual action changes something from another (parent) component. But when you use ViewModel there is no need in `StateHasChanged` call here because the View should be subscribed to `INotifyPropertyChanged` anyway.

# Button Group
Button group wraps several command buttons in a single neat component. I usually use it for data table editing
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/g8swcuac9pdm2xt54bup.PNG)
{% gist https://gist.github.com/xakpc/5edb41886f12b695edfc694a54280360 file=RowButtonGroup.razor %}

The component is rather simple, you can use icons instead of text for a better look, but the main thing that it nicely fits Blazor way of building tables.
You could pass commands and current item to ViewModel for processing. If you have a lot of tables in your app that saves tons of space also, you get consistency across tables and can easily adapt styles in the future.
```
<tbody>
    @foreach (var item in Items)
    {
        <tr>
            <td>@item</td>
            <td><RowButtonGroup 
                    EditCommand="EditItemCommand" 
                    DeleteCommand="DeleteItemCommand" 
                    Parameter="item"/></td>
        </tr>
    }
</tbody>
```

# Card
For me, the card is the primary component of any web app. This component wrap most of the basic HTML card into several optional `RenderFragments`. You can expand it further to add an optional `card-image` or `list-group` block.
{% gist https://gist.github.com/xakpc/093c85494c623954107ea7cfc8b88dd6 %}

I noticed that some folks missing the fact that you **can use several RenderFragment** inside your component. Well, you can and it allows you to use your components like that

```
<Card Title="Special title treatment">
    <Body>
        <p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
        <a href="#" class="btn btn-primary">Go somewhere</a>
    </Body>
    <Footer>
        2 days ago
    </Footer>
</Card>
```
Please note 
```
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object> InputAttributes { get; set; } 
    = new Dictionary<string, object>();
```
This parameter is used on card to catch-all unmatched attributes that you want to assign to it `<div class="card @Class" @attributes="InputAttributes">`. It's usually a good practice to include such catch-all property to every custom component. Saves some time on unmatched exceptions later. But be aware where you put it, for some components, it might be wise to apply attributes to the child or not apply it at all.

# Progress Bar
Small component but I want to show it here as an example of the power of Blazor components and proper MVVM usage.

{% gist https://gist.github.com/xakpc/5edb41886f12b695edfc694a54280360 file=ProgressBar.razor %}

## Progress Bar with MVVM Example
Let's dig into the example of usage of ProgressBar with backing it ViewModel.

### View
```
<h2 class="mt-3">Interactive (with VM)</h2>
<ProgressBar Progress="@DataContext.Progress" Class="mt-2 mb-2">@((DataContext.Progress/100f).ToString("P0"))</ProgressBar>
<CommandButton class="btn-primary" Command="@DataContext.Add">+</CommandButton>
<CommandButton class="btn-secondary" Command="@DataContext.Subtract">-</CommandButton>
```
As you can see View is quite simple: we have progress which is transformed like that `@((DataContext.Progress/100f).ToString("P0"))` for display only and couple buttons with commands `Add` and `Subtract`. 
These actions are calculated in ViewModel. To ensure that ViewModel created, initialized, and linked I use [ContextComponentBase](https://gist.github.com/xakpc/6d15b7b10ac9d01fcf9dbe30e89fcde8) as a base class for all my pages.

Page code-behind looks like this
```
    public partial class Progresses
    {
        [Inject]
        protected new ProgressViewModel DataContext
        {
            get => base.DataContext as ProgressViewModel;
            set => base.DataContext = value;
        }
    }
```
Ensure that `.razor` page itself is inherited from the proper class
```
@page "/progress"
@inherits Xakpc.BlazorBits.Bootstrap.ViewModels.ContextComponentBase;
```
That's all we need for View, let's switch to ViewModel!

### ViewModel
First, check out the previous code snippet. Our ViewModel is Injected into our View - so let's not forget to add it in `Startup.cs`
```
services.AddScoped<ProgressViewModel>();
```
I recommend read several times about [Scopes](https://docs.microsoft.com/en-Us/aspnet/core/blazor/fundamentals/dependency-injection?view=aspnetcore-3.1#service-lifetime/) in Blazor. Once I lost a day trying to fix a problem caused by misunderstanding Blazor DI Scopes.
Finally a ViewModel itself
```
public class ProgressViewModel : ViewModelBase
{
    private int _progress;

    public ProgressViewModel()
    {
        Add = new Command<int>(i => Progress += 1, i => Progress < 100);
        Subtract = new Command<int>(i => Progress -= 1, i => Progress > 0);
    }

    public int Progress
    {
        get => _progress;
        set { _progress = value; OnPropertyChanged(nameof(Progress)); }
    }

    public override Task InitializeAsync()
    {
        Progress = 22;
        return base.InitializeAsync();
    }

    public ICommand Add { get; set; }
    public ICommand Subtract { get; set; }
}
```
I will not go deep into VM, only point to main things
* `InitializeAsync` called once per scope on first page-load - that means once per connection for Blazor Server because we added it with `AddScope`;
* Commands set `Progress` which fire `OnPropertyChanged` which fire `StateHasChanged` which fire page redraw;
* Commands have `CanExecute` func to ensure that Progress in range 0-100;
* CanExecute also used to disable buttons when needed;

# Spinner
Spinner is another simple example of how easy to wrap into a Razor component.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/suoy0ho1b7yuz6vsc5ut.PNG)
{% gist https://gist.github.com/xakpc/5edb41886f12b695edfc694a54280360 file=Spinner.razor %}

# Toasts
For toasts, I usually don't use a Bootstrap component but a nice Blazor port of very popular toastr.js 
{% github https://github.com/sotsera/sotsera.blazor.toaster %}
I should probably try Bootrstap toasts someday.

# Modal
Bootstrap has a Modal component but it is highly dependant on JavaScript. In my work with Blazor, I prefer to minimize the amount of JS code overall, so I use `Blazored.Modal` - an amazing native component for Modals. You should check it out.
{% github https://github.com/Blazored/Modal %}

And that's all for now. I am not very good at writing such long articles, so will be appreciated for any feedback. 

And if you have any questions, feel free to mention me in [Twitter](https://twitter.com/xakpc)