Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Blazor and Angular support for the checkbox error state #2484

Merged
merged 18 commits into from
Dec 2, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Angular support for checkbox errors",
"packageName": "@ni/nimble-angular",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Blazor support for checkbox errors",
"packageName": "@ni/nimble-blazor",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Checkbox>) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand All @@ -65,7 +75,9 @@ describe('Nimble checkbox', () => {
<nimble-checkbox #checkbox
disabled
checked
indeterminate>
indeterminate
error-visible
error-text="Error message">
</nimble-checkbox>`
})
class TestHostComponent {
Expand Down Expand Up @@ -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', () => {
Expand All @@ -110,7 +132,9 @@ describe('Nimble checkbox', () => {
<nimble-checkbox #checkbox
[disabled]="disabled"
[checked]="checked"
[indeterminate]="indeterminate">
[indeterminate]="indeterminate"
[error-text]="errorText"
[error-visible]="errorVisible">
</nimble-checkbox>
`
})
Expand All @@ -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<TestHostComponent>;
Expand Down Expand Up @@ -169,14 +195,38 @@ 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', () => {
@Component({
template: `
<nimble-checkbox #checkbox
[attr.disabled]="disabled"
[attr.checked]="checked">
[attr.checked]="checked"
[attr.error-text]="errorText"
[attr.error-visible]="errorVisible">
</nimble-checkbox>
`
})
Expand All @@ -185,6 +235,8 @@ describe('Nimble checkbox', () => {
@ViewChild('checkbox', { read: ElementRef }) public elementRef: ElementRef<Checkbox>;
public disabled: BooleanValueOrAttribute = null;
public checked: BooleanValueOrAttribute = null;
public errorText = 'initial value';
public errorVisible: BooleanValueOrAttribute = null;
}

let fixture: ComponentFixture<TestHostComponent>;
Expand Down Expand Up @@ -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
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
indeterminate="@Indeterminate"
required="@Required"
readonly="@ReadOnly"
error-visible="@ErrorVisible"
error-text="@ErrorText"
@attributes="AdditionalAttributes">
@ChildContent
</nimble-checkbox>
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public partial class NimbleCheckbox : NimbleInputBase<bool>
[Parameter]
public bool? ReadOnly { get; set; }

[Parameter]
public bool? ErrorVisible { get; set; }

[Parameter]
public string? ErrorText { get; set; }

[Parameter]
public RenderFragment? ChildContent { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;
using System.Linq.Expressions;
using Bunit;
using Xunit;

Expand Down Expand Up @@ -28,4 +30,27 @@ public void NimbleCheckbox_SupportsAdditionalAttributes()
var exception = Record.Exception(() => context.RenderComponent<NimbleCheckbox>(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<NimbleCheckbox> RenderNimbleCheckboxWithPropertySet<TProperty>(Expression<Func<NimbleCheckbox, TProperty>> propertyGetter, TProperty propertyValue)
{
var context = new TestContext();
context.JSInterop.Mode = JSRuntimeMode.Loose;
return context.RenderComponent<NimbleCheckbox>(p => p.Add(propertyGetter, propertyValue));
}
}
Loading