Skip to content

Commit a3abbdc

Browse files
committed
refactor: replace first operator usages
Replaces all usages of the `first` operator with `take(1)` in order to avoid some cryptic errors that `first` throws when the observable completes before it has emitted a value.
1 parent 262c23b commit a3abbdc

File tree

16 files changed

+36
-35
lines changed

16 files changed

+36
-35
lines changed

src/cdk/a11y/focus-trap.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
} from '@angular/core';
1818
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1919
import {Platform} from '@angular/cdk/platform';
20-
import {first} from 'rxjs/operators/first';
20+
import {take} from 'rxjs/operators/take';
2121
import {InteractivityChecker} from './interactivity-checker';
2222

2323

@@ -283,7 +283,7 @@ export class FocusTrap {
283283
if (this._ngZone.isStable) {
284284
fn();
285285
} else {
286-
this._ngZone.onStable.asObservable().pipe(first()).subscribe(fn);
286+
this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(fn);
287287
}
288288
}
289289
}

src/cdk/a11y/list-key-manager.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {DOWN_ARROW, TAB, UP_ARROW} from '@angular/cdk/keycodes';
2-
import {first} from 'rxjs/operators/first';
2+
import {take} from 'rxjs/operators/take';
33
import {QueryList} from '@angular/core';
44
import {fakeAsync, tick} from '@angular/core/testing';
55
import {createKeyboardEvent} from '../testing/event-objects';
@@ -196,7 +196,7 @@ describe('Key managers', () => {
196196

197197
it('should emit tabOut when the tab key is pressed', () => {
198198
let spy = jasmine.createSpy('tabOut spy');
199-
keyManager.tabOut.pipe(first()).subscribe(spy);
199+
keyManager.tabOut.pipe(take(1)).subscribe(spy);
200200
keyManager.onKeydown(fakeKeyEvents.tab);
201201

202202
expect(spy).toHaveBeenCalled();

src/cdk/overlay/overlay-ref.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {OverlayConfig} from './overlay-config';
1212
import {OverlayKeyboardDispatcher} from './keyboard/overlay-keyboard-dispatcher';
1313
import {Observable} from 'rxjs/Observable';
1414
import {Subject} from 'rxjs/Subject';
15-
import {first} from 'rxjs/operators/first';
15+
import {take} from 'rxjs/operators/take';
1616

1717

1818
/**
@@ -69,7 +69,7 @@ export class OverlayRef implements PortalOutlet {
6969
// Update the position once the zone is stable so that the overlay will be fully rendered
7070
// before attempting to position it, as the position may depend on the size of the rendered
7171
// content.
72-
this._ngZone.onStable.asObservable().pipe(first()).subscribe(() => {
72+
this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => {
7373
this.updatePosition();
7474
});
7575

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from '@angular/cdk/overlay';
1919
import {TemplatePortal} from '@angular/cdk/portal';
2020
import {filter} from 'rxjs/operators/filter';
21-
import {first} from 'rxjs/operators/first';
21+
import {take} from 'rxjs/operators/take';
2222
import {switchMap} from 'rxjs/operators/switchMap';
2323
import {tap} from 'rxjs/operators/tap';
2424
import {delay} from 'rxjs/operators/delay';
@@ -368,7 +368,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
368368
* stream every time the option list changes.
369369
*/
370370
private _subscribeToClosingActions(): Subscription {
371-
const firstStable = this._zone.onStable.asObservable().pipe(first());
371+
const firstStable = this._zone.onStable.asObservable().pipe(take(1));
372372
const optionChanges = this.autocomplete.options.changes.pipe(
373373
tap(() => this._positionStrategy.recalculateLastPosition()),
374374
// Defer emitting to the stream until the next tick, because changing
@@ -387,7 +387,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
387387
return this.panelClosingActions;
388388
}),
389389
// when the first closing event occurs...
390-
first()
390+
take(1)
391391
)
392392
// set the value, close the panel, and complete.
393393
.subscribe(event => this._setValueAndClose(event));

src/lib/datepicker/calendar.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
SimpleChanges,
3737
} from '@angular/core';
3838
import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats} from '@angular/material/core';
39-
import {first} from 'rxjs/operators/first';
39+
import {take} from 'rxjs/operators/take';
4040
import {Subscription} from 'rxjs/Subscription';
4141
import {createMissingDateImplError} from './datepicker-errors';
4242
import {MatDatepickerIntl} from './datepicker-intl';
@@ -261,7 +261,7 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
261261
/** Focuses the active cell after the microtask queue is empty. */
262262
_focusActiveCell() {
263263
this._ngZone.runOutsideAngular(() => {
264-
this._ngZone.onStable.asObservable().pipe(first()).subscribe(() => {
264+
this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => {
265265
this._elementRef.nativeElement.querySelector('.mat-calendar-body-active').focus();
266266
});
267267
});

src/lib/datepicker/datepicker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
ScrollStrategy,
1919
} from '@angular/cdk/overlay';
2020
import {ComponentPortal} from '@angular/cdk/portal';
21-
import {first} from 'rxjs/operators/first';
21+
import {take} from 'rxjs/operators/take';
2222
import {
2323
AfterContentInit,
2424
ChangeDetectionStrategy,
@@ -345,7 +345,7 @@ export class MatDatepicker<D> implements OnDestroy {
345345
componentRef.instance.datepicker = this;
346346

347347
// Update the position once the calendar has rendered.
348-
this._ngZone.onStable.asObservable().pipe(first()).subscribe(() => {
348+
this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => {
349349
this._popupRef.updatePosition();
350350
});
351351
}

src/lib/dialog/dialog-ref.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import {OverlayRef, GlobalPositionStrategy} from '@angular/cdk/overlay';
1010
import {filter} from 'rxjs/operators/filter';
11-
import {first} from 'rxjs/operators/first';
11+
import {take} from 'rxjs/operators/take';
1212
import {DialogPosition} from './dialog-config';
1313
import {Observable} from 'rxjs/Observable';
1414
import {Subject} from 'rxjs/Subject';
@@ -50,7 +50,7 @@ export class MatDialogRef<T> {
5050
// Emit when opening animation completes
5151
_containerInstance._animationStateChanged.pipe(
5252
filter(event => event.phaseName === 'done' && event.toState === 'enter'),
53-
first()
53+
take(1)
5454
)
5555
.subscribe(() => {
5656
this._afterOpen.next();
@@ -60,7 +60,7 @@ export class MatDialogRef<T> {
6060
// Dispose overlay when closing animation is complete
6161
_containerInstance._animationStateChanged.pipe(
6262
filter(event => event.phaseName === 'done' && event.toState === 'exit'),
63-
first()
63+
take(1)
6464
)
6565
.subscribe(() => {
6666
this._overlayRef.dispose();
@@ -80,7 +80,7 @@ export class MatDialogRef<T> {
8080
// Transition the backdrop in parallel to the dialog.
8181
this._containerInstance._animationStateChanged.pipe(
8282
filter(event => event.phaseName === 'start'),
83-
first()
83+
take(1)
8484
)
8585
.subscribe(() => {
8686
this._beforeClose.next(dialogResult);

src/lib/form-field/form-field.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import {animate, state, style, transition, trigger} from '@angular/animations';
1010
import {coerceBooleanProperty} from '@angular/cdk/coercion';
11-
import {first} from 'rxjs/operators/first';
11+
import {take} from 'rxjs/operators/take';
1212
import {startWith} from 'rxjs/operators/startWith';
1313
import {
1414
AfterContentChecked,
@@ -237,7 +237,7 @@ export class MatFormField implements AfterViewInit, AfterContentInit, AfterConte
237237
this._showAlwaysAnimate = true;
238238
this._floatPlaceholder = 'always';
239239

240-
fromEvent(this._placeholder.nativeElement, 'transitionend').pipe(first()).subscribe(() => {
240+
fromEvent(this._placeholder.nativeElement, 'transitionend').pipe(take(1)).subscribe(() => {
241241
this._showAlwaysAnimate = false;
242242
});
243243

src/lib/icon/icon.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {first} from 'rxjs/operators/first';
9+
import {take} from 'rxjs/operators/take';
1010
import {
1111
Attribute,
1212
ChangeDetectionStrategy,
@@ -132,7 +132,7 @@ export class MatIcon extends _MatIconMixinBase implements OnChanges, OnInit, Can
132132
if (this.svgIcon) {
133133
const [namespace, iconName] = this._splitIconName(this.svgIcon);
134134

135-
this._iconRegistry.getNamedSvgIcon(iconName, namespace).pipe(first()).subscribe(
135+
this._iconRegistry.getNamedSvgIcon(iconName, namespace).pipe(take(1)).subscribe(
136136
svg => this._setSvgElement(svg),
137137
(err: Error) => console.log(`Error retrieving icon: ${err.message}`)
138138
);

src/lib/menu/menu-directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {Direction} from '@angular/cdk/bidi';
1212
import {ESCAPE, LEFT_ARROW, RIGHT_ARROW} from '@angular/cdk/keycodes';
1313
import {startWith} from 'rxjs/operators/startWith';
1414
import {switchMap} from 'rxjs/operators/switchMap';
15-
import {first} from 'rxjs/operators/first';
15+
import {take} from 'rxjs/operators/take';
1616
import {
1717
AfterContentInit,
1818
ChangeDetectionStrategy,
@@ -197,7 +197,7 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
197197

198198
return this._ngZone.onStable
199199
.asObservable()
200-
.pipe(first(), switchMap(() => this._hovered()));
200+
.pipe(take(1), switchMap(() => this._hovered()));
201201
}
202202

203203
/** Handle a keyboard event from the menu, delegating to the appropriate action. */

0 commit comments

Comments
 (0)