diff --git a/src/app/shared/components/form-input/form-input.component.html b/src/app/shared/components/form-input/form-input.component.html index b1ef73456..0b56d1a82 100644 --- a/src/app/shared/components/form-input/form-input.component.html +++ b/src/app/shared/components/form-input/form-input.component.html @@ -15,26 +15,28 @@ /> } @if (type === 'select') { - -} -@if (type === 'select') { -
- {{ getOptionTextFromValue(control.value) || placeholder }} +
+ +
}
diff --git a/src/app/shared/components/form-input/form-input.component.scss b/src/app/shared/components/form-input/form-input.component.scss index 6deabe989..5bc44eafc 100644 --- a/src/app/shared/components/form-input/form-input.component.scss +++ b/src/app/shared/components/form-input/form-input.component.scss @@ -3,3 +3,41 @@ cursor: not-allowed; user-select: none; } + +.select-wrapper { + position: relative; + width: 100%; + border: 1px solid #ced4da; + padding: 10px 0px; +} + +.real-select { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0; + z-index: 2; + cursor: pointer; +} + +.input-vertical-select-placeholder { + position: relative; + z-index: 1; +} + +.select-wrapper { + position: relative; + width: 100%; +} + +.styled-select { + width: 100%; + cursor: pointer; +} + +.open-toggle { + cursor: pointer; + top: 24px; +} diff --git a/src/app/shared/components/form-input/form-input.component.spec.ts b/src/app/shared/components/form-input/form-input.component.spec.ts new file mode 100644 index 000000000..531ffaf80 --- /dev/null +++ b/src/app/shared/components/form-input/form-input.component.spec.ts @@ -0,0 +1,106 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { + FormsModule, + ReactiveFormsModule, + UntypedFormControl, +} from '@angular/forms'; +import { By } from '@angular/platform-browser'; +import { + FormInputComponent, + FormInputSelectOption, +} from './form-input.component'; + +describe('FormInputComponent', () => { + let component: FormInputComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [FormInputComponent], + imports: [FormsModule, ReactiveFormsModule], + }).compileComponents(); + + fixture = TestBed.createComponent(FormInputComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should render a text input when type is not "select"', () => { + component.type = 'text'; + component.fieldName = 'username'; + component.placeholder = 'Enter username'; + component.control = new UntypedFormControl(''); + fixture.detectChanges(); + + const inputEl = fixture.debugElement.query(By.css('input.form-control')); + + expect(inputEl).toBeTruthy(); + expect(inputEl.nativeElement.placeholder).toBe('Enter username'); + }); + + it('should render a select when type is "select"', () => { + component.type = 'select'; + component.fieldName = 'country'; + component.placeholder = 'Select country'; + component.selectOptions = [ + { value: 'us', text: 'USA' }, + { value: 'ca', text: 'Canada' }, + ]; + component.control = new UntypedFormControl(''); + fixture.detectChanges(); + + const selectEl = fixture.debugElement.query(By.css('select')); + + expect(selectEl).toBeTruthy(); + const options = selectEl.queryAll(By.css('option')); + + expect(options.length).toBe(2); + }); + + it('should toggle openStatus when openSelect() is called', () => { + expect(component.openStatus).toBeFalse(); + component.openSelect(); + + expect(component.openStatus).toBeTrue(); + component.openSelect(); + + expect(component.openStatus).toBeFalse(); + }); + + it('should reset openStatus and alert when handleChange() is called', () => { + spyOn(window, 'alert'); + component.openStatus = true; + component.handleChange(); + + expect(component.openStatus).toBeFalse(); + expect(window.alert).toHaveBeenCalledWith('Element selected... closed'); + }); + + it('should display the correct option text from value', () => { + const options: FormInputSelectOption[] = [ + { text: 'Apple', value: 'a' }, + { text: 'Banana', value: 'b' }, + ]; + component.selectOptions = options; + const result = component.getOptionTextFromValue('b'); + + expect(result).toBe('Banana'); + }); + + it('should hide label if value is empty and type is number', () => { + component.type = 'number'; + component.control = new UntypedFormControl(''); + + expect(component.isLabelHidden()).toBeTrue(); + }); + + it('should not hide label if type is date', () => { + component.type = 'date'; + component.control = new UntypedFormControl(''); + + expect(component.isLabelHidden()).toBeFalse(); + }); +}); diff --git a/src/app/shared/components/form-input/form-input.component.ts b/src/app/shared/components/form-input/form-input.component.ts index c71fe2bdc..569141a3b 100644 --- a/src/app/shared/components/form-input/form-input.component.ts +++ b/src/app/shared/components/form-input/form-input.component.ts @@ -47,6 +47,8 @@ export class FormInputComponent implements OnInit, AfterViewInit { @HostBinding('class.right-align') rightAlign = false; @HostBinding('class.input-vertical') inputVertical = true; + openStatus = false; + @Input() config: FormInputConfig; constructor(private element: ElementRef) {} @@ -125,4 +127,11 @@ export class FormInputComponent implements OnInit, AfterViewInit { getOptionTextFromValue(value: string) { return find(this.selectOptions, { value })?.text; } + openSelect() { + this.openStatus = !this.openStatus; + } + + handleChange() { + this.openStatus = false; + } }