Skip to content

Commit

Permalink
feat(overlay): use ViewContainerRef to create components #11671 (#11685)
Browse files Browse the repository at this point in the history
  • Loading branch information
wnvko authored Mar 14, 2023
1 parent e5e95ba commit d072852
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 99 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ All notable changes for each version of this project will be documented in this
- Added `shape` property that controls the shape of the badge and can be either `square` or `rounded`. The default shape of the badge is rounded.
- `IgxAvatar`
- **Breaking Change** The `roundShape` property has been deprecated and will be removed in a future version. Users can control the shape of the avatar by the newly added `shape` attribute that can be `square`, `rounded` or `circle`. The default shape of the avatar is `square`.
- `IgxOverlayService`
- `attach` method overload accepting `ComponentFactoryResolver` (trough `NgModuleRef`-like object) is now deprecated in line with API deprecated in Angular 13. New overload is added accepting `ViewComponentRef` that should be used instead.


## 15.0.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1317,6 +1317,9 @@ describe('Multi-View Calendar - ', () => {
overlay = document.querySelector(HelperTestFunctions.OVERLAY_CSSCLASS);
HelperTestFunctions.verifyMonthsViewNumber(overlay, 2);
HelperTestFunctions.verifyCalendarSubHeaders(overlay, [new Date('2019-09-16'), new Date('2019-10-16')]);

// clean up test
tick(350);
}));

it('Verify setting hideOutsideDays and monthsViewNumber from datepicker', fakeAsync(() => {
Expand Down Expand Up @@ -1349,8 +1352,10 @@ describe('Multi-View Calendar - ', () => {
expect(HelperTestFunctions.getHiddenDays(overlay, 0).length).toBe(0);
expect(HelperTestFunctions.getHiddenDays(overlay, 1).length).toBe(0);
expect(HelperTestFunctions.getHiddenDays(overlay, 2).length).toBe(0);
}));

// clean up test
tick(350);
}));
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,14 @@ describe('IgxDatePicker', () => {
fixture.detectChanges();

datePicker.close();
tick();
tick(350);
fixture.detectChanges();
expect(datePicker.collapsed).toBeFalsy();
expect(datePicker.closing.emit).toHaveBeenCalled();
expect(datePicker.closed.emit).not.toHaveBeenCalled();

closingSub.unsubscribe();
(datePicker as any)._overlayService.detachAll();
}));
});

Expand Down Expand Up @@ -176,6 +177,9 @@ describe('IgxDatePicker', () => {
expect(datePicker.collapsed).toBeFalsy();
expect(datePicker.opening.emit).toHaveBeenCalledTimes(1);
expect(datePicker.opened.emit).toHaveBeenCalledTimes(1);

// wait datepicker to get destroyed and test to cleanup
tick(350);
}));

it('should close the calendar with ESC', fakeAsync(() => {
Expand Down Expand Up @@ -455,7 +459,7 @@ describe('IgxDatePicker', () => {
let mockDateEditor: any;
let mockCalendar: Partial<IgxCalendarComponent>;
let mockInputDirective: any;
const mockModuleRef = {} as any;
const viewsContainerRef = {} as any;
const mockOverlayId = '1';
const today = new Date();
const elementRef = {
Expand Down Expand Up @@ -625,10 +629,11 @@ describe('IgxDatePicker', () => {
},
focus: () => { }
};
datePicker = new IgxDatePickerComponent(elementRef, 'en-US', overlay, mockModuleRef, mockInjector, renderer2, null, mockCdr);
datePicker = new IgxDatePickerComponent(elementRef, 'en-US', overlay, mockInjector, renderer2, null, mockCdr);
(datePicker as any).inputGroup = mockInputGroup;
(datePicker as any).inputDirective = mockInputDirective;
(datePicker as any).dateTimeEditor = mockDateEditor;
(datePicker as any).viewContainerRef = viewsContainerRef;
// TODO: TEMP workaround for afterViewInit call in unit tests:
datePicker.clearComponents = new QueryList<any>();
datePicker.toggleComponents = new QueryList<any>();
Expand Down Expand Up @@ -886,19 +891,19 @@ describe('IgxDatePicker', () => {
const isDropdownSpy = spyOnProperty(datePicker, 'isDropdown', 'get');
isDropdownSpy.and.returnValue(false);
datePicker.open();
expect(overlay.attach).toHaveBeenCalledWith(IgxCalendarContainerComponent, baseDialogSettings, mockModuleRef);
expect(overlay.attach).toHaveBeenCalledWith(IgxCalendarContainerComponent, viewsContainerRef, baseDialogSettings);
expect(overlay.show).toHaveBeenCalledWith(mockOverlayId);
isDropdownSpy.and.returnValue(true);
datePicker.open();
expect(overlay.attach).toHaveBeenCalledWith(IgxCalendarContainerComponent, baseDropdownSettings, mockModuleRef);
expect(overlay.attach).toHaveBeenCalledWith(IgxCalendarContainerComponent, viewsContainerRef, baseDropdownSettings);
expect(overlay.show).toHaveBeenCalledWith(mockOverlayId);
const mockOutlet = {} as any;
datePicker.outlet = mockOutlet;
datePicker.open();
expect(overlay.attach).toHaveBeenCalledWith(
IgxCalendarContainerComponent,
viewsContainerRef,
Object.assign({}, baseDropdownSettings, { outlet: mockOutlet }),
mockModuleRef
);
expect(overlay.show).toHaveBeenCalledWith(mockOverlayId);
let mockSettings: OverlaySettings = {
Expand All @@ -910,8 +915,8 @@ describe('IgxDatePicker', () => {
datePicker.open(mockSettings);
expect(overlay.attach).toHaveBeenCalledWith(
IgxCalendarContainerComponent,
viewsContainerRef,
Object.assign({}, baseDropdownSettings, mockSettings),
mockModuleRef
);
expect(overlay.show).toHaveBeenCalledWith(mockOverlayId);
isDropdownSpy.and.returnValue(false);
Expand All @@ -923,8 +928,8 @@ describe('IgxDatePicker', () => {
datePicker.open(mockSettings);
expect(overlay.attach).toHaveBeenCalledWith(
IgxCalendarContainerComponent,
viewsContainerRef,
Object.assign({}, baseDialogSettings, mockSettings),
mockModuleRef
);
expect(overlay.show).toHaveBeenCalledWith(mockOverlayId);
isDropdownSpy.and.returnValue(true);
Expand All @@ -937,8 +942,8 @@ describe('IgxDatePicker', () => {
datePicker.open(mockSettings);
expect(overlay.attach).toHaveBeenCalledWith(
IgxCalendarContainerComponent,
viewsContainerRef,
Object.assign({}, baseDropdownSettings, { modal: true }),
mockModuleRef
);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,77 @@
import {
Component, ContentChild, EventEmitter, HostBinding, Input,
OnDestroy, Output, ViewChild, ElementRef, Inject, HostListener,
NgModuleRef, OnInit, AfterViewInit, Injector, AfterViewChecked, ContentChildren,
QueryList, LOCALE_ID, Renderer2, Optional, PipeTransform, ChangeDetectorRef
AfterViewChecked,
AfterViewInit,
ChangeDetectorRef,
Component,
ContentChild,
ContentChildren,
ElementRef,
EventEmitter,
HostBinding,
HostListener,
Inject,
Injector,
Input,
LOCALE_ID,
OnDestroy,
OnInit,
Optional,
Output,
PipeTransform,
QueryList,
Renderer2,
ViewChild,
ViewContainerRef
} from '@angular/core';
import {
ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl, AbstractControl,
NG_VALIDATORS, ValidationErrors, Validator
AbstractControl,
ControlValueAccessor,
NgControl,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
ValidationErrors,
Validator
} from '@angular/forms';
import {
IgxCalendarComponent, IgxCalendarHeaderTemplateDirective, IgxCalendarSubheaderTemplateDirective,
isDateInRanges, IFormattingViews, IFormattingOptions
} from '../calendar/public_api';
import {
IgxInputDirective, IgxInputGroupComponent,
IgxLabelDirective, IGX_INPUT_GROUP_TYPE, IgxInputGroupType, IgxInputState
} from '../input-group/public_api';
import { fromEvent, Subscription, noop, MonoTypeOperatorFunction } from 'rxjs';
import { fromEvent, MonoTypeOperatorFunction, noop, Subscription } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { IgxOverlayOutletDirective } from '../directives/toggle/toggle.directive';
import { fadeIn, fadeOut } from '../animations/fade';
import {
OverlaySettings, IgxOverlayService, AbsoluteScrollStrategy,
AutoPositionStrategy,
OverlayCancelableEventArgs,
OverlayEventArgs
} from '../services/public_api';
import { CurrentResourceStrings } from '../core/i18n/resources';
import { IDatePickerResourceStrings } from '../core/i18n/date-picker-resources';
IFormattingOptions,
IFormattingViews,
IgxCalendarComponent,
IgxCalendarHeaderTemplateDirective,
IgxCalendarSubheaderTemplateDirective,
isDateInRanges
} from '../calendar/public_api';
import { DateRangeDescriptor, DateRangeType } from '../core/dates/dateRange';
import { IBaseCancelableBrowserEventArgs, PlatformUtil, isDate } from '../core/utils';
import { DisplayDensityToken, IDisplayDensityOptions } from '../core/density';
import { IDatePickerResourceStrings } from '../core/i18n/date-picker-resources';
import { CurrentResourceStrings } from '../core/i18n/resources';
import { IBaseCancelableBrowserEventArgs, isDate, PlatformUtil } from '../core/utils';
import { IgxCalendarContainerComponent } from '../date-common/calendar-container/calendar-container.component';
import { fadeIn, fadeOut } from '../animations/fade';
import { PickerBaseDirective } from '../date-common/picker-base.directive';
import { DisplayDensityToken, IDisplayDensityOptions } from '../core/density';
import { DatePart, DatePartDeltas, IgxDateTimeEditorDirective } from '../directives/date-time-editor/public_api';
import { IgxPickerActionsDirective, IgxPickerClearComponent } from '../date-common/public_api';
import { PickerHeaderOrientation } from '../date-common/types';
import { DateTimeUtil } from '../date-common/util/date-time.util';
import { PickerHeaderOrientation as PickerHeaderOrientation } from '../date-common/types';
import { DatePart, DatePartDeltas, IgxDateTimeEditorDirective } from '../directives/date-time-editor/public_api';
import { IgxOverlayOutletDirective } from '../directives/toggle/toggle.directive';
import {
IgxInputDirective,
IgxInputGroupComponent,
IgxInputGroupType,
IgxInputState,
IgxLabelDirective,
IGX_INPUT_GROUP_TYPE
} from '../input-group/public_api';
import {
AbsoluteScrollStrategy,
AutoPositionStrategy,
IgxOverlayService,
OverlayCancelableEventArgs,
OverlayEventArgs,
OverlaySettings
} from '../services/public_api';
import { IDatePickerValidationFailedEventArgs } from './date-picker.common';
import { IgxPickerClearComponent, IgxPickerActionsDirective } from '../date-common/public_api';

let NEXT_ID = 0;

Expand Down Expand Up @@ -378,6 +412,9 @@ export class IgxDatePickerComponent extends PickerBaseDirective implements Contr
@ViewChild(IgxInputGroupComponent)
private inputGroup: IgxInputGroupComponent;

@ViewChild(IgxInputGroupComponent, { read: ViewContainerRef })
private viewContainerRef: ViewContainerRef;

@ViewChild(IgxLabelDirective)
private labelDirective: IgxLabelDirective;

Expand Down Expand Up @@ -467,7 +504,6 @@ export class IgxDatePickerComponent extends PickerBaseDirective implements Contr
constructor(public element: ElementRef<HTMLElement>,
@Inject(LOCALE_ID) protected _localeId: string,
@Inject(IgxOverlayService) private _overlayService: IgxOverlayService,
private _moduleRef: NgModuleRef<any>,
private _injector: Injector,
private _renderer: Renderer2,
private platform: PlatformUtil,
Expand Down Expand Up @@ -541,9 +577,8 @@ export class IgxDatePickerComponent extends PickerBaseDirective implements Contr
if (this.outlet) {
overlaySettings.outlet = this.outlet;
}

this._overlayId = this._overlayService
.attach(IgxCalendarContainerComponent, overlaySettings, this._moduleRef);
.attach(IgxCalendarContainerComponent, this.viewContainerRef, overlaySettings);
this._overlayService.show(this._overlayId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ describe('IgxDateRangePicker', () => {
let mockPlatformUtil: any;
let overlay: IgxOverlayService;
let mockInjector;
let ngModuleRef: any;
let mockCalendar: IgxCalendarComponent;
let mockDaysView: any;
let mockAnimationService: AnimationService;
Expand All @@ -77,13 +76,6 @@ describe('IgxDateRangePicker', () => {
})
})
};
ngModuleRef = ({
injector: (...args: any[]) => { },
componentFactoryResolver: mockFactoryResolver,
instance: () => { },
destroy: () => { },
onDestroy: (fn: any) => { }
});
mockElement = {
style: { visibility: '', cursor: '', transitionDuration: '' },
classList: { add: () => { }, remove: () => { } },
Expand Down Expand Up @@ -123,7 +115,14 @@ describe('IgxDateRangePicker', () => {
getPosition: () => 0,
parentPlayer: {},
totalTime: 0,
beforeDestroy: () => { }
beforeDestroy: () => { },
_renderer: {
engine: {
players: [
{}
]
}
}
})
})
};
Expand Down Expand Up @@ -255,7 +254,7 @@ describe('IgxDateRangePicker', () => {
});

it('should disable calendar dates when min and/or max values as dates are provided', () => {
const dateRange = new IgxDateRangePickerComponent(elementRef, 'en-US', platform, mockInjector, ngModuleRef, null, overlay);
const dateRange = new IgxDateRangePickerComponent(elementRef, 'en-US', platform, mockInjector, null, overlay);
dateRange.ngOnInit();

spyOnProperty((dateRange as any), 'calendar').and.returnValue(mockCalendar);
Expand Down Expand Up @@ -775,6 +774,9 @@ describe('IgxDateRangePicker', () => {
fixture.detectChanges();

expect((dateRange as any).calendar.selectedDates.length).toBeGreaterThan(0);

// clean up test
tick(350);
}));

it('should set initial validity state when the form group is disabled', () => {
Expand Down Expand Up @@ -1036,12 +1038,12 @@ describe('IgxDateRangePicker', () => {
const fix = TestBed.createComponent(DateRangeReactiveFormComponent);
fix.detectChanges();
const dateRangePicker = fix.componentInstance.dateRangeWithTwoInputs;

fix.componentInstance.markAsTouched();
fix.detectChanges();
expect(dateRangePicker.projectedInputs.first.inputDirective.valid).toBe(IgxInputState.INVALID);
expect(dateRangePicker.projectedInputs.last.inputDirective.valid).toBe(IgxInputState.INVALID);

fix.componentInstance.disableForm();
fix.detectChanges();
expect(dateRangePicker.projectedInputs.first.inputDirective.valid).toBe(IgxInputState.INITIAL);
Expand Down Expand Up @@ -1349,6 +1351,9 @@ describe('IgxDateRangePicker', () => {
dateRange.select(startDate, endDate);
fixture.detectChanges();
expect(singleInputElement.nativeElement.getAttribute('placeholder')).toEqual('');

// clean up test
tick(350);
}));

it('should render custom label', () => {
Expand Down
Loading

0 comments on commit d072852

Please sign in to comment.