Skip to content

Commit efb2508

Browse files
authored
feat(Select): add LookupService parameter (#4898)
* refactor: 增加 LookupService 扩展方法 * refactor: 增加 LookupService 参数 * feat: 增加扩展方法 * feat: 支持 LookupService 服务 * test: 提高代码覆盖率 * refactor: 增加 LookupService 支持 * feat: 增加 Select 组件对 LookupService 自动赋值逻辑
1 parent c4901f2 commit efb2508

File tree

8 files changed

+80
-55
lines changed

8 files changed

+80
-55
lines changed

src/BootstrapBlazor/Components/EditorForm/EditorForm.razor

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,9 @@
4040
</div>
4141
}
4242

43-
@if (!_inited)
44-
{
45-
<div class="ef-loading">
46-
<Spinner Color="Color.Primary" />
47-
</div>
48-
}
43+
<div class="ef-loading">
44+
<Spinner Color="Color.Primary" />
45+
</div>
4946
</div>
5047

5148
@code

src/BootstrapBlazor/Components/EditorForm/EditorForm.razor.cs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ public partial class EditorForm<TModel> : IShowLabel
191191
.GroupBy(i => i.GroupOrder).OrderBy(i => i.Key)
192192
.Select(i => new KeyValuePair<string, IOrderedEnumerable<IEditorItem>>(i.First().GroupName!, i.OrderBy(x => x.Order)));
193193

194-
private bool _inited;
195194
private List<IEditorItem>? _itemsCache;
196195

197196
private List<IEditorItem> RenderItems
@@ -238,29 +237,6 @@ protected override void OnParametersSet()
238237
_itemsCache = null;
239238
}
240239

241-
/// <summary>
242-
/// <inheritdoc/>
243-
/// </summary>
244-
/// <param name="firstRender"></param>
245-
protected override async Task OnAfterRenderAsync(bool firstRender)
246-
{
247-
await base.OnAfterRenderAsync(firstRender);
248-
249-
if (firstRender)
250-
{
251-
foreach (var item in RenderItems)
252-
{
253-
if (item.Lookup == null && !string.IsNullOrEmpty(item.LookupServiceKey))
254-
{
255-
var lookupServcie = item.LookupService ?? LookupService;
256-
item.Lookup = await lookupServcie.GetItemsAsync(item.LookupServiceKey, item.LookupServiceData);
257-
}
258-
}
259-
_inited = true;
260-
StateHasChanged();
261-
}
262-
}
263-
264240
private List<IEditorItem> GetRenderItems()
265241
{
266242
var items = new List<IEditorItem>();
@@ -315,7 +291,7 @@ private RenderFragment AutoGenerateTemplate(IEditorItem item) => builder =>
315291
else
316292
{
317293
item.PlaceHolder ??= PlaceHolderText;
318-
builder.CreateComponentByFieldType(this, item, Model, ItemChangedType, IsSearch.Value);
294+
builder.CreateComponentByFieldType(this, item, Model, ItemChangedType, IsSearch.Value, item.GetLookupService(LookupService));
319295
}
320296
};
321297

src/BootstrapBlazor/Components/Select/Select.razor.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,10 @@ private SelectedItem? SelectedRow
284284
private List<SelectedItem> GetRowsByItems()
285285
{
286286
var items = new List<SelectedItem>();
287-
items.AddRange(Items);
287+
if (Items != null)
288+
{
289+
items.AddRange(Items);
290+
}
288291
items.AddRange(_children);
289292
return items;
290293
}
@@ -306,11 +309,20 @@ protected override void OnParametersSet()
306309
{
307310
base.OnParametersSet();
308311

309-
Items ??= [];
310312
PlaceHolder ??= Localizer[nameof(PlaceHolder)];
311313
NoSearchDataText ??= Localizer[nameof(NoSearchDataText)];
312314
DropdownIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectDropdownIcon);
313315
ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectClearIcon);
316+
}
317+
318+
/// <summary>
319+
/// <inheritdoc/>
320+
/// </summary>
321+
protected override async Task OnParametersSetAsync()
322+
{
323+
await base.OnParametersSetAsync();
324+
325+
Items ??= await GetItemsAsync();
314326

315327
// 内置对枚举类型的支持
316328
if (!Items.Any() && ValueType.IsEnum())
@@ -338,6 +350,16 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
338350
}
339351
}
340352

353+
private async Task<IEnumerable<SelectedItem>> GetItemsAsync()
354+
{
355+
IEnumerable<SelectedItem>? items = null;
356+
if (LookupService != null)
357+
{
358+
items = await LookupService.GetItemsByKeyAsync(LookupServiceKey, LookupServiceData);
359+
}
360+
return items ?? [];
361+
}
362+
341363
/// <summary>
342364
/// 获得/设置 数据总条目
343365
/// </summary>

src/BootstrapBlazor/Components/Select/SelectBase.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ public abstract class SelectBase<TValue> : PopoverSelectBase<TValue>
5353
[Parameter]
5454
public RenderFragment<string>? GroupItemTemplate { get; set; }
5555

56+
/// <summary>
57+
/// 获得/设置 <see cref="ILookupService"/> 服务实例
58+
/// </summary>
59+
[Parameter]
60+
public ILookupService? LookupService { get; set; }
61+
62+
/// <summary>
63+
/// 获得/设置 <see cref="ILookupService"/> 服务获取 Lookup 数据集合键值 常用于外键自动转换为名称操作,可以通过 <see cref="LookupServiceData"/> 传递自定义数据
64+
/// </summary>
65+
[Parameter]
66+
public string? LookupServiceKey { get; set; }
67+
68+
/// <summary>
69+
/// 获得/设置 <see cref="ILookupService"/> 服务获取 Lookup 数据集合键值自定义数据,通过 <see cref="LookupServiceKey"/> 指定键值
70+
/// </summary>
71+
[Parameter]
72+
public object? LookupServiceData { get; set; }
73+
5674
/// <summary>
5775
/// 获得/设置 IIconTheme 服务实例
5876
/// </summary>

src/BootstrapBlazor/Components/Table/Table.razor.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,12 +1141,6 @@ private async Task ProcessFirstRender()
11411141
Columns.Clear();
11421142
Columns.AddRange(cols.OrderFunc());
11431143

1144-
// 准备 Lookup 数据
1145-
foreach (var column in Columns)
1146-
{
1147-
column.Lookup ??= await LookupService.GetItemsAsync(column.LookupServiceKey, column.LookupServiceData);
1148-
}
1149-
11501144
// 查看是否开启列宽序列化
11511145
_clientColumnWidths = await ReloadColumnWidthFromBrowserAsync();
11521146
ResetColumnWidth();
@@ -1329,7 +1323,7 @@ RenderFragment RenderTemplate() => col.Template == null
13291323
: col.Template(item);
13301324

13311325
RenderFragment RenderEditTemplate() => col.EditTemplate == null
1332-
? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, false))
1326+
? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, false, col.GetLookupService(LookupService)))
13331327
: col.EditTemplate(item);
13341328
}
13351329

@@ -1371,7 +1365,7 @@ void SetDynamicEditTemplate()
13711365
parameters.Add(new(nameof(ValidateBase<string>.OnValueChanged), onValueChanged.Invoke(d, col, (model, column, val) => DynamicContext.OnValueChanged(model, column, val))));
13721366
col.ComponentParameters = parameters;
13731367
}
1374-
builder.CreateComponentByFieldType(this, col, row, changedType, false);
1368+
builder.CreateComponentByFieldType(this, col, row, changedType, false, col.GetLookupService(LookupService));
13751369
};
13761370
}
13771371

src/BootstrapBlazor/Extensions/IEditorItemExtensions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ namespace BootstrapBlazor.Components;
1212
/// </summary>
1313
public static class IEditorItemExtensions
1414
{
15+
/// <summary>
16+
/// 判断当前 IEditorItem 实例是否为 Lookup 类型
17+
/// </summary>
18+
/// <param name="item"></param>
19+
/// <returns></returns>
20+
public static bool IsLookup(this IEditorItem item) => item.Lookup != null || item.LookupService != null || !string.IsNullOrEmpty(item.LookupServiceKey);
21+
1522
/// <summary>
1623
/// 判断当前 IEditorItem 实例是否可以编辑
1724
/// </summary>
@@ -110,4 +117,12 @@ bool ComplexCanWrite()
110117
internal static bool GetIgnore(this IEditorItem col) => col.Ignore ?? false;
111118

112119
internal static bool GetReadonly(this IEditorItem col) => col.Readonly ?? false;
120+
121+
/// <summary>
122+
/// 获得 ILookupService 实例
123+
/// </summary>
124+
/// <param name="item"></param>
125+
/// <param name="service"></param>
126+
/// <returns></returns>
127+
public static ILookupService GetLookupService(this IEditorItem item, ILookupService service) => item.LookupService ?? service;
113128
}

src/BootstrapBlazor/Utils/Utility.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,8 @@ public static void CreateDisplayByFieldType(this RenderTreeBuilder builder, IEdi
459459
/// <param name="item"></param>
460460
/// <param name="changedType"></param>
461461
/// <param name="isSearch"></param>
462-
public static void CreateComponentByFieldType(this RenderTreeBuilder builder, ComponentBase component, IEditorItem item, object model, ItemChangedType changedType = ItemChangedType.Update, bool isSearch = false)
462+
/// <param name="lookupService"></param>
463+
public static void CreateComponentByFieldType(this RenderTreeBuilder builder, ComponentBase component, IEditorItem item, object model, ItemChangedType changedType = ItemChangedType.Update, bool isSearch = false, ILookupService? lookupService = null)
463464
{
464465
var fieldType = item.PropertyType;
465466
var fieldName = item.GetFieldName();
@@ -468,8 +469,7 @@ public static void CreateComponentByFieldType(this RenderTreeBuilder builder, Co
468469
var fieldValue = GenerateValue(model, fieldName);
469470
var fieldValueChanged = GenerateValueChanged(component, model, fieldName, fieldType);
470471
var valueExpression = GenerateValueExpression(model, fieldName, fieldType);
471-
var lookup = item.Lookup;
472-
var componentType = item.ComponentType ?? GenerateComponentType(fieldType, item.Rows != 0, lookup);
472+
var componentType = item.ComponentType ?? GenerateComponentType(item);
473473
builder.OpenComponent(0, componentType);
474474
if (componentType.IsSubclassOf(typeof(ValidateBase<>).MakeGenericType(fieldType)))
475475
{
@@ -513,20 +513,22 @@ public static void CreateComponentByFieldType(this RenderTreeBuilder builder, Co
513513
}
514514

515515
// Nullable<bool?>
516-
if (item.ComponentType == typeof(Select<bool?>) && fieldType == typeof(bool?) && lookup == null && item.Items == null)
516+
if (item.ComponentType == typeof(Select<bool?>) && fieldType == typeof(bool?) && !item.IsLookup() && item.Items == null)
517517
{
518518
builder.AddAttribute(100, nameof(Select<bool?>.Items), GetNullableBoolItems(model, fieldName));
519519
}
520520

521521
// Lookup
522-
if (lookup != null && item.Items == null)
522+
if (item.IsLookup() && item.Items == null)
523523
{
524524
builder.AddAttribute(110, nameof(Select<SelectedItem>.ShowSearch), item.ShowSearchWhenSelect);
525-
builder.AddAttribute(120, nameof(Select<SelectedItem>.Items), lookup.Clone());
525+
builder.AddAttribute(120, nameof(Select<SelectedItem>.LookupService), lookupService);
526+
builder.AddAttribute(121, nameof(Select<SelectedItem>.LookupServiceKey), item.LookupServiceKey);
527+
builder.AddAttribute(122, nameof(Select<SelectedItem>.LookupServiceData), item.LookupServiceData);
526528
builder.AddAttribute(130, nameof(Select<SelectedItem>.StringComparison), item.LookupStringComparison);
527529
}
528530

529-
// 增加非枚举类,手动设定 ComponentType 为 Select 并且 Data 有值 自动生成下拉框
531+
// 增加非枚举类,手动设定 ComponentType 为 Select 并且 Items 有值 自动生成下拉框
530532
if (item.Items != null && item.ComponentType == typeof(Select<>).MakeGenericType(fieldType))
531533
{
532534
builder.AddAttribute(140, nameof(Select<SelectedItem>.Items), item.Items.Clone());
@@ -615,15 +617,13 @@ object ComplexPropertyValueExpression()
615617
/// <summary>
616618
/// 通过指定类型生成组件类型
617619
/// </summary>
618-
/// <param name="fieldType"></param>
619-
/// <param name="hasRows">是否为 TextArea 组件</param>
620-
/// <param name="lookup"></param>
621-
/// <returns></returns>
622-
private static Type GenerateComponentType(Type fieldType, bool hasRows, IEnumerable<SelectedItem>? lookup)
620+
/// <param name="item"></param>
621+
private static Type GenerateComponentType(IEditorItem item)
623622
{
623+
var fieldType = item.PropertyType;
624624
Type? ret = null;
625625
var type = (Nullable.GetUnderlyingType(fieldType) ?? fieldType);
626-
if (type.IsEnum || lookup != null)
626+
if (type.IsEnum || item.IsLookup())
627627
{
628628
ret = typeof(Select<>).MakeGenericType(fieldType);
629629
}
@@ -649,7 +649,7 @@ private static Type GenerateComponentType(Type fieldType, bool hasRows, IEnumera
649649
}
650650
else if (fieldType == typeof(string))
651651
{
652-
ret = hasRows ? typeof(Textarea) : typeof(BootstrapInput<>).MakeGenericType(typeof(string));
652+
ret = item.Rows > 0 ? typeof(Textarea) : typeof(BootstrapInput<>).MakeGenericType(typeof(string));
653653
}
654654
return ret ?? typeof(BootstrapInput<>).MakeGenericType(fieldType);
655655
}

test/UnitTest/Components/EditorFormTest.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,9 @@ public async Task LookupServiceKey_Ok()
443443
var lookup = await lookupService.GetItemsAsync("FooLookup", "");
444444
Assert.NotNull(lookup);
445445
Assert.Equal(lookup.Count(), select.Instance.Items.Count());
446+
447+
lookup = await lookupService.GetItemsAsync(null, "");
448+
Assert.Null(lookup);
446449
}
447450

448451
[Fact]

0 commit comments

Comments
 (0)