Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Components/Checkbox/Checkbox.razor
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ else
@code {
RenderFragment RenderCheckbox =>
@<div @attributes="AdditionalAttributes" class="@ClassString">
<input class="@InputClassString" type="checkbox" id="@Id" disabled="@Disabled" checked="@CheckedString" data-bb-trigger-before="@TriggerBeforeValueString" data-bb-stop-propagation="@StopPropagationString" />
<input class="@InputClassString" type="checkbox" id="@Id" disabled="@Disabled" checked="@CheckedString" data-bb-stop-propagation="@StopPropagationString" />
@if (IsShowAfterLabel)
{
@RenderLabel
Expand Down
62 changes: 26 additions & 36 deletions src/BootstrapBlazor/Components/Checkbox/Checkbox.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ public partial class Checkbox<TValue> : ValidateBase<TValue>

private string? StopPropagationString => StopPropagation ? "true" : null;

private string? TriggerBeforeValueString => OnBeforeStateChanged == null ? null : "true";

/// <summary>
/// <inheritdoc/>
/// </summary>
Expand Down Expand Up @@ -159,55 +157,47 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new
{
TriggerOnBeforeStateChanged = nameof(TriggerOnBeforeStateChanged),
TriggerClick = nameof(TriggerClick),
SyncStateCallback = nameof(SyncStateCallback)
});
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, nameof(OnTriggerClickAsync));

private CheckboxState NextState => State == CheckboxState.Checked ? CheckboxState.UnChecked : CheckboxState.Checked;
/// <summary>
/// 触发 Click 方法
/// </summary>
/// <returns></returns>
public async Task TriggerClick() => await OnTriggerClickAsync();

/// <summary>
/// 触发 OnBeforeStateChanged 回调方法 由 JavaScript 调用
/// 触发 Click 方法 由 JavaScript 调用
/// </summary>
/// <returns></returns>
[JSInvokable]
public async ValueTask TriggerOnBeforeStateChanged()
public async ValueTask<bool> OnTriggerClickAsync(CheckboxState? state = null)
{
// 本组件由于支持 OnBeforeStateChanged 回调方法,所以设计上移除了 onclick 事件,改为通过 JS 调用 TriggerClick 方法
// state 有值时表示同步状态功能
if (state.HasValue)
{
State = state.Value;
return true;
}

// 调用 OnBeforeStateChanged 回调方法查看是否阻止状态改变
// 返回 true 时改变状态,返回 false 时不改变状态阻止状态改变 preventDefault
var val = State == CheckboxState.Checked ? CheckboxState.UnChecked : CheckboxState.Checked;
if (OnBeforeStateChanged != null)
{
var ret = await OnBeforeStateChanged(NextState);
if (ret)
var ret = await OnBeforeStateChanged(val);
if (ret == false)
{
await TriggerClick();
return false;
}
}
}

/// <summary>
/// 同步 <see cref="State"/> 值方法 由 JavaScript 调用
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
[JSInvokable]
public ValueTask SyncStateCallback(CheckboxState state)
{
State = state;
return ValueTask.CompletedTask;
}

/// <summary>
/// 触发 Click 方法 由 JavaScript 调用
/// </summary>
/// <returns></returns>
[JSInvokable]
public async ValueTask TriggerClick()
{
var render = await InternalStateChanged(NextState);
var render = await InternalStateChanged(val);
if (render)
{
StateHasChanged();
}
return true;
}

/// <summary>
Expand Down Expand Up @@ -246,7 +236,7 @@ private async Task<bool> InternalStateChanged(CheckboxState state)
/// 设置 复选框状态方法
/// </summary>
/// <param name="state"></param>
public virtual async Task SetState(CheckboxState state)
public async Task SetState(CheckboxState state)
{
if (!_paddingStateChanged)
{
Expand Down
17 changes: 3 additions & 14 deletions src/BootstrapBlazor/Components/Checkbox/Checkbox.razor.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { setIndeterminate } from "../../modules/utility.js"
import EventHandler from "../../modules/event-handler.js"

export function init(id, invoke, options) {
export function init(id, invoke, method) {
const el = document.getElementById(id);
if (el === null) {
return;
Expand All @@ -14,31 +14,20 @@ export function init(id, invoke, options) {
}

const state = el.getAttribute("data-bb-state");
const trigger = el.getAttribute("data-bb-trigger-before");

if (state) {
el.removeAttribute('data-bb-state');
await invoke.invokeMethodAsync(options.syncStateCallback, parseInt(state));

if (state === "1") {
el.parentElement.classList.remove('is-checked');
}
else {
el.parentElement.classList.add('is-checked');
}

if (trigger !== "true") {
return;
}
}

if (trigger === 'true') {
var result = await invoke.invokeMethodAsync(method, state == "1" ? 0 : 1);
if (result === false) {
e.preventDefault();
await invoke.invokeMethodAsync(options.triggerOnBeforeStateChanged);
return;
}

await invoke.invokeMethodAsync(options.triggerClick);
});
}

Expand Down
44 changes: 24 additions & 20 deletions test/UnitTest/Components/CheckboxListTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,6 @@ public void StopPropagation_Ok()
Assert.Contains("data-bb-stop-propagation=\"true\"", cut.Markup);
}

[Fact]
public async Task SyncStateCallback_Ok()
{
var cut = Context.RenderComponent<Checkbox<bool>>(builder =>
{
builder.Add(a => a.State, CheckboxState.UnChecked);
});
Assert.Equal(CheckboxState.UnChecked, cut.Instance.State);

await cut.InvokeAsync(() => cut.Instance.SyncStateCallback(CheckboxState.Checked));
Assert.Equal(CheckboxState.Checked, cut.Instance.State);
}

[Fact]
public void ShowAfterLabel_Ok()
{
Expand Down Expand Up @@ -82,14 +69,31 @@ public async Task Checkbox_OnBeforeStateChanged()
});
Assert.False(cut.Instance.Value);

await cut.InvokeAsync(cut.Instance.TriggerOnBeforeStateChanged);
await cut.InvokeAsync(cut.Instance.TriggerClick);
Assert.True(cut.Instance.Value);

confirm = false;
await cut.InvokeAsync(cut.Instance.TriggerOnBeforeStateChanged);
await cut.InvokeAsync(cut.Instance.TriggerClick);
Assert.True(cut.Instance.Value);
}

[Fact]
public async Task Checkbox_OnTriggerClickAsync()
{
var cut = Context.RenderComponent<Checkbox<bool>>();
Assert.False(cut.Instance.Value);

// JavaScript 调用 OnTriggerClickAsync 方法
var val = await cut.Instance.OnTriggerClickAsync(CheckboxState.UnChecked);

Assert.True(val);
Assert.Equal(CheckboxState.UnChecked, cut.Instance.State);

val = await cut.Instance.OnTriggerClickAsync(CheckboxState.Checked);
Assert.True(val);
Assert.Equal(CheckboxState.Checked, cut.Instance.State);
}

[Fact]
public void Checkbox_Dispose()
{
Expand All @@ -104,7 +108,7 @@ public void Checkbox_Dispose()

var methodInfo = checkbox.GetType().GetMethod("DisposeAsync", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
Assert.NotNull(methodInfo);
methodInfo.Invoke(checkbox, new object[] { false });
methodInfo.Invoke(checkbox, [false]);
}

[Fact]
Expand Down Expand Up @@ -410,20 +414,20 @@ public async Task OnMaxSelectedCountExceed_Ok()

await cut.InvokeAsync(async () =>
{
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
await checkboxes[0].Instance.TriggerClick();
});
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);

await cut.InvokeAsync(async () =>
{
await checkboxes[1].Instance.TriggerOnBeforeStateChanged();
await checkboxes[1].Instance.TriggerClick();
});
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);

// 选中第三个由于限制无法选中
await cut.InvokeAsync(async () =>
{
await checkboxes[2].Instance.TriggerOnBeforeStateChanged();
await checkboxes[2].Instance.TriggerClick();
});
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
Expand All @@ -434,7 +438,7 @@ await cut.InvokeAsync(async () =>
max = false;
await cut.InvokeAsync(async () =>
{
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
await checkboxes[0].Instance.TriggerClick();
});
Assert.Equal(CheckboxState.UnChecked, checkboxes[0].Instance.State);
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
Expand Down
8 changes: 4 additions & 4 deletions test/UnitTest/Components/TreeViewTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,20 +235,20 @@ public async Task OnMaxSelectedCountExceed_Ok()

await cut.InvokeAsync(async () =>
{
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
await checkboxes[0].Instance.TriggerClick();
});
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);

await cut.InvokeAsync(async () =>
{
await checkboxes[1].Instance.TriggerOnBeforeStateChanged();
await checkboxes[1].Instance.TriggerClick();
});
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);

// 选中第三个由于限制无法选中
await cut.InvokeAsync(async () =>
{
await checkboxes[2].Instance.TriggerOnBeforeStateChanged();
await checkboxes[2].Instance.TriggerClick();
});
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
Expand All @@ -259,7 +259,7 @@ await cut.InvokeAsync(async () =>
max = false;
await cut.InvokeAsync(async () =>
{
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
await checkboxes[0].Instance.TriggerClick();
});
Assert.Equal(CheckboxState.UnChecked, checkboxes[0].Instance.State);
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
Expand Down