Skip to content

Commit bd6b13b

Browse files
authored
feat(CardUpload): trigger Validate when delete file (#7434)
* refactor: 增加条件判断 * doc: 更新文档注释 * test: 更新单元测试 * test: 更新单元测试 * test: 更新单元测试 * test: 更新单元测试 * chore: bump version 10.1.5-beta05
1 parent 8a9748e commit bd6b13b

10 files changed

Lines changed: 118 additions & 21 deletions

File tree

src/BootstrapBlazor/BootstrapBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>10.1.5-beta04</Version>
4+
<Version>10.1.5-beta05</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,10 @@ public override async Task ToggleMessage(IReadOnlyCollection<ValidationResult> r
187187

188188
ValidateModule ??= await LoadValidateModule();
189189

190-
var invalidItems = IsInValidOnAddItem
191-
? [new { Id = AddId, _results.First().ErrorMessage }]
192-
: _results.Select(i => new { Id = i.MemberNames.FirstOrDefault(), i.ErrorMessage }).ToList();
193-
194190
var items = IsInValidOnAddItem
195191
? [AddId]
196192
: Files.Select(i => i.ValidateId).ToList();
197-
193+
var invalidItems = _results.GetInvalidItems(IsInValidOnAddItem, AddId);
198194
var addId = IsInValidOnAddItem ? null : AddId;
199195
await ValidateModule.InvokeVoidAsync("executeUpload", items, invalidItems, addId);
200196
}

src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,10 @@ public override async Task ToggleMessage(IReadOnlyCollection<ValidationResult> r
176176

177177
ValidateModule ??= await LoadValidateModule();
178178

179-
var invalidItems = IsInValidOnAddItem
180-
? [new { Id = AddId, _results.First().ErrorMessage }]
181-
: _results.Select(i => new { Id = i.MemberNames.FirstOrDefault(), i.ErrorMessage }).ToList();
182-
183179
var items = IsInValidOnAddItem
184180
? [AddId]
185181
: Files.Select(i => i.ValidateId).ToList();
186-
182+
var invalidItems = _results.GetInvalidItems(IsInValidOnAddItem, AddId);
187183
var addId = IsInValidOnAddItem ? null : AddId;
188184
await ValidateModule.InvokeVoidAsync("executeUpload", items, invalidItems, addId);
189185
}

src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the Apache 2.0 License
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
55

66
namespace BootstrapBlazor.Components;
77

88
/// <summary>
9-
/// PreviewListUploadBase 基类
9+
/// FileListUploadBase 基类
1010
/// </summary>
1111
/// <typeparam name="TValue"></typeparam>
1212
public class FileListUploadBase<TValue> : UploadBase<TValue>

src/BootstrapBlazor/Components/Upload/UploadBase.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ protected async Task OnFileChange(InputFileChangeEventArgs args)
190190
await OnAllFileUploaded(items);
191191
}
192192

193+
UpdateValue(items);
194+
}
195+
196+
private void UpdateValue(List<UploadFile> items)
197+
{
193198
if (ValueType.IsAssignableTo(typeof(IEnumerable<UploadFile>)))
194199
{
195200
CurrentValue = (TValue)(object)items;
@@ -248,6 +253,8 @@ protected virtual async Task<bool> OnFileDelete(UploadFile item)
248253
UploadFiles.Remove(item);
249254
DefaultFileList?.Remove(item);
250255
_filesCache = null;
256+
257+
UpdateValue(Files);
251258
}
252259
StateHasChanged();
253260
return ret;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
5+
6+
namespace BootstrapBlazor.Components;
7+
8+
readonly record struct UploadValidateItem(string? Id, string? ErrorMessage);

src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using Microsoft.AspNetCore.Components.Forms;
77
using Microsoft.Extensions.Localization;
8+
using System.Collections;
89
using System.Collections.Concurrent;
910
using System.Linq.Expressions;
1011
using System.Reflection;
@@ -508,7 +509,14 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext
508509
else
509510
{
510511
// 未选择文件
511-
propertyValue = null;
512+
if (propertyValue is string)
513+
{
514+
515+
}
516+
else if (propertyValue is IEnumerable)
517+
{
518+
propertyValue = null;
519+
}
512520
ValidateDataAnnotations(propertyValue, context, messages, pi);
513521
}
514522

src/BootstrapBlazor/Extensions/ValidateContextExtensions.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the Apache 2.0 License
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
@@ -42,4 +42,8 @@ public static ValidationResult GetValidationResult(this ValidationContext contex
4242
var memberNames = string.IsNullOrEmpty(context.MemberName) ? null : new string[] { context.MemberName };
4343
return new ValidationResult(errorMessage, memberNames);
4444
}
45+
46+
internal static List<UploadValidateItem> GetInvalidItems(this IReadOnlyCollection<ValidationResult> source, bool isInValidOnAddItem, string? newId) => isInValidOnAddItem
47+
? [new UploadValidateItem() { Id = newId, ErrorMessage = source.First().ErrorMessage }]
48+
: source.Select(i => new UploadValidateItem() { Id = i.MemberNames.FirstOrDefault(), ErrorMessage = i.ErrorMessage }).ToList();
4549
}

test/UnitTest/Components/UploadAvatarTest.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,26 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha
286286
await cut.InvokeAsync(() => items[1].Click());
287287
}
288288

289+
[Fact]
290+
public void UploadValidateItem_Ok()
291+
{
292+
var type = Type.GetType("BootstrapBlazor.Components.UploadValidateItem, BootstrapBlazor");
293+
Assert.NotNull(type);
294+
295+
var instance = Activator.CreateInstance(type, ["addId", "mock_ErrorMessage"]);
296+
var propertyInfo = type.GetProperty("Id");
297+
Assert.NotNull(propertyInfo);
298+
299+
var v = propertyInfo.GetValue(instance, null);
300+
Assert.Equal("addId", v);
301+
302+
propertyInfo = type.GetProperty("ErrorMessage");
303+
Assert.NotNull(propertyInfo);
304+
305+
v = propertyInfo.GetValue(instance, null);
306+
Assert.Equal("mock_ErrorMessage", v);
307+
}
308+
289309
private class Person
290310
{
291311
[Required]

test/UnitTest/Components/UploadCardTest.cs

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
55

66
using Microsoft.AspNetCore.Components.Forms;
7+
using System.ComponentModel.DataAnnotations;
78

89
namespace UnitTest.Components;
910

@@ -150,20 +151,77 @@ public void ShowFileSize_Ok()
150151
cut.DoesNotContain("upload-item-file-size");
151152
}
152153

154+
private class Dummy
155+
{
156+
[Required]
157+
public List<UploadFile>? Files { get; set; }
158+
}
159+
153160
[Fact]
154-
public void CardUpload_ValidateForm_Ok()
161+
public async Task CardUpload_ValidateForm_Ok()
155162
{
156-
var foo = new Foo();
163+
var invalid = false;
164+
var foo = new Dummy();
157165
var cut = Context.Render<ValidateForm>(pb =>
158166
{
159167
pb.Add(a => a.Model, foo);
160-
pb.AddChildContent<CardUpload<string>>(pb =>
168+
pb.AddChildContent<CardUpload<List<UploadFile>>>(pb =>
169+
{
170+
pb.Add(a => a.Accept, "Image");
171+
pb.Add(a => a.Value, foo.Files);
172+
pb.Add(a => a.ValueChanged, EventCallback.Factory.Create<List<UploadFile>?>(this, v => foo.Files = v));
173+
pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, "Files", typeof(List<UploadFile>)));
174+
pb.Add(a => a.AllowExtensions, [".jpg"]);
175+
pb.Add(a => a.ShowDeleteButton, true);
176+
});
177+
pb.Add(a => a.OnValidSubmit, context =>
178+
{
179+
invalid = false;
180+
return Task.CompletedTask;
181+
});
182+
pb.Add(a => a.OnInvalidSubmit, context =>
161183
{
162-
pb.Add(a => a.Value, foo.Name);
163-
pb.Add(a => a.ValueExpression, foo.GenerateValueExpression());
184+
invalid = true;
185+
return Task.CompletedTask;
164186
});
165187
});
166-
cut.Contains("form-label");
188+
189+
// 提交表单
190+
var form = cut.Find("form");
191+
await cut.InvokeAsync(() => form.Submit());
192+
Assert.True(invalid);
193+
194+
var input = cut.FindComponent<InputFile>();
195+
await cut.InvokeAsync(async () =>
196+
{
197+
await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List<MockBrowserFile>()
198+
{
199+
new()
200+
}));
201+
form.Submit();
202+
});
203+
Assert.False(invalid);
204+
205+
// 设置 Disabled 取消校验
206+
var upload = cut.FindComponent<CardUpload<List<UploadFile>>>();
207+
upload.Render(pb =>
208+
{
209+
pb.Add(a => a.IsDisabled, true);
210+
});
211+
212+
Assert.DoesNotContain("is-invalid", upload.Markup);
213+
214+
upload.Render(pb =>
215+
{
216+
pb.Add(a => a.IsDisabled, false);
217+
});
218+
219+
var items = cut.FindAll(".btn-outline-danger");
220+
Assert.Single(items);
221+
await cut.InvokeAsync(() => items[0].Click());
222+
223+
form = cut.Find("form");
224+
await cut.InvokeAsync(() => form.Submit());
167225
}
168226

169227
[Fact]

0 commit comments

Comments
 (0)