Skip to content

fix(stepper): not picking up indirect descendant elements #17529

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cdk/stepper/stepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ export class CdkStepper implements AfterViewInit, OnDestroy {
* @deprecated use `steps` instead
* @breaking-change 9.0.0 remove this property
*/
@ContentChildren(CdkStep) _steps: QueryList<CdkStep>;
@ContentChildren(CdkStep, {descendants: true}) _steps: QueryList<CdkStep>;

/**
* We need to store the steps in an Iterable due to strict template type checking with *ngFor and
Expand All @@ -273,7 +273,7 @@ export class CdkStepper implements AfterViewInit, OnDestroy {
* @deprecated Type to be changed to `QueryList<CdkStepHeader>`.
* @breaking-change 8.0.0
*/
@ContentChildren(CdkStepHeader) _stepHeader: QueryList<FocusableOption>;
@ContentChildren(CdkStepHeader, {descendants: true}) _stepHeader: QueryList<FocusableOption>;

/** Whether the validity of previous steps should be checked or not. */
@Input()
Expand Down
108 changes: 108 additions & 0 deletions src/material/stepper/stepper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,79 @@ describe('MatStepper', () => {
expect(stepper._getIndicatorType(1)).toBe(STEP_STATE.EDIT);
});
});

describe('indirect descendants', () => {
it('should be able to change steps when steps are indirect descendants', () => {
const fixture = createComponent(StepperWithIndirectDescendantSteps);
fixture.detectChanges();

const stepHeaders = fixture.debugElement.queryAll(By.css('.mat-vertical-stepper-header'));
const stepperComponent =
fixture.debugElement.query(By.directive(MatStepper))!.componentInstance;

expect(stepperComponent.selectedIndex).toBe(0);
expect(stepperComponent.selected instanceof MatStep).toBe(true);

// select the second step
let stepHeaderEl = stepHeaders[1].nativeElement;
stepHeaderEl.click();
fixture.detectChanges();

expect(stepperComponent.selectedIndex).toBe(1);
expect(stepperComponent.selected instanceof MatStep).toBe(true);

// select the third step
stepHeaderEl = stepHeaders[2].nativeElement;
stepHeaderEl.click();
fixture.detectChanges();

expect(stepperComponent.selectedIndex).toBe(2);
expect(stepperComponent.selected instanceof MatStep).toBe(true);
});

it('should allow for the `edit` icon to be overridden', () => {
const fixture = createComponent(IndirectDescendantIconOverridesStepper);
fixture.detectChanges();

const stepperDebugElement = fixture.debugElement.query(By.directive(MatStepper))!;
const stepperComponent: MatStepper = stepperDebugElement.componentInstance;

stepperComponent.steps.toArray()[0].editable = true;
stepperComponent.next();
fixture.detectChanges();

const header = stepperDebugElement.nativeElement.querySelector('mat-step-header');

expect(header.textContent).toContain('Custom edit');
});

it('should allow for the `done` icon to be overridden', () => {
const fixture = createComponent(IndirectDescendantIconOverridesStepper);
fixture.detectChanges();

const stepperDebugElement = fixture.debugElement.query(By.directive(MatStepper))!;
const stepperComponent: MatStepper = stepperDebugElement.componentInstance;

stepperComponent.steps.toArray()[0].editable = false;
stepperComponent.next();
fixture.detectChanges();

const header = stepperDebugElement.nativeElement.querySelector('mat-step-header');

expect(header.textContent).toContain('Custom done');
});

it('should allow for the `number` icon to be overridden with context', () => {
const fixture = createComponent(IndirectDescendantIconOverridesStepper);
fixture.detectChanges();

const stepperDebugElement = fixture.debugElement.query(By.directive(MatStepper))!;
const headers = stepperDebugElement.nativeElement.querySelectorAll('mat-step-header');

expect(headers[2].textContent).toContain('III');
});

});
});

/** Asserts that keyboard interaction works correctly. */
Expand Down Expand Up @@ -1510,6 +1583,26 @@ class IconOverridesStepper {
}
}

@Component({
template: `
<mat-horizontal-stepper>
<ng-container [ngSwitch]="true">
<ng-template matStepperIcon="edit">Custom edit</ng-template>
<ng-template matStepperIcon="done">Custom done</ng-template>
<ng-template matStepperIcon="number" let-index="index">
{{getRomanNumeral(index + 1)}}
</ng-template>
</ng-container>

<mat-step>Content 1</mat-step>
<mat-step>Content 2</mat-step>
<mat-step>Content 3</mat-step>
</mat-horizontal-stepper>
`
})
class IndirectDescendantIconOverridesStepper extends IconOverridesStepper {
}

@Component({
template: `
<mat-horizontal-stepper linear>
Expand All @@ -1536,3 +1629,18 @@ class StepperWithAriaInputs {
ariaLabel: string;
ariaLabelledby: string;
}


@Component({
template: `
<mat-vertical-stepper>
<ng-container [ngSwitch]="true">
<mat-step label="Step 1">Content 1</mat-step>
<mat-step label="Step 2">Content 2</mat-step>
<mat-step label="Step 3">Content 3</mat-step>
</ng-container>
</mat-vertical-stepper>
`
})
class StepperWithIndirectDescendantSteps {
}
4 changes: 2 additions & 2 deletions src/material/stepper/stepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ export class MatStepper extends CdkStepper implements AfterContentInit {
@ViewChildren(MatStepHeader) _stepHeader: QueryList<MatStepHeader>;

/** Steps that the stepper holds. */
@ContentChildren(MatStep) _steps: QueryList<MatStep>;
@ContentChildren(MatStep, {descendants: true}) _steps: QueryList<MatStep>;

/** Custom icon overrides passed in by the consumer. */
@ContentChildren(MatStepperIcon) _icons: QueryList<MatStepperIcon>;
@ContentChildren(MatStepperIcon, {descendants: true}) _icons: QueryList<MatStepperIcon>;

/** Event emitted when the current step is done transitioning in. */
@Output() readonly animationDone: EventEmitter<void> = new EventEmitter<void>();
Expand Down