From 280d85aab3c4cb9c78d4a336d2babbfd9bc33b8d Mon Sep 17 00:00:00 2001 From: mollykreis <20542556+mollykreis@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:17:45 -0500 Subject: [PATCH] Support error state on radio group in Angular and Blazor (#2433) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## ๐Ÿคจ Rationale Resolves #2019 by adding Angular and Blazor support for `error-text` and `error-visible` on the `nimble-radio-group`. ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation - Expose error text and error visible on the radio group in Angular and Blazor - Update Angular and Blazor example apps to put a label on the radio group ## ๐Ÿงช Testing - Updated unit tests for the components - Manually verified that error text and error visible can be configured through both Angular and Blazor ## โœ… Checklist - [ ] I have updated the project documentation to reflect my changes or determined no changes are needed. --------- Co-authored-by: Milan Raj --- ...-4f066aff-68a7-4244-bfec-93033280f250.json | 7 ++ ...-9ba53191-8378-401c-a6c9-05fce98a89d0.json | 7 ++ .../app/customapp/customapp.component.html | 1 + .../nimble-radio-group.directive.ts | 16 ++++ .../nimble-radio-group.directive.spec.ts | 95 ++++++++++++++++++- .../Demo.Shared/Pages/ComponentsDemo.razor | 1 + .../Components/NimbleRadioGroup.razor | 2 + .../Components/NimbleRadioGroup.razor.cs | 12 +++ .../Unit/Components/NimbleRadioGroupTests.cs | 16 ++++ 9 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 change/@ni-nimble-angular-4f066aff-68a7-4244-bfec-93033280f250.json create mode 100644 change/@ni-nimble-blazor-9ba53191-8378-401c-a6c9-05fce98a89d0.json diff --git a/change/@ni-nimble-angular-4f066aff-68a7-4244-bfec-93033280f250.json b/change/@ni-nimble-angular-4f066aff-68a7-4244-bfec-93033280f250.json new file mode 100644 index 0000000000..30e9e20dde --- /dev/null +++ b/change/@ni-nimble-angular-4f066aff-68a7-4244-bfec-93033280f250.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Expose error state on radio-group", + "packageName": "@ni/nimble-angular", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-blazor-9ba53191-8378-401c-a6c9-05fce98a89d0.json b/change/@ni-nimble-blazor-9ba53191-8378-401c-a6c9-05fce98a89d0.json new file mode 100644 index 0000000000..4b2ae2f22d --- /dev/null +++ b/change/@ni-nimble-blazor-9ba53191-8378-401c-a6c9-05fce98a89d0.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Expose error state on radio-group", + "packageName": "@ni/nimble-blazor", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/angular-workspace/example-client-app/src/app/customapp/customapp.component.html b/packages/angular-workspace/example-client-app/src/app/customapp/customapp.component.html index 112b7c9e39..0012056b01 100644 --- a/packages/angular-workspace/example-client-app/src/app/customapp/customapp.component.html +++ b/packages/angular-workspace/example-client-app/src/app/customapp/customapp.component.html @@ -74,6 +74,7 @@
Radio Buttons
+ Fruit Apple Banana Mango diff --git a/packages/angular-workspace/nimble-angular/src/directives/radio-group/nimble-radio-group.directive.ts b/packages/angular-workspace/nimble-angular/src/directives/radio-group/nimble-radio-group.directive.ts index ab8f734697..d23fd3205a 100644 --- a/packages/angular-workspace/nimble-angular/src/directives/radio-group/nimble-radio-group.directive.ts +++ b/packages/angular-workspace/nimble-angular/src/directives/radio-group/nimble-radio-group.directive.ts @@ -38,5 +38,21 @@ export class NimbleRadioGroupDirective { this.renderer.setProperty(this.elementRef.nativeElement, 'orientation', 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/radio-group/tests/nimble-radio-group.directive.spec.ts b/packages/angular-workspace/nimble-angular/src/directives/radio-group/tests/nimble-radio-group.directive.spec.ts index 89733b336a..28d133c4e8 100644 --- a/packages/angular-workspace/nimble-angular/src/directives/radio-group/tests/nimble-radio-group.directive.spec.ts +++ b/packages/angular-workspace/nimble-angular/src/directives/radio-group/tests/nimble-radio-group.directive.spec.ts @@ -70,11 +70,28 @@ describe('Nimble radio group', () => { directive.orientation = Orientation.vertical; expect(nativeElement.orientation).toBe(Orientation.vertical); }); + + it('has expected defaults for errorText', () => { + expect(directive.errorText).toBeUndefined(); + expect(nativeElement.errorText).toBeUndefined(); + }); + + it('can use the directive to set errorText', () => { + directive.errorText = 'new value'; + expect(nativeElement.errorText).toBe('new value'); + }); }); describe('with template string values', () => { @Component({ - template: '' + template: ` + ` }) class TestHostComponent { @ViewChild('radioGroup', { read: NimbleRadioGroupDirective }) public directive: NimbleRadioGroupDirective; @@ -110,11 +127,28 @@ describe('Nimble radio group', () => { expect(directive.orientation).toBe(Orientation.vertical); expect(nativeElement.orientation).toBe(Orientation.vertical); }); + + it('will use template string values for errorText', () => { + expect(directive.errorText).toBe('error text'); + expect(nativeElement.errorText).toBe('error text'); + }); + + it('will use template string values for errorVisible', () => { + expect(directive.errorVisible).toBeTrue(); + expect(nativeElement.errorVisible).toBeTrue(); + }); }); describe('with property bound values', () => { @Component({ - template: '' + template: ` + ` }) class TestHostComponent { @ViewChild('radioGroup', { read: NimbleRadioGroupDirective }) public directive: NimbleRadioGroupDirective; @@ -122,6 +156,8 @@ describe('Nimble radio group', () => { public disabled = false; public name = 'foo'; public orientation: Orientation = Orientation.vertical; + public errorText = 'initial value'; + public errorVisible = false; } let fixture: ComponentFixture; @@ -171,11 +207,40 @@ describe('Nimble radio group', () => { expect(directive.orientation).toBe(Orientation.horizontal); expect(nativeElement.orientation).toBe(Orientation.horizontal); }); + + 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', () => { @Component({ - template: '' + template: ` + ` }) class TestHostComponent { @ViewChild('radioGroup', { read: NimbleRadioGroupDirective }) public directive: NimbleRadioGroupDirective; @@ -183,6 +248,8 @@ describe('Nimble radio group', () => { public disabled: BooleanValueOrAttribute = null; public name = 'foo'; public orientation: Orientation = Orientation.vertical; + public errorText = 'initial value'; + public errorVisible: BooleanValueOrAttribute = null; } let fixture: ComponentFixture; @@ -232,5 +299,27 @@ describe('Nimble radio group', () => { expect(directive.orientation).toBe(Orientation.horizontal); expect(nativeElement.orientation).toBe(Orientation.horizontal); }); + + 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(); + }); }); }); \ No newline at end of file diff --git a/packages/blazor-workspace/Examples/Demo.Shared/Pages/ComponentsDemo.razor b/packages/blazor-workspace/Examples/Demo.Shared/Pages/ComponentsDemo.razor index b1cfb981a1..c9a5932b31 100644 --- a/packages/blazor-workspace/Examples/Demo.Shared/Pages/ComponentsDemo.razor +++ b/packages/blazor-workspace/Examples/Demo.Shared/Pages/ComponentsDemo.razor @@ -91,6 +91,7 @@
Radio Buttons
+ Options Option 1 Option 2 Option 3 diff --git a/packages/blazor-workspace/NimbleBlazor/Components/NimbleRadioGroup.razor b/packages/blazor-workspace/NimbleBlazor/Components/NimbleRadioGroup.razor index 7126ca671b..a1977d4386 100644 --- a/packages/blazor-workspace/NimbleBlazor/Components/NimbleRadioGroup.razor +++ b/packages/blazor-workspace/NimbleBlazor/Components/NimbleRadioGroup.razor @@ -3,6 +3,8 @@ diff --git a/packages/blazor-workspace/NimbleBlazor/Components/NimbleRadioGroup.razor.cs b/packages/blazor-workspace/NimbleBlazor/Components/NimbleRadioGroup.razor.cs index 2409272603..0d017beda7 100644 --- a/packages/blazor-workspace/NimbleBlazor/Components/NimbleRadioGroup.razor.cs +++ b/packages/blazor-workspace/NimbleBlazor/Components/NimbleRadioGroup.razor.cs @@ -23,6 +23,18 @@ public partial class NimbleRadioGroup : NimbleInputBase [Parameter] public Orientation? Orientation { get; set; } + /// + /// Gets or sets whether the error state is displayed + /// + [Parameter] + public bool? ErrorVisible { get; set; } + + /// + /// Gets or sets an error message describing the error state + /// + [Parameter] + public string? ErrorText { get; set; } + /// /// Gets or sets the child content to be rendered inside the . /// diff --git a/packages/blazor-workspace/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioGroupTests.cs b/packages/blazor-workspace/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioGroupTests.cs index be2e13a6ee..26ae0a5efa 100644 --- a/packages/blazor-workspace/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioGroupTests.cs +++ b/packages/blazor-workspace/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioGroupTests.cs @@ -66,6 +66,22 @@ public void NimbleRadioGroupName_AttributeIsSet() Assert.Contains("name", radioGroup.Markup); } + [Fact] + public void NimbleRadioGroupErrorText_AttributeIsSet() + { + var radioGroup = RenderNimbleRadioGroupWithPropertySet(x => x.ErrorText, "bad value"); + + Assert.Contains("error-text=\"bad value\"", radioGroup.Markup); + } + + [Fact] + public void NimbleRadioGroupErrorVisible_AttributeIsSet() + { + var radioGroup = RenderNimbleRadioGroupWithPropertySet(x => x.ErrorVisible, true); + + Assert.Contains("error-visible", radioGroup.Markup); + } + private IRenderedComponent RenderNimbleRadioGroupWithPropertySet(Expression> propertyGetter, TProperty propertyValue) { var context = new TestContext();