Skip to content

Commit decddb5

Browse files
crisbetommalerba
authored andcommitted
refactor(stepper): rework buttons to handle Ivy (#15429)
In Ivy inheriting `host` bindings works correctly by merging the two declarations, whereas in ViewEngine the bindings aren't inherited at all. This means that with our current setup the `click` listener on the buttons will be invoked twice with Ivy. These changes rework the buttons so that they work both with Ivy and ViewEngine.
1 parent f1b13a2 commit decddb5

File tree

4 files changed

+40
-18
lines changed

4 files changed

+40
-18
lines changed

src/cdk/stepper/stepper-button.ts

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

9-
import {Directive, Input} from '@angular/core';
9+
import {Directive, HostListener, Input} from '@angular/core';
10+
1011
import {CdkStepper} from './stepper';
1112

1213
/** Button that moves to the next step in a stepper workflow. */
1314
@Directive({
1415
selector: 'button[cdkStepperNext]',
1516
host: {
16-
'(click)': '_stepper.next()',
1717
'[type]': 'type',
1818
}
1919
})
@@ -22,13 +22,22 @@ export class CdkStepperNext {
2222
@Input() type: string = 'submit';
2323

2424
constructor(public _stepper: CdkStepper) {}
25+
26+
// We have to use a `HostListener` here in order to support both Ivy and ViewEngine.
27+
// In Ivy the `host` bindings will be merged when this class is extended, whereas in
28+
// ViewEngine they're overwritte.
29+
// TODO(crisbeto): we move this back into `host` once Ivy is turned on by default.
30+
// tslint:disable-next-line:no-host-decorator-in-concrete
31+
@HostListener('click')
32+
_handleClick() {
33+
this._stepper.next();
34+
}
2535
}
2636

2737
/** Button that moves to the previous step in a stepper workflow. */
2838
@Directive({
2939
selector: 'button[cdkStepperPrevious]',
3040
host: {
31-
'(click)': '_stepper.previous()',
3241
'[type]': 'type',
3342
}
3443
})
@@ -37,4 +46,14 @@ export class CdkStepperPrevious {
3746
@Input() type: string = 'button';
3847

3948
constructor(public _stepper: CdkStepper) {}
49+
50+
// We have to use a `HostListener` here in order to support both Ivy and ViewEngine.
51+
// In Ivy the `host` bindings will be merged when this class is extended, whereas in
52+
// ViewEngine they're overwritte.
53+
// TODO(crisbeto): we move this back into `host` once Ivy is turned on by default.
54+
// tslint:disable-next-line:no-host-decorator-in-concrete
55+
@HostListener('click')
56+
_handleClick() {
57+
this._stepper.previous();
58+
}
4059
}

src/lib/stepper/stepper-button.ts

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

9+
import {CdkStepperNext, CdkStepperPrevious} from '@angular/cdk/stepper';
910
import {Directive} from '@angular/core';
10-
import {CdkStepper, CdkStepperNext, CdkStepperPrevious} from '@angular/cdk/stepper';
11-
import {MatStepper} from './stepper';
1211

1312
/** Button that moves to the next step in a stepper workflow. */
1413
@Directive({
1514
selector: 'button[matStepperNext]',
1615
host: {
17-
'(click)': '_stepper.next()',
1816
'[type]': 'type',
1917
},
20-
inputs: ['type'],
21-
providers: [{provide: CdkStepper, useExisting: MatStepper}]
18+
inputs: ['type']
2219
})
23-
export class MatStepperNext extends CdkStepperNext {}
20+
export class MatStepperNext extends CdkStepperNext {
21+
}
2422

2523
/** Button that moves to the previous step in a stepper workflow. */
2624
@Directive({
2725
selector: 'button[matStepperPrevious]',
2826
host: {
29-
'(click)': '_stepper.previous()',
3027
'[type]': 'type',
3128
},
32-
inputs: ['type'],
33-
providers: [{provide: CdkStepper, useExisting: MatStepper}]
29+
inputs: ['type']
3430
})
35-
export class MatStepperPrevious extends CdkStepperPrevious {}
31+
export class MatStepperPrevious extends CdkStepperPrevious {
32+
}

src/lib/stepper/stepper.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,7 @@ export class MatStep extends CdkStep implements ErrorStateMatcher {
8181
}
8282

8383

84-
@Directive({
85-
selector: '[matStepper]'
86-
})
84+
@Directive({selector: '[matStepper]', providers: [{provide: CdkStepper, useExisting: MatStepper}]})
8785
export class MatStepper extends CdkStepper implements AfterContentInit {
8886
/** The list of step headers of the steps in the stepper. */
8987
@ViewChildren(MatStepHeader) _stepHeader: QueryList<MatStepHeader>;
@@ -141,7 +139,10 @@ export class MatStepper extends CdkStepper implements AfterContentInit {
141139
'role': 'tablist',
142140
},
143141
animations: [matStepperAnimations.horizontalStepTransition],
144-
providers: [{provide: MatStepper, useExisting: MatHorizontalStepper}],
142+
providers: [
143+
{provide: MatStepper, useExisting: MatHorizontalStepper},
144+
{provide: CdkStepper, useExisting: MatHorizontalStepper}
145+
],
145146
encapsulation: ViewEncapsulation.None,
146147
changeDetection: ChangeDetectionStrategy.OnPush,
147148
})
@@ -164,7 +165,10 @@ export class MatHorizontalStepper extends MatStepper {
164165
'role': 'tablist',
165166
},
166167
animations: [matStepperAnimations.verticalStepTransition],
167-
providers: [{provide: MatStepper, useExisting: MatVerticalStepper}],
168+
providers: [
169+
{provide: MatStepper, useExisting: MatVerticalStepper},
170+
{provide: CdkStepper, useExisting: MatVerticalStepper}
171+
],
168172
encapsulation: ViewEncapsulation.None,
169173
changeDetection: ChangeDetectionStrategy.OnPush,
170174
})

tools/public_api_guard/cdk/stepper.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,14 @@ export declare class CdkStepperNext {
6969
_stepper: CdkStepper;
7070
type: string;
7171
constructor(_stepper: CdkStepper);
72+
_handleClick(): void;
7273
}
7374

7475
export declare class CdkStepperPrevious {
7576
_stepper: CdkStepper;
7677
type: string;
7778
constructor(_stepper: CdkStepper);
79+
_handleClick(): void;
7880
}
7981

8082
export declare const MAT_STEPPER_GLOBAL_OPTIONS: InjectionToken<StepperOptions>;

0 commit comments

Comments
 (0)