Skip to content

Commit 9c70ca8

Browse files
IvayloGLipata
authored andcommitted
feat(overlay): expose onAppended event #6472 (#6496)
1 parent d050b25 commit 9c70ca8

File tree

10 files changed

+113
-41
lines changed

10 files changed

+113
-41
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ All notable changes for each version of this project will be documented in this
2121
- `IgxCarousel`:
2222
- **Breaking Changes** -The carousel slides are no longer array, they are changed to QueryList.
2323
- **Behavioural change** - When slides are more than 5, a label is shown instead of the indicators. The count limit of visible indicators can be changed with the input `maximumIndicatorsCount`
24-
24+
- `igxOverlay`:
25+
- **Behavioural Change** - `igxOverlay` - no longer persists element scrolling `out of the box`. In order to persist an element scroll position after attaching the element to an overlay, handle the exposed `onAppended` overlay event and manage/restore the scroll position.
2526

2627
### New Features
2728
- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`:

projects/igniteui-angular/src/lib/directives/toggle/README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ Open/Close the directive only through one trigger by exporting it with name **to
2828
handlers when the toggle is opened and respectively closed.
2929
```html
3030
<button (click)="toggleRef.toggle()">Toggle</button>
31-
<div igxToggle #toggleRef="toggle" (onOpening)="eventHandler()" (onOpened)="eventHandler()" (onClosing)="eventHandler()" (onClosed)="eventHandler()">
31+
<div igxToggle #toggleRef="toggle"
32+
(onOpening)="eventHandler()" (onAppended)="eventHandler()" (onOpened)="eventHandler()"
33+
(onClosing)="eventHandler()" (onClosed)="eventHandler()" >
3234
<p>Some content that user would like to make it togglable.</p>
3335
</div>
3436
```
@@ -38,10 +40,11 @@ handlers when the toggle is opened and respectively closed.
3840
### Outputs
3941
| Name | Return Type | Description |
4042
|:--:|:---|:---|
41-
| `onOpening` | `void` | Emits an event before the toggle container is opened. |
42-
| `onOpened` | `void` | Emits an event after the toggle container is opened. |
43-
| `onClosing` | `void` | Emits an event before the toggle container is closed. |
44-
| `onClosed` | `void` | Emits an event after the toggle container is closed. |
43+
| `onAppended` | `void` | Emits an event after content is appended to the overlay. |
44+
| `onOpening` | `void` | Emits an event before the toggle container is opened. |
45+
| `onOpened` | `void` | Emits an event after the toggle container is opened. |
46+
| `onClosing` | `void` | Emits an event before the toggle container is closed. |
47+
| `onClosed` | `void` | Emits an event after the toggle container is closed. |
4548
### Methods
4649
| Name | Arguments | Return Type | Description |
4750
|:----------:|:------|:------|:------|

projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ describe('IgxToggle', () => {
7878
expect(toggle.onOpened.emit).toHaveBeenCalled();
7979
}));
8080

81+
it('should emit \'onAppended\' event', fakeAsync(() => {
82+
const fixture = TestBed.createComponent(IgxToggleTestComponent);
83+
fixture.detectChanges();
84+
85+
const toggle = fixture.componentInstance.toggle;
86+
spyOn(toggle.onAppended, 'emit');
87+
toggle.open();
88+
tick();
89+
fixture.detectChanges();
90+
91+
expect(toggle.onAppended.emit).toHaveBeenCalled();
92+
}));
93+
8194
it('should emit \'onClosing\' and \'onClosed\' events', fakeAsync(() => {
8295
const fixture = TestBed.createComponent(IgxToggleTestComponent);
8396
fixture.detectChanges();

projects/igniteui-angular/src/lib/directives/toggle/toggle.directive.ts

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy {
3535
private _overlayOpenedSub: Subscription;
3636
private _overlayClosingSub: Subscription;
3737
private _overlayClosedSub: Subscription;
38+
private _overlayAppendedSub: Subscription;
3839

3940
/**
4041
* Emits an event after the toggle container is opened.
@@ -164,6 +165,25 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy {
164165
@Optional() private navigationService: IgxNavigationService) {
165166
}
166167

168+
/**
169+
* Emits an event after the toggle element is appended to the overlay container.
170+
*
171+
* ```typescript
172+
* onAppended() {
173+
* alert("Content appended!");
174+
* }
175+
* ```
176+
*
177+
* ```html
178+
* <div
179+
* igxToggle
180+
* (onAppended)='onToggleAppended()'>
181+
* </div>
182+
* ```
183+
*/
184+
@Output()
185+
public onAppended = new EventEmitter();
186+
167187
/**
168188
* Opens the toggle.
169189
*
@@ -196,32 +216,37 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy {
196216
return;
197217
}
198218

199-
this.overlayService.show(this._overlayId, overlaySettings);
200-
201219
this.unsubscribe();
220+
221+
this._overlayAppendedSub = this.overlayService.onAppended.pipe(...this._overlaySubFilter).subscribe(() => {
222+
this.onAppended.emit();
223+
});
224+
202225
this._overlayOpenedSub = this.overlayService.onOpened.pipe(...this._overlaySubFilter).subscribe(() => {
203226
this.onOpened.emit();
204227
});
205228

206229
this._overlayClosingSub = this.overlayService
207-
.onClosing
208-
.pipe(...this._overlaySubFilter)
209-
.subscribe((e: OverlayClosingEventArgs) => {
210-
const eventArgs: CancelableBrowserEventArgs = { cancel: false, event: e.event };
211-
this.onClosing.emit(eventArgs);
212-
e.cancel = eventArgs.cancel;
213-
214-
// in case event is not canceled this will close the toggle and we need to unsubscribe.
215-
// Otherwise if for some reason, e.g. close on outside click, close() gets called before
216-
// onClosed was fired we will end with calling onClosing more than once
217-
if (!e.cancel) {
218-
this.clearSubscription(this._overlayClosingSub);
219-
}
220-
});
230+
.onClosing
231+
.pipe(...this._overlaySubFilter)
232+
.subscribe((e: OverlayClosingEventArgs) => {
233+
const eventArgs: CancelableBrowserEventArgs = { cancel: false, event: e.event };
234+
this.onClosing.emit(eventArgs);
235+
e.cancel = eventArgs.cancel;
236+
237+
// in case event is not canceled this will close the toggle and we need to unsubscribe.
238+
// Otherwise if for some reason, e.g. close on outside click, close() gets called before
239+
// onClosed was fired we will end with calling onClosing more than once
240+
if (!e.cancel) {
241+
this.clearSubscription(this._overlayClosingSub);
242+
}
243+
});
221244

222245
this._overlayClosedSub = this.overlayService.onClosed
223-
.pipe(...this._overlaySubFilter)
224-
.subscribe(this.overlayClosed);
246+
.pipe(...this._overlaySubFilter)
247+
.subscribe(this.overlayClosed);
248+
249+
this.overlayService.show(this._overlayId, overlaySettings);
225250
}
226251

227252
/**
@@ -319,6 +344,7 @@ export class IgxToggleDirective implements IToggleView, OnInit, OnDestroy {
319344
this.clearSubscription(this._overlayOpenedSub);
320345
this.clearSubscription(this._overlayClosingSub);
321346
this.clearSubscription(this._overlayClosedSub);
347+
this.clearSubscription(this._overlayAppendedSub);
322348
}
323349

324350
private clearSubscription(subscription: Subscription) {

projects/igniteui-angular/src/lib/drop-down/drop-down.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="igx-drop-down__list" igxToggle [style.width]="width"
2-
(onOpening)="onToggleOpening($event)" (onOpened)="onToggleOpened()"
2+
(onOpening)="onToggleOpening($event)" (onOpened)="onToggleOpened()" (onAppended)="onToggleContentAppended()"
33
(onClosing)="onToggleClosing($event)" (onClosed)="onToggleClosed()">
44
<div class="igx-drop-down__list-scroll" #scrollContainer [attr.id]="this.listId" role="listbox"
55
[style.height]="height"

projects/igniteui-angular/src/lib/drop-down/drop-down.component.spec.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,7 @@ describe('IgxDropDown ', () => {
10621062
fixture.detectChanges();
10631063

10641064
spyOn(componentInstance, 'onToggleOpening');
1065+
spyOn(componentInstance.dropdown, 'onToggleContentAppended');
10651066
spyOn(componentInstance, 'onToggleOpened');
10661067
spyOn(componentInstance, 'onToggleClosing');
10671068
spyOn(componentInstance, 'onToggleClosed');
@@ -1073,13 +1074,14 @@ describe('IgxDropDown ', () => {
10731074

10741075
fixture.detectChanges();
10751076
expect(componentInstance.onToggleOpening).toHaveBeenCalledTimes(1);
1077+
expect(componentInstance.dropdown.onToggleContentAppended).toHaveBeenCalledTimes(1);
10761078
expect(componentInstance.onToggleOpened).toHaveBeenCalledTimes(1);
10771079
button.click({ stopPropagation: () => null });
10781080
tick();
10791081

10801082
fixture.detectChanges();
10811083
expect(componentInstance.onToggleClosing).toHaveBeenCalledTimes(1);
1082-
expect(componentInstance.onToggleClosing).toHaveBeenCalledTimes(1);
1084+
expect(componentInstance.onToggleClosed).toHaveBeenCalledTimes(1);
10831085
}));
10841086

10851087
it('Should retain width/height properties', fakeAsync(() => {
@@ -1729,6 +1731,10 @@ class IgxDropDownTestScrollComponent {
17291731
public selectItem5() {
17301732
this.dropdownScroll.setSelectedItem(4);
17311733
}
1734+
1735+
public selectItem15() {
1736+
this.dropdownScroll.setSelectedItem(14);
1737+
}
17321738
}
17331739

17341740
@Component({
@@ -1864,6 +1870,10 @@ class IgxDropDownWithScrollComponent implements OnInit {
18641870
this.dropdownScroll.setSelectedItem(4);
18651871
}
18661872

1873+
public selectItem15() {
1874+
this.dropdownScroll.setSelectedItem(14);
1875+
}
1876+
18671877
ngOnInit() {
18681878
this.dropdownScroll.height = '200px';
18691879
for (let index = 1; index < 100; index++) {

projects/igniteui-angular/src/lib/drop-down/drop-down.component.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,14 +365,21 @@ export class IgxDropDownComponent extends IgxDropDownBaseDirective implements ID
365365
if (e.cancel) {
366366
return;
367367
}
368-
if (!this.virtDir && this.selectedItem) {
369-
this.scrollToItem(this.selectedItem);
370-
}
368+
371369
if (this.virtDir) {
372370
this.virtDir.scrollPosition = this._scrollPosition;
373371
}
374372
}
375373

374+
/**
375+
* @hidden @internal
376+
*/
377+
public onToggleContentAppended() {
378+
if (!this.virtDir && this.selectedItem) {
379+
this.scrollToItem(this.selectedItem);
380+
}
381+
}
382+
376383
/**
377384
* @hidden @internal
378385
*/

projects/igniteui-angular/src/lib/services/overlay/README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,11 @@ this.overlay.show(component, overlaySettings);
123123
##### Events
124124

125125
###### IgxOverlayService
126-
| Name | Description | Cancelable | Parameters |
127-
|-------------|-------------------------------------|------------|------------|
128-
|onOpening | Emitted before overlay shows | true | |
129-
|onOpened | Emitted after overlay shows | false | |
130-
|onClosing | Emitted before overlay hides | true | |
131-
|onClosed | Emitted after overlay hides | false | |
132-
|onAnimation | Emitted before animation is started | false | |
126+
| Name | Description | Cancelable | Parameters |
127+
|-------------|-----------------------------------------------|------------|------------|
128+
|onAppended | Emitted after overlay's content is appended | false | |
129+
|onOpening | Emitted before overlay shows | true | |
130+
|onOpened | Emitted after overlay shows | false | |
131+
|onClosing | Emitted before overlay hides | true | |
132+
|onClosed | Emitted after overlay hides | false | |
133+
|onAnimation | Emitted before animation is started | false | |

projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ describe('igxOverlay', () => {
324324
spyOn(overlayInstance.onClosed, 'emit');
325325
spyOn(overlayInstance.onClosing, 'emit');
326326
spyOn(overlayInstance.onOpened, 'emit');
327+
spyOn(overlayInstance.onAppended, 'emit');
327328
spyOn(overlayInstance.onOpening, 'emit');
328329
spyOn(overlayInstance.onAnimation, 'emit');
329330

@@ -335,6 +336,7 @@ describe('igxOverlay', () => {
335336
.toHaveBeenCalledWith({ id: firstCallId, componentRef: jasmine.any(ComponentRef), cancel: false });
336337
const args: OverlayEventArgs = (overlayInstance.onOpening.emit as jasmine.Spy).calls.mostRecent().args[0];
337338
expect(args.componentRef.instance).toEqual(jasmine.any(SimpleDynamicComponent));
339+
expect(overlayInstance.onAppended.emit).toHaveBeenCalledTimes(1);
338340
expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(1);
339341

340342
tick();
@@ -356,6 +358,7 @@ describe('igxOverlay', () => {
356358
tick();
357359
expect(overlayInstance.onOpening.emit).toHaveBeenCalledTimes(2);
358360
expect(overlayInstance.onOpening.emit).toHaveBeenCalledWith({ componentRef: undefined, id: secondCallId, cancel: false });
361+
expect(overlayInstance.onAppended.emit).toHaveBeenCalledTimes(2);
359362
expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(3);
360363

361364
tick();

projects/igniteui-angular/src/lib/services/overlay/overlay.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ export class IgxOverlayService implements OnDestroy {
6262
*/
6363
public onOpening = new EventEmitter<OverlayCancelableEventArgs>();
6464

65+
/**
66+
* Emitted after the component is appended to the overlay, and before animations are started.
67+
* ```typescript
68+
* onAppended(event: OverlayEventArgs){
69+
* const onAppended = event;
70+
* }
71+
* ```
72+
*/
73+
public onAppended = new EventEmitter<OverlayEventArgs>();
74+
6575
/**
6676
* Emitted after the component is opened and all animations are finished.
6777
* ```typescript
@@ -292,6 +302,9 @@ export class IgxOverlayService implements OnDestroy {
292302
if (info.componentRef) {
293303
info.componentRef.changeDetectorRef.detectChanges();
294304
}
305+
306+
this.onAppended.emit({ id: info.id, componentRef: info.componentRef });
307+
295308
this.updateSize(info);
296309
if (this._overlayInfos.indexOf(info) === -1) {
297310
this._overlayInfos.push(info);
@@ -397,12 +410,7 @@ export class IgxOverlayService implements OnDestroy {
397410
const wrapperElement = this.getWrapperElement();
398411
const contentElement = this.getContentElement(wrapperElement, info.settings.modal);
399412
this.getOverlayElement(info).appendChild(wrapperElement);
400-
const elementScrollTop = info.elementRef.nativeElement.scrollTop;
401413
contentElement.appendChild(info.elementRef.nativeElement);
402-
403-
if (elementScrollTop) {
404-
info.elementRef.nativeElement.scrollTop = elementScrollTop;
405-
}
406414
}
407415

408416
private getWrapperElement(): HTMLElement {

0 commit comments

Comments
 (0)