diff --git a/change/@ni-nimble-angular-7cf42a56-d9cf-45ba-90cf-25f5e337cc00.json b/change/@ni-nimble-angular-7cf42a56-d9cf-45ba-90cf-25f5e337cc00.json new file mode 100644 index 0000000000..45f9d3e711 --- /dev/null +++ b/change/@ni-nimble-angular-7cf42a56-d9cf-45ba-90cf-25f5e337cc00.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Angular support for checkbox errors", + "packageName": "@ni/nimble-angular", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-blazor-2fe9754e-dc45-42b5-af23-c457ac37170c.json b/change/@ni-nimble-blazor-2fe9754e-dc45-42b5-af23-c457ac37170c.json new file mode 100644 index 0000000000..54db8016b6 --- /dev/null +++ b/change/@ni-nimble-blazor-2fe9754e-dc45-42b5-af23-c457ac37170c.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Blazor support for checkbox errors", + "packageName": "@ni/nimble-blazor", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/angular-workspace/nimble-angular/src/directives/checkbox/nimble-checkbox.directive.ts b/packages/angular-workspace/nimble-angular/src/directives/checkbox/nimble-checkbox.directive.ts index a7706e33a4..13c91e861a 100644 --- a/packages/angular-workspace/nimble-angular/src/directives/checkbox/nimble-checkbox.directive.ts +++ b/packages/angular-workspace/nimble-angular/src/directives/checkbox/nimble-checkbox.directive.ts @@ -36,5 +36,21 @@ export class NimbleCheckboxDirective { this.renderer.setProperty(this.elementRef.nativeElement, 'indeterminate', toBooleanProperty(value)); } + public get errorText(): string | undefined { + return this.elementRef.nativeElement.errorText; + } + + @Input('error-text') public set errorText(value: string | undefined) { + this.renderer.setProperty(this.elementRef.nativeElement, 'errorText', value); + } + + public get errorVisible(): boolean { + return this.elementRef.nativeElement.errorVisible; + } + + @Input('error-visible') public set errorVisible(value: BooleanValueOrAttribute) { + this.renderer.setProperty(this.elementRef.nativeElement, 'errorVisible', toBooleanProperty(value)); + } + public constructor(private readonly renderer: Renderer2, private readonly elementRef: ElementRef) {} } diff --git a/packages/angular-workspace/nimble-angular/src/directives/checkbox/tests/nimble-checkbox.directive.spec.ts b/packages/angular-workspace/nimble-angular/src/directives/checkbox/tests/nimble-checkbox.directive.spec.ts index 4f99853d11..3653ebd0b0 100644 --- a/packages/angular-workspace/nimble-angular/src/directives/checkbox/tests/nimble-checkbox.directive.spec.ts +++ b/packages/angular-workspace/nimble-angular/src/directives/checkbox/tests/nimble-checkbox.directive.spec.ts @@ -57,6 +57,16 @@ describe('Nimble checkbox', () => { expect(directive.indeterminate).toBeFalse(); expect(nativeElement.indeterminate).toBeFalse(); }); + + it('has expected defaults for errorVisible', () => { + expect(directive.errorVisible).toBeFalse(); + expect(nativeElement.errorVisible).toBeFalse(); + }); + + it('has expected defaults for errorText', () => { + expect(directive.errorText).toBeUndefined(); + expect(nativeElement.errorText).toBeUndefined(); + }); }); describe('with template string values', () => { @@ -65,7 +75,9 @@ describe('Nimble checkbox', () => { + indeterminate + error-visible + error-text="Error message"> ` }) class TestHostComponent { @@ -102,6 +114,16 @@ describe('Nimble checkbox', () => { expect(directive.indeterminate).toBeTrue(); expect(nativeElement.indeterminate).toBeTrue(); }); + + it('will use template string values for errorVisible', () => { + expect(directive.errorVisible).toBeTrue(); + expect(nativeElement.errorVisible).toBeTrue(); + }); + + it('will use template string values for errorText', () => { + expect(directive.errorText).toBe('Error message'); + expect(nativeElement.errorText).toBe('Error message'); + }); }); describe('with property bound values', () => { @@ -110,7 +132,9 @@ describe('Nimble checkbox', () => { + [indeterminate]="indeterminate" + [error-text]="errorText" + [error-visible]="errorVisible"> ` }) @@ -120,6 +144,8 @@ describe('Nimble checkbox', () => { public disabled = false; public checked = false; public indeterminate = false; + public errorText = 'initial value'; + public errorVisible = false; } let fixture: ComponentFixture; @@ -169,6 +195,28 @@ describe('Nimble checkbox', () => { expect(directive.indeterminate).toBeTrue(); expect(nativeElement.indeterminate).toBeTrue(); }); + + it('can be configured with property binding for errorText', () => { + expect(directive.errorText).toBe('initial value'); + expect(nativeElement.errorText).toBe('initial value'); + + fixture.componentInstance.errorText = 'new value'; + fixture.detectChanges(); + + expect(directive.errorText).toBe('new value'); + expect(nativeElement.errorText).toBe('new value'); + }); + + it('can be configured with property binding for errorVisible', () => { + expect(directive.errorVisible).toBeFalse(); + expect(nativeElement.errorVisible).toBeFalse(); + + fixture.componentInstance.errorVisible = true; + fixture.detectChanges(); + + expect(directive.errorVisible).toBeTrue(); + expect(nativeElement.errorVisible).toBeTrue(); + }); }); describe('with attribute bound values', () => { @@ -176,7 +224,9 @@ describe('Nimble checkbox', () => { template: ` + [attr.checked]="checked" + [attr.error-text]="errorText" + [attr.error-visible]="errorVisible"> ` }) @@ -185,6 +235,8 @@ describe('Nimble checkbox', () => { @ViewChild('checkbox', { read: ElementRef }) public elementRef: ElementRef; public disabled: BooleanValueOrAttribute = null; public checked: BooleanValueOrAttribute = null; + public errorText = 'initial value'; + public errorVisible: BooleanValueOrAttribute = null; } let fixture: ComponentFixture; @@ -224,6 +276,28 @@ describe('Nimble checkbox', () => { expect(nativeElement.checked).toBeTrue(); }); + it('can be configured with attribute binding for errorText', () => { + expect(directive.errorText).toBe('initial value'); + expect(nativeElement.errorText).toBe('initial value'); + + fixture.componentInstance.errorText = 'new value'; + fixture.detectChanges(); + + expect(directive.errorText).toBe('new value'); + expect(nativeElement.errorText).toBe('new value'); + }); + + it('can be configured with attribute binding for errorVisible', () => { + expect(directive.errorVisible).toBeFalse(); + expect(nativeElement.errorVisible).toBeFalse(); + + fixture.componentInstance.errorVisible = ''; + fixture.detectChanges(); + + expect(directive.errorVisible).toBeTrue(); + expect(nativeElement.errorVisible).toBeTrue(); + }); + // indeterminate property does not have a matching attribute }); }); diff --git a/packages/blazor-workspace/NimbleBlazor/Components/NimbleCheckbox.razor b/packages/blazor-workspace/NimbleBlazor/Components/NimbleCheckbox.razor index 20d551bb05..01423e0fab 100644 --- a/packages/blazor-workspace/NimbleBlazor/Components/NimbleCheckbox.razor +++ b/packages/blazor-workspace/NimbleBlazor/Components/NimbleCheckbox.razor @@ -6,6 +6,8 @@ indeterminate="@Indeterminate" required="@Required" readonly="@ReadOnly" + error-visible="@ErrorVisible" + error-text="@ErrorText" @attributes="AdditionalAttributes"> @ChildContent diff --git a/packages/blazor-workspace/NimbleBlazor/Components/NimbleCheckbox.razor.cs b/packages/blazor-workspace/NimbleBlazor/Components/NimbleCheckbox.razor.cs index 0fbf651529..1429f79197 100644 --- a/packages/blazor-workspace/NimbleBlazor/Components/NimbleCheckbox.razor.cs +++ b/packages/blazor-workspace/NimbleBlazor/Components/NimbleCheckbox.razor.cs @@ -17,6 +17,12 @@ public partial class NimbleCheckbox : NimbleInputBase [Parameter] public bool? ReadOnly { get; set; } + [Parameter] + public bool? ErrorVisible { get; set; } + + [Parameter] + public string? ErrorText { get; set; } + [Parameter] public RenderFragment? ChildContent { get; set; } diff --git a/packages/blazor-workspace/Tests/NimbleBlazor.Tests/Unit/Components/NimbleCheckboxTests.cs b/packages/blazor-workspace/Tests/NimbleBlazor.Tests/Unit/Components/NimbleCheckboxTests.cs index 39f60a9b97..b9d2ee4979 100644 --- a/packages/blazor-workspace/Tests/NimbleBlazor.Tests/Unit/Components/NimbleCheckboxTests.cs +++ b/packages/blazor-workspace/Tests/NimbleBlazor.Tests/Unit/Components/NimbleCheckboxTests.cs @@ -1,3 +1,5 @@ +using System; +using System.Linq.Expressions; using Bunit; using Xunit; @@ -28,4 +30,27 @@ public void NimbleCheckbox_SupportsAdditionalAttributes() var exception = Record.Exception(() => context.RenderComponent(ComponentParameter.CreateParameter("class", "foo"))); Assert.Null(exception); } + + [Fact] + public void NimbleCheckboxErrorText_AttributeIsSet() + { + var checkbox = RenderNimbleCheckboxWithPropertySet(x => x.ErrorText, "bad value"); + + Assert.Contains("error-text=\"bad value\"", checkbox.Markup); + } + + [Fact] + public void NimbleCheckboxErrorVisible_AttributeIsSet() + { + var checkbox = RenderNimbleCheckboxWithPropertySet(x => x.ErrorVisible, true); + + Assert.Contains("error-visible", checkbox.Markup); + } + + private IRenderedComponent RenderNimbleCheckboxWithPropertySet(Expression> propertyGetter, TProperty propertyValue) + { + var context = new TestContext(); + context.JSInterop.Mode = JSRuntimeMode.Loose; + return context.RenderComponent(p => p.Add(propertyGetter, propertyValue)); + } }