Skip to content

Commit

Permalink
Dialog: Fix corrupted Parameters with Multiple open Dialogs (MudBlazo…
Browse files Browse the repository at this point in the history
  • Loading branch information
belucha committed Aug 19, 2022
1 parent 5d6ba1b commit b559b3d
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 26 deletions.
Expand Up @@ -15,6 +15,13 @@
[Parameter] public string TestValue { get; set; }
[Parameter] public Color Color_Test { get; set; }

public int ParamtersSetCounter { get; private set; }
protected override void OnParametersSet()
{
base.OnParametersSet();
ParamtersSetCounter++;
}

private void OnTest()
{
MudDialog.ForceRender();
Expand Down
@@ -1,4 +1,5 @@
@namespace MudBlazor.UnitTests.TestComponents
@inject IDialogService DialogService

<MudButton Variant="Variant.Filled" OnClick="()=>visible=true">Open</MudButton>

Expand All @@ -9,6 +10,7 @@
</DialogContent>
<DialogActions>
<MudButton Color="Color.Primary" OnClick="()=>visible=false">Close</MudButton>
<MudButton Color="Color.Primary" OnClick="CloseAndOpen">Close and open</MudButton>
</DialogActions>
</MudDialog>

Expand All @@ -18,5 +20,10 @@
bool visible;
private int rating;

Task CloseAndOpen() {
visible=false;
return DialogService.ShowMessageBox(title: "hello from inline", message: "BUG4871", yesText: "BUG4871");
}

private DialogOptions inlineOptions = new() { FullWidth = true };
}
31 changes: 31 additions & 0 deletions src/MudBlazor.UnitTests/Components/DialogTests.cs
Expand Up @@ -257,6 +257,7 @@ public async Task DialogShouldNotOverwriteParameters()
//Console.WriteLine(comp.Markup);

((DialogWithParameters)dialogReference.Dialog).TestValue.Should().Be("new_test");
((DialogWithParameters)dialogReference.Dialog).ParamtersSetCounter.Should().Be(1);
textField.Text.Should().Be("new_test");
}

Expand Down Expand Up @@ -416,6 +417,36 @@ public async Task DialogHandlesOnBackdropClickEvent()
comp.Find("div.mud-dialog-title").TrimmedText().Should().Be("Title: Backdrop clicked");
}

/// <summary>
/// Open Inline Dialog and the from the inline dialog another normal dialog
/// while closing the inline dialog.
/// https://github.com/MudBlazor/MudBlazor/issues/4871
/// </summary>
[Test]
public async Task InlineDialogBug4871Test()
{
var comp = Context.RenderComponent<MudDialogProvider>();
comp.Markup.Trim().Should().BeEmpty();
var service = Context.Services.GetService<IDialogService>() as DialogService;
service.Should().NotBe(null);
// displaying the component with the inline dialog only renders the open button
var comp1 = Context.RenderComponent<TestInlineDialog>();
comp1.FindComponents<MudButton>().Count.Should().Be(1);
// open the dialog
comp1.Find("button").Click();
comp1.WaitForAssertion(() =>
comp.Find("div.mud-dialog-container").Should().NotBe(null)
);
comp.Find("p.mud-typography").TrimmedText().Should().Be("Wabalabadubdub!");
comp.Find("div.mud-dialog").GetAttribute("class").Should().Contain("mud-dialog-width-full");
// close by click on ok button
comp.FindAll("button").Last().Click();
comp.WaitForAssertion(() => comp.FindComponent<MudMessageBox>());
var messageBox = comp.FindComponent<MudMessageBox>();
messageBox.Should().NotBeNull();
messageBox.Instance.YesText.Should().Be("BUG4871");
}

[Test]
public async Task DialogToggleFullscreenOptions()
{
Expand Down
20 changes: 13 additions & 7 deletions src/MudBlazor.UnitTests/Components/FormTests.cs
Expand Up @@ -1092,20 +1092,23 @@ public async Task FormReset_Should_ClearDatePicker()
var form = comp.FindComponent<MudForm>().Instance;
var datePickerComp = comp.FindComponent<MudDatePicker>();
var datePicker = datePickerComp.Instance;
// create test value and it's localized string representation
var testDate = new DateTime(2020, 05, 24);
var testDateString = testDate.ToShortDateString(); // locale independent test, will work e.g. in germany too

// input a date
datePickerComp.Find("input").Change("05/24/2020");
datePicker.Date.Should().Be(Convert.ToDateTime("05/24/2020"));
datePicker.Text.Should().Be("05/24/2020");
datePickerComp.Find("input").Change(testDateString);
datePicker.Date.Should().Be(testDate);
datePicker.Text.Should().Be(testDateString);
// call reset directly
await comp.InvokeAsync(() => form.Reset());
datePicker.Date.Should().BeNull();
datePicker.Text.Should().BeNullOrEmpty();

// input a date
datePickerComp.Find("input").Change("05/24/2020");
datePicker.Date.Should().Be(Convert.ToDateTime("05/24/2020"));
datePicker.Text.Should().Be("05/24/2020");
datePickerComp.Find("input").Change(testDateString);
datePicker.Date.Should().Be(testDate);
datePicker.Text.Should().Be(testDateString);
// hit reset button
comp.Find("button.reset").Click();
datePicker.Date.Should().BeNull();
Expand All @@ -1123,9 +1126,12 @@ public async Task FormReset_Should_ResetFormStateForFieldsThatWrapMudInput()
var datePickerComp = comp.FindComponent<MudDatePicker>();
var textFieldComp = comp.FindComponents<MudTextField<string>>()[1]; //the picker includes a MudTextField, so the MudTextField we want is the second in the DOM
var numericFieldComp = comp.FindComponent<MudNumericField<int?>>();
// create test value and it's localized string representation
var testDate = new DateTime(2022, 07, 29);
var testDateString = testDate.ToShortDateString(); // locale independent test, will work e.g. in germany too

form.IsValid.Should().Be(false);
datePickerComp.Find("input").Change("07/29/2022");
datePickerComp.Find("input").Change(testDateString);
form.IsValid.Should().Be(false);
textFieldComp.Find("input").Input("Some value");
form.IsValid.Should().Be(false);
Expand Down
2 changes: 0 additions & 2 deletions src/MudBlazor/Components/Dialog/DialogReference.cs
Expand Up @@ -46,8 +46,6 @@ public virtual bool Dismiss(DialogResult result)

public Task<DialogResult> Result => _resultCompletion.Task;

public bool AreParametersRendered { get; set; }

public void InjectDialog(object inst)
{
Dialog = inst;
Expand Down
5 changes: 3 additions & 2 deletions src/MudBlazor/Components/Dialog/IDialogReference.cs
Expand Up @@ -5,9 +5,9 @@
// License: MIT

using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using System.Diagnostics.CodeAnalysis;

namespace MudBlazor
{
Expand All @@ -16,7 +16,8 @@ public interface IDialogReference
Guid Id { get; }
RenderFragment RenderFragment { get; set; }

bool AreParametersRendered { get; set; }
[Obsolete("This will always return true"), ExcludeFromCodeCoverage]
bool AreParametersRendered { get => true; set { } }

Task<DialogResult> Result { get; }

Expand Down
49 changes: 34 additions & 15 deletions src/MudBlazor/Services/DialogService.cs
Expand Up @@ -13,6 +13,36 @@ namespace MudBlazor
{
public class DialogService : IDialogService
{
/// <summary>
/// This internal wrapper components prevents overwriting parameters of once
/// instanciated dialog instances
/// </summary>
private class DialogHelperComponent : IComponent
{
const string ChildContent = nameof(ChildContent);
RenderFragment _renderFragment;
RenderHandle _renderHandle;
void IComponent.Attach(RenderHandle renderHandle) => _renderHandle = renderHandle;
Task IComponent.SetParametersAsync(ParameterView parameters)
{
if (_renderFragment == null)
{
if (parameters.TryGetValue(ChildContent, out _renderFragment))
{
_renderHandle.Render(_renderFragment);
}
}
return Task.CompletedTask;
}
public static RenderFragment Wrap(RenderFragment renderFragment)
=> new RenderFragment(builder =>
{
builder.OpenComponent<DialogHelperComponent>(1);
builder.AddAttribute(2, ChildContent, renderFragment);
builder.CloseComponent();
});
}

public event Action<IDialogReference> OnDialogInstanceAdded;
public event Action<IDialogReference, DialogResult> OnDialogCloseRequested;

Expand Down Expand Up @@ -69,28 +99,17 @@ public IDialogReference Show([DynamicallyAccessedMembers(DynamicallyAccessedMemb
}
var dialogReference = CreateReference();

var dialogContent = new RenderFragment(builder =>
var dialogContent = DialogHelperComponent.Wrap(new RenderFragment(builder =>
{
var i = 0;
builder.OpenComponent(i++, contentComponent);
if (!dialogReference.AreParametersRendered)
{
foreach (var parameter in parameters)
{
builder.AddAttribute(i++, parameter.Key, parameter.Value);
}
dialogReference.AreParametersRendered = true;
}
else
foreach (var parameter in parameters)
{
i += parameters.Count;
builder.AddAttribute(i++, parameter.Key, parameter.Value);
}
builder.AddComponentReferenceCapture(i++, inst => { dialogReference.InjectDialog(inst); });
builder.CloseComponent();
});
}));
var dialogInstance = new RenderFragment(builder =>
{
builder.OpenComponent<MudDialogInstance>(0);
Expand Down

0 comments on commit b559b3d

Please sign in to comment.