Skip to content

Instantly share code, notes, and snippets.

@smokedlinq
Created January 12, 2020 23:18
Show Gist options
  • Save smokedlinq/26fd4b026eef0800460548b2bc30b1fe to your computer and use it in GitHub Desktop.
Save smokedlinq/26fd4b026eef0800460548b2bc30b1fe to your computer and use it in GitHub Desktop.
Blazor Modal Example
<!-- Add before blazor.server.js -->
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.bundle.min.js" integrity="sha384-6khuMg9gaYr5AxOqhkVIODVIvm9ynTT5J4V1cfthmT+emCG6yVmEZsRHdxlotUnm" crossorigin="anonymous"></script>
<script>
window.showModal = id => $('#' + id).modal('show');
window.hideModal = id => $('#' + id).modal('hide');
</script>
using System;
using System.Runtime.Serialization;
namespace blazor
{
[Serializable]
internal class ComponentRefMissingException : InvalidOperationException
{
public ComponentRefMissingException(string componentName)
: base($"The component '{componentName}' is missing the '@ref' attribute.")
{
}
protected ComponentRefMissingException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
### WORKING OUTPUT ##
conversion-modal.OnAfterRenderAsync(True) [1]
conversion-input-modal.OnAfterRenderAsync(True) [1]
conversion-input-modal.ShowAsync()
conversion-input-modal.OnAfterRenderAsync(False) [2]
conversion-modal.OnAfterRenderAsync(False) [2]
conversion-input-modal.OnAfterRenderAsync(False) [3]
## BROKEN OUTPUT ###
conversion-modal.OnAfterRenderAsync(True) [1]
conversion-input-modal.OnAfterRenderAsync(True) [1]
conversion-modal.ShowAsync()
conversion-modal.OnAfterRenderAsync(True) [1]
conversion-modal.OnAfterRenderAsync(False) [2]
conversion-input-modal.OnAfterRenderAsync(False) [2]
@inherits ComponentBase
<EditForm Model="@_model" OnValidSubmit="@OnValidSubmit">
<Modal @ref="_modal" Id="@ModalId" Title="@_title">
<Body>
<div class="form-group">
<InputText id="name" class="form-control text-monospace" @bind-Value="_model.Name" placeholder="Name" />
<ValidationMessage For="@(() => _model.Name)" class="text-danger" />
</div>
<div class="form-group">
<InputTextArea id="value" class="form-control text-monospace" @bind-Value="_model.Value" rows="3" placeholder="Value" />
<ValidationMessage For="@(() => _model.Value)" class="text-danger" />
</div>
</Body>
<Footer>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary" accesskey="v">Sa<u>v</u>e</button>
</Footer>
</Modal>
</EditForm>
@code {
[Parameter]
public string ModalId { get; set; } = "conversion-modal";
[Parameter]
public EventCallback<Conversion> OnSave { get; set; }
private Conversion _model { get; set; } = new Conversion();
private string _title;
private Modal _modal;
public async Task ShowAddConversionAsync()
{
_ = _modal ?? throw new ComponentRefMissingException(nameof(Modal));
_title = "Add Conversion";
_model = new Conversion();
StateHasChanged();
await _modal.ShowAsync().ConfigureAwait(false);
}
private async Task OnValidSubmit()
{
_ = _modal ?? throw new ComponentRefMissingException(nameof(Modal));
await OnSave.InvokeAsync(_model).ConfigureAwait(false);
await _modal.HideAsync().ConfigureAwait(false);
}
public class Conversion
{
public string Name { get; set; }
public string Value { get; set; }
}
}
@inherits ComponentBase
<EditForm Model="@this" OnValidSubmit="@OnValidSubmit">
<Modal @ref="_modal" Id="@ModalId" Title="Add Conversion Input">
<Body>
<div class="form-group">
<InputTextArea id="value" class="form-control text-monospace" rows="3" placeholder="Input" @bind-Value="Value" />
<ValidationMessage For="@(() => Value)" class="text-danger" />
</div>
</Body>
<Footer>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary" accesskey="v">Sa<u>v</u>e</button>
</Footer>
</Modal>
</EditForm>
@code {
[Parameter]
public string ModalId { get; set; } = "conversion-input-modal";
[Parameter]
public EventCallback<string> OnSave { get; set; }
public string Value { get; set; } = string.Empty;
private Modal _modal;
public async Task ShowAddConversionInputAsync()
{
_ = _modal ?? throw new ComponentRefMissingException(nameof(Modal));
Value = string.Empty;
StateHasChanged();
await _modal.ShowAsync().ConfigureAwait(false);
}
private async Task OnValidSubmit()
{
_ = _modal ?? throw new ComponentRefMissingException(nameof(Modal));
await OnSave.InvokeAsync(Value).ConfigureAwait(false);
await _modal.HideAsync().ConfigureAwait(false);
}
}
@page "/"
<button type="button" class="btn btn-primary" @onclick="(() => _form.ShowAddConversionAsync())" accesskey="i">
Add Conversion
</button>
<button type="button" class="btn btn-secondary" @onclick="(() => _inputForm.ShowAddConversionInputAsync())" accesskey="i">
Add Conversion Input
</button>
<ConversionForm @ref="_form" OnSave="@OnAddConversion" />
<ConversionInputForm @ref="_inputForm" OnSave="@OnAddConversionInput" />
@code {
private ConversionForm _form;
private ConversionInputForm _inputForm;
private Task OnAddConversion(ConversionForm.Conversion conversion)
=> Console.Out.WriteLineAsync($"OnAddConversion({conversion.Name}");
private Task OnAddConversionInput(string input)
=> Console.Out.WriteLineAsync($"OnAddConversionInput({input})");
}
@inherits ComponentBase
@inject IJSRuntime JSRuntime
<div class="modal" tabindex="-1" role="dialog" id="@Id" @attributes="Attributes">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@Title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
@Body
</div>
@if (!(Footer is null))
{
<div class="modal-footer">
@Footer
</div>
}
</div>
</div>
</div>
@code {
[Parameter]
public string Id { get; set; } = "modal";
[Parameter]
public string Title { get; set; } = string.Empty;
[Parameter]
public RenderFragment Body { get; set; }
[Parameter]
public RenderFragment Footer { get; set; }
private int _OnAfterRenderAsync = 0;
protected override Task OnAfterRenderAsync(bool firstRender)
=> Console.Out.WriteLineAsync($"{Id}.{nameof(OnAfterRenderAsync)}({firstRender}) [{++_OnAfterRenderAsync}]");
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object> Attributes { get; set; } = new Dictionary<string, object>();
public async Task ShowAsync()
{
await Console.Out.WriteLineAsync($"{Id}.{nameof(ShowAsync)}()");
await JSRuntime.InvokeVoidAsync("showModal", Id).ConfigureAwait(false);
}
public async Task HideAsync()
{
await Console.Out.WriteLineAsync($"{Id}.{nameof(ShowAsync)}()");
await JSRuntime.InvokeVoidAsync("hideModal", Id).ConfigureAwait(false);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment