Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
64 changes: 28 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,49 @@ 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 +238,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') {
const 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