Skip to content

Commit 46d6065

Browse files
authored
Merge pull request #8197 from IgniteUI/simeonoff/toast-outlet
refactor(toast): utilize Overlay Service to display in DOM
2 parents fc324af + cfd99c9 commit 46d6065

File tree

10 files changed

+289
-254
lines changed

10 files changed

+289
-254
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ All notable changes for each version of this project will be documented in this
3535
- `IgxOverlay`
3636
- The `PositionSettings` `target` property has been deprecated and moved to `OverlaySettings`.
3737
- An optional Point/HTML Element parameter `target` has been added to the `position()` method
38+
- `IgxToast`
39+
- The component now utilizes the `IgxOverlayService` to position itself in the DOM.
40+
- An additional input property `outlet` has been added to allow users to specify custom Overlay Outlets using the `IgxOverlayOutletDirective`;
41+
- The `position` property now accepts values of type `IgxToastPosition` that work with strict templates.
3842

3943
## 10.1.0
4044

projects/igniteui-angular/src/lib/core/styles/components/toast/_toast-component.scss

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,5 @@
88
@include b(igx-toast) {
99
$this: bem--selector-to-string(&);
1010
@include register-component(str-slice($this, 2, -1));
11-
1211
@extend %igx-toast-display !optional;
13-
14-
@include m(top) {
15-
@extend %igx-toast-display !optional;
16-
@extend %igx-toast--top !optional;
17-
}
18-
19-
@include m(middle) {
20-
@extend %igx-toast-display !optional;
21-
@extend %igx-toast--middle !optional;
22-
}
23-
24-
@include m(bottom) {
25-
@extend %igx-toast-display !optional;
26-
@extend %igx-toast--bottom !optional;
27-
}
2812
}

projects/igniteui-angular/src/lib/core/styles/components/toast/_toast-theme.scss

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,9 @@
102102
), $variant);
103103

104104
%igx-toast-display {
105-
position: fixed;
106-
display: flex;
105+
display: inline-flex;
107106
justify-content: center;
108107
align-items: center;
109-
left: 50%;
110-
transform: translate3d(-50%, 0, 0);
111108
margin: $margin;
112109
padding: $padding;
113110
min-width: $width;
@@ -117,23 +114,6 @@
117114
border-radius: --var($theme, 'border-radius');
118115
box-shadow: map-get($theme, 'shadow');
119116
backdrop-filter: blur(10px);
120-
opacity: 0;
121-
z-index: 999999;
122-
}
123-
124-
%igx-toast--top {
125-
top: 0;
126-
margin-top: 16px;
127-
}
128-
129-
%igx-toast--middle {
130-
top: 50%;
131-
transform: translate3d(-50%, -50%, 0);
132-
}
133-
134-
%igx-toast--bottom {
135-
bottom: 0;
136-
margin-bottom: 16px;
137117
}
138118
}
139119

projects/igniteui-angular/src/lib/toast/README.md

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# igx-toast
22

3-
**igx-toast** IgxToast provides information and warning messages. They could not be dismissed, are non-interactive and can appear on top, middle and the bottom of the screen.
4-
A walkthrough of how to get started can be found [here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toast.html)
3+
The Toast component shows application messages in a stylized pop-up box positioned inside the global overlay outlet(default). Toasts can't be dismissed, they are non-interactive and can appear on top, middle, and the bottom of the screen. A walkthrough on how to get started can be found [here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toast.html)
54

65
# Usage
76

@@ -11,53 +10,49 @@ A walkthrough of how to get started can be found [here](https://www.infragistics
1110
<button (click)="toast.show()">Show toast</button>
1211
<button (click)="toast.hide()">Hide toast</button>
1312

14-
<igx-toast #toast
15-
message="Something happened!">
16-
</igx-toast>
13+
<igx-toast #toast>Well, hi there!</igx-toast>
1714
```
18-
You can set the id of the component by `id="myToast"` or will be automatically generated;
1915

20-
You can be more descriptive and set message `message="Something happened!"`.
16+
You can set the id of the component by setting the attribute `id` on the component (e.g. `id="myToast"`), or it will be automatically generated for you if you don't provide anything;
17+
18+
The toast can be shown by using the `show()` method.
2119

22-
You can show the toast by using `toast.show()` method.
20+
You can hide the toast by using the `hide()` method.
2321

24-
You can show hide toast by using `toast.hide()` method.
22+
## Toast Position
23+
You can set the `positon` property to `top`, `middle`, or `bottom`, which will position the toast near the top, middle, or bottom of the document*.
2524

26-
## Toast positioned on top
25+
*By default the toast renders inside a global overlay outlet. You can specify a different overlay outlet by setting the `outlet` property on the toast;
2726

2827
```html
2928
<button (click)="toast.show()">Show toast</button>
30-
31-
<igx-toast #toast
32-
message="Something happened!"
33-
position="IgxToastPosition.Top">
34-
</igx-toast>
29+
<igx-toast #toast position="top">Top Positioned Toast</igx-toast>
3530
```
3631

37-
You can modify the position of the toast by setting `postion="IgxToastPosition.Top"`.
38-
3932
## Toast with different content
4033

4134
```html
42-
<igx-toast #toast [position]="toastPosition">
35+
<igx-toast #toast position="bottom">
4336
<igx-icon>notifications</igx-icon>
4437
This message will self-destruct in 4 seconds.
4538
</igx-toast>
4639
```
4740

48-
You can display various content by placing it between the igx-toast tags. If so, the message property will be overwritten.
41+
You can display various content by placing it between the `igx-toast` tags.
4942

50-
## Toast with events
43+
## Toast Events
5144

5245
```html
5346
<button (click)="toast.show()">Show toast</button>
5447

55-
<igx-toast #toast
56-
message="Something happened!"
57-
(onShowing)="onToastShowing($event)"
58-
(onShown)="onToastShown($event)"
59-
(onHiding)="onToastShowing($event)"
60-
(onHidden)="onToastHidden($event)">
48+
<igx-toast
49+
#toast
50+
message="Something happened!"
51+
(onShowing)="onToastShowing($event)"
52+
(onShown)="onToastShown($event)"
53+
(onHiding)="onToastShowing($event)"
54+
(onHidden)="onToastHidden($event)"
55+
>
6156
</igx-toast>
6257
```
6358

projects/igniteui-angular/src/lib/toast/toast.component.spec.ts

Lines changed: 62 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
1-
import {Component, ViewChild } from '@angular/core';
2-
import {async, TestBed, fakeAsync, tick, ComponentFixture} from '@angular/core/testing';
3-
import {By} from '@angular/platform-browser';
4-
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
5-
import {IgxToastComponent, IgxToastModule, IgxToastPosition} from './toast.component';
1+
import { Component, ViewChild } from '@angular/core';
2+
import {
3+
waitForAsync,
4+
TestBed,
5+
fakeAsync,
6+
tick,
7+
ComponentFixture,
8+
} from '@angular/core/testing';
9+
import { By } from '@angular/platform-browser';
10+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
11+
import {
12+
IgxToastComponent,
13+
IgxToastModule,
14+
} from './toast.component';
615
import { configureTestSuite } from '../test-utils/configure-suite';
716

817
describe('IgxToast', () => {
918
configureTestSuite();
10-
beforeAll(async(() => {
19+
beforeAll(waitForAsync(() => {
1120
TestBed.configureTestingModule({
12-
declarations: [
13-
ToastInitializeTestComponent
14-
],
15-
imports: [
16-
BrowserAnimationsModule,
17-
IgxToastModule
18-
]
21+
declarations: [ToastInitializeTestComponent],
22+
imports: [BrowserAnimationsModule, IgxToastModule],
1923
}).compileComponents();
2024
}));
2125

2226
const baseClass = 'igx-toast';
23-
const classes = {
24-
top: `${baseClass}--top`,
25-
middle: `${baseClass}--middle`,
26-
bottom: `${baseClass}--bottom`,
27-
};
28-
2927
let fixture: ComponentFixture<ToastInitializeTestComponent>;
3028
let toast: IgxToastComponent;
3129

@@ -37,13 +35,13 @@ describe('IgxToast', () => {
3735
});
3836

3937
it('should properly initialize', () => {
40-
const domToast = fixture.debugElement.query(By.css(baseClass)).nativeElement;
38+
const domToast = fixture.debugElement.query(By.css(baseClass))
39+
.nativeElement;
4140
expect(toast.id).toContain('igx-toast-');
4241
expect(domToast.id).toContain('igx-toast-');
4342
expect(toast.displayTime).toBe(4000);
4443
expect(toast.autoHide).toBeTruthy();
4544
expect(toast.isVisible).toBeTruthy();
46-
expect(domToast.classList).toContain(classes.bottom);
4745

4846
toast.id = 'customToast';
4947
fixture.detectChanges();
@@ -52,87 +50,70 @@ describe('IgxToast', () => {
5250
expect(domToast.id).toBe('customToast');
5351
});
5452

55-
it('should change toast position to middle', () => {
56-
toast.position = IgxToastPosition.Middle;
57-
fixture.detectChanges();
58-
const domToast = fixture.debugElement.query(By.css(baseClass)).nativeElement;
59-
60-
expect(domToast.classList).toContain(classes.middle);
61-
});
62-
63-
it('should change toast position to top', () => {
64-
toast.position = IgxToastPosition.Top;
65-
fixture.detectChanges();
66-
const domToast = fixture.debugElement.query(By.css(baseClass)).nativeElement;
67-
68-
expect(domToast.classList).toContain(classes.top);
69-
});
70-
71-
it('should change toast position to bottom', () => {
72-
toast.position = IgxToastPosition.Bottom;
73-
fixture.detectChanges();
74-
const domToast = fixture.debugElement.query(By.css(baseClass)).nativeElement;
75-
76-
expect(domToast.classList).not.toContain(classes.top);
77-
expect(domToast.classList).not.toContain(classes.middle);
78-
expect(domToast.classList).toContain(classes.bottom);
79-
});
80-
81-
it('should auto hide 1 second after it\'s open', fakeAsync(() => {
53+
it('should auto hide after it\'s open', fakeAsync(() => {
54+
spyOn(toast.onHiding, 'emit');
8255
toast.displayTime = 1000;
8356

8457
toast.show();
85-
86-
expect(toast.isVisible).toBeTruthy();
87-
expect(toast.animationState).toBe('visible');
88-
expect(toast.autoHide).toBeTruthy();
89-
9058
tick(1000);
91-
92-
expect(toast.isVisible).toBeFalsy();
93-
expect(toast.animationState).toBe('invisible');
59+
expect(toast.onHiding.emit).toHaveBeenCalled();
9460
}));
9561

9662
it('should not auto hide after it\'s open', fakeAsync(() => {
63+
spyOn(toast.onHiding, 'emit');
9764
toast.displayTime = 1000;
9865
toast.autoHide = false;
9966

10067
toast.show();
101-
102-
expect(toast.isVisible).toBeTruthy();
103-
expect(toast.animationState).toBe('visible');
104-
expect(toast.autoHide).toBeFalsy();
105-
10668
tick(1000);
107-
108-
expect(toast.isVisible).toBeTruthy();
109-
expect(toast.animationState).toBe('visible');
69+
expect(toast.onHiding.emit).not.toHaveBeenCalled();
11070
}));
11171

112-
it('visibility is updated by the toggle() method', () => {
72+
it('should emit onShowing when toast is shown', () => {
11373
spyOn(toast.onShowing, 'emit');
114-
spyOn(toast.onShown, 'emit');
74+
toast.show();
75+
expect(toast.onShowing.emit).toHaveBeenCalled();
76+
});
77+
78+
it('should emit onHiding when toast is hidden', () => {
11579
spyOn(toast.onHiding, 'emit');
80+
toast.hide();
81+
expect(toast.onHiding.emit).toHaveBeenCalled();
82+
});
83+
84+
it('should emit onShown when toggle onOpened is fired', waitForAsync(() => {
85+
spyOn(toast.onShown, 'emit');
86+
toast.open();
87+
88+
toast.onOpened.subscribe(() => {
89+
expect(toast.onShown.emit).toHaveBeenCalled();
90+
});
91+
}));
92+
93+
it('should emit onHidden when toggle onClosed is fired', waitForAsync(() => {
11694
spyOn(toast.onHidden, 'emit');
95+
toast.isVisible = true;
96+
toast.close();
11797

118-
toast.show();
119-
expect(toast.isVisible).toBe(true);
120-
expect(toast.animationState).toBe('visible');
98+
toast.onClosed.subscribe(() => {
99+
expect(toast.onHidden.emit).toHaveBeenCalled();
100+
});
101+
}));
121102

122-
expect(toast.onShowing.emit).toHaveBeenCalledTimes(1);
123-
expect(toast.onShown.emit).toHaveBeenCalledTimes(1);
124-
expect(toast.onHiding.emit).toHaveBeenCalledTimes(0);
125-
expect(toast.onHidden.emit).toHaveBeenCalledTimes(0);
103+
it('visibility is updated by the toggle() method', waitForAsync((done: DoneFn) => {
104+
toast.autoHide = false;
126105

127106
toast.toggle();
128-
expect(toast.isVisible).toBe(false);
129-
expect(toast.animationState).toBe('invisible');
107+
toast.onOpened.subscribe(() => {
108+
expect(toast.isVisible).toEqual(true);
109+
});
130110

131-
expect(toast.onShowing.emit).toHaveBeenCalledTimes(1);
132-
expect(toast.onShown.emit).toHaveBeenCalledTimes(1);
133-
expect(toast.onHiding.emit).toHaveBeenCalledTimes(1);
134-
expect(toast.onHidden.emit).toHaveBeenCalledTimes(1);
135-
});
111+
toast.toggle();
112+
toast.onClosed.subscribe(() => {
113+
expect(toast.isVisible).toEqual(false);
114+
done();
115+
});
116+
}));
136117

137118
it('can set message through show method', fakeAsync(() => {
138119
toast.displayTime = 100;
@@ -143,15 +124,13 @@ describe('IgxToast', () => {
143124
fixture.detectChanges();
144125

145126
expect(toast.isVisible).toBeTruthy();
146-
expect(toast.animationState).toBe('visible');
147127
expect(toast.autoHide).toBeFalsy();
148128
expect(toast.toastMessage).toBe('Custom Message');
149-
expect(fixture.nativeElement.querySelector('igx-toast:first-child').innerText).toBe('Custom Message');
150129
}));
151130
});
152131

153132
@Component({
154-
template: `<igx-toast #toast></igx-toast>`
133+
template: `<igx-toast #toast></igx-toast>`,
155134
})
156135
class ToastInitializeTestComponent {
157136
@ViewChild(IgxToastComponent, { static: true })

0 commit comments

Comments
 (0)