diff --git a/projects/novo-elements/src/elements/date-picker/DatePicker.ts b/projects/novo-elements/src/elements/date-picker/DatePicker.ts index f05df2cde..48e2231cb 100644 --- a/projects/novo-elements/src/elements/date-picker/DatePicker.ts +++ b/projects/novo-elements/src/elements/date-picker/DatePicker.ts @@ -159,6 +159,9 @@ export class NovoDatePickerElement implements ControlValueAccessor, OnInit { @Input() disabledDateMessage: string; + @Input() + dateForInitialView?: Date; + // Select callback for output @Output() onSelect: EventEmitter = new EventEmitter(false); @@ -260,7 +263,9 @@ export class NovoDatePickerElement implements ControlValueAccessor, OnInit { if (this.model) { this.modelToSelection(this.model); } - if (this.selection && this.selection.length) { + if (this.dateForInitialView) { + this.updateView(this.dateForInitialView); + } else if (this.selection && this.selection.length) { this.updateView(this.selection[0]); } } diff --git a/projects/novo-elements/src/elements/date-picker/DatePickerInput.ts b/projects/novo-elements/src/elements/date-picker/DatePickerInput.ts index 9f6f9256a..3632f731d 100644 --- a/projects/novo-elements/src/elements/date-picker/DatePickerInput.ts +++ b/projects/novo-elements/src/elements/date-picker/DatePickerInput.ts @@ -61,6 +61,7 @@ const DATE_VALUE_ACCESSOR = { [ngModel]="value" [weekStart]="weekStart" [hideFooter]="hideFooter" + [dateForInitialView]="dateForInitialView" > `, @@ -143,6 +144,11 @@ export class NovoDatePickerInputElement implements OnInit, OnChanges, AfterViewI */ @Input() disabledDateMessage: string; + /** + * An optional date/month to show in the DatePicker initially besides the current date/month + */ + @Input() + dateForInitialView?: Date; /** * Day of the week the calendar should display first, Sunday=0...Saturday=6 **/ diff --git a/projects/novo-elements/src/elements/picker/Picker.spec.ts b/projects/novo-elements/src/elements/picker/Picker.spec.ts index 88f42e578..01f6b43a1 100644 --- a/projects/novo-elements/src/elements/picker/Picker.spec.ts +++ b/projects/novo-elements/src/elements/picker/Picker.spec.ts @@ -316,6 +316,62 @@ describe('Elements: NovoPickerElement', () => { })); }); + describe('clearValue', () => { + beforeEach(() => { + component._value = 'initialValue'; + component.term = 'initialTerm'; + component.popup = { + instance: { + customTextValue: 'popupValue', + }, + }; + component.select = { + emit: jest.fn() + } as unknown; + component.changed = { + emit: jest.fn() + } as unknown; + spyOn(component, 'onModelChange'); + spyOn(component, 'hideResults'); + }); + + it('should clear the value, emit the new value, and optionally clear the term', () => { + component.clearValue(true); + + expect(component._value).toBeNull(); + expect(component.select.emit).toHaveBeenCalledWith(null); + expect(component.changed.emit).toHaveBeenCalledWith({ value: null, rawValue: { label: '', value: null } }); + expect(component.onModelChange).toHaveBeenCalledWith(null); + expect(component.term).toBe(''); + expect(component.popup.instance.customTextValue).toBeNull(); + expect(component.hideResults).toHaveBeenCalled(); + }); + it('should clear the value and emit the new value without clearing the term', () => { + component.clearValue(false); + + expect(component._value).toBeNull(); + expect(component.select.emit).toHaveBeenCalledWith(null); + expect(component.changed.emit).toHaveBeenCalledWith({ value: null, rawValue: { label: '', value: null } }); + expect(component.onModelChange).toHaveBeenCalledWith(null); + expect(component.term).toBe('initialTerm'); + expect(component.popup.instance.customTextValue).toBe('popupValue'); + expect(component.hideResults).not.toHaveBeenCalled(); + }); + it('should not try to clear out customTextValue if popup and popup.instance are undefined', () => { + component.popup = undefined; + component.clearValue(true); + + expect(component.popup).toBeUndefined(); + + component.popup = { + instance: undefined, + }; + component.clearValue(true); + + expect(component.popup.instance).toBeUndefined(); + }); + }); + describe('Method: registerOnChange()', () => { it('should be defined.', () => { expect(component.registerOnChange).toBeDefined(); diff --git a/projects/novo-elements/src/elements/picker/Picker.ts b/projects/novo-elements/src/elements/picker/Picker.ts index 6a7bb698b..8b3865cea 100644 --- a/projects/novo-elements/src/elements/picker/Picker.ts +++ b/projects/novo-elements/src/elements/picker/Picker.ts @@ -265,7 +265,9 @@ export class NovoPickerElement implements OnInit { if (wipeTerm) { this.term = ''; - this.popup.instance.customTextValue = null; + if (this.popup?.instance) { + this.popup.instance.customTextValue = null; + } this.hideResults(); } this.ref.markForCheck(); diff --git a/projects/novo-elements/src/elements/query-builder/condition-builder/condition-builder.component.ts b/projects/novo-elements/src/elements/query-builder/condition-builder/condition-builder.component.ts index fb3f5bd99..b42b5e373 100644 --- a/projects/novo-elements/src/elements/query-builder/condition-builder/condition-builder.component.ts +++ b/projects/novo-elements/src/elements/query-builder/condition-builder/condition-builder.component.ts @@ -187,6 +187,22 @@ export class ConditionBuilderComponent implements OnInit, OnChanges, AfterConten this.results$ = Promise.resolve(this.fieldConfig.options); } + /** + * Resets the input and operator view containers, regenerates the field templates, + * and marks the component for change detection. + * + * Use this method after updating form controls to reinitialize the input and + * operator fields so that the view reflects the latest form control changes. + * + * @returns void + */ + resetInputAndOperator(): void { + this._inputOutlet.viewContainer.clear(); + this._operatorOutlet.viewContainer.clear(); + this.createFieldTemplates(); + this.cdr.markForCheck(); + } + getField() { const field = this.parentForm?.value?.field; if (!field) return null;