Skip to content

chore(accordion): adds disabled property to CDK accordion-item (#8141) #8201

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
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
159 changes: 112 additions & 47 deletions src/cdk/accordion/accordion-item.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,55 +31,106 @@ describe('CdkAccordionItem', () => {
.injector.get(CdkAccordionItem);
});

it('should toggle its expanded state', () => {
expect(item.expanded).toBe(false);
item.toggle();
expect(item.expanded).toBe(true);
item.toggle();
expect(item.expanded).toBe(false);
describe('that is not disabled', () => {
beforeEach(() => {
item.disabled = false;
});

it('should toggle its expanded state', () => {
expect(item.expanded).toBe(false);
item.toggle();
expect(item.expanded).toBe(true);
item.toggle();
expect(item.expanded).toBe(false);
});

it('should set its expanded state to expanded', () => {
item.expanded = false;
item.open();
expect(item.expanded).toBe(true);
});

it('should set its expanded state to closed', () => {
item.expanded = true;
item.close();
expect(item.expanded).toBe(false);
});

it('should emit a closed event', () => {
item.open();
fixture.detectChanges();
spyOn(item.closed, 'emit');
item.close();
fixture.detectChanges();
expect(item.closed.emit).toHaveBeenCalled();
});

it('should not emit a closed event when the item is closed already', () => {
expect(item.expanded).toBe(false);
spyOn(item.closed, 'emit');
item.close();
fixture.detectChanges();
expect(item.closed.emit).not.toHaveBeenCalled();
});

it('should emit an opened event', () => {
spyOn(item.opened, 'emit');
item.open();
fixture.detectChanges();
expect(item.opened.emit).toHaveBeenCalled();
});

it('should emit a destroyed event', () => {
spyOn(item.destroyed, 'emit');
item.ngOnDestroy();
fixture.detectChanges();
expect(item.destroyed.emit).toHaveBeenCalled();
});
});

it('should set its expanded state to expanded', () => {
item.expanded = false;
item.open();
expect(item.expanded).toBe(true);
});

it('should set its expanded state to closed', () => {
item.expanded = true;
item.close();
expect(item.expanded).toBe(false);
});

it('should emit a closed event', () => {
item.open();
fixture.detectChanges();
spyOn(item.closed, 'emit');
item.close();
fixture.detectChanges();
expect(item.closed.emit).toHaveBeenCalled();
});

it('should not emit a closed event when the item is closed already', () => {
expect(item.expanded).toBe(false);
spyOn(item.closed, 'emit');
item.close();
fixture.detectChanges();
expect(item.closed.emit).not.toHaveBeenCalled();
});

it('should emit an opened event', () => {
spyOn(item.opened, 'emit');
item.open();
fixture.detectChanges();
expect(item.opened.emit).toHaveBeenCalled();
});

it('should emit an destroyed event', () => {
spyOn(item.destroyed, 'emit');
item.ngOnDestroy();
fixture.detectChanges();
expect(item.destroyed.emit).toHaveBeenCalled();
describe('that is disabled', () => {
beforeEach(() => {
item.disabled = true;
});

it('should not toggle its expanded state', () => {
expect(item.expanded).toBe(false);
item.toggle();
expect(item.expanded).toBe(false);
});

it('should not set its expanded state to expanded', () => {
item.expanded = false;
item.open();
expect(item.expanded).toBe(false);
});

it('should not set its expanded state to closed', () => {
item.expanded = true;
item.close();
expect(item.expanded).toBe(true);
});

it('should not emit a closed event', () => {
spyOn(item.closed, 'emit');
item.close();
fixture.detectChanges();
expect(item.closed.emit).not.toHaveBeenCalled();
});

it('should not emit an opened event', () => {
spyOn(item.opened, 'emit');
item.open();
fixture.detectChanges();
expect(item.opened.emit).not.toHaveBeenCalled();
});

it('should emit a destroyed event', () => {
spyOn(item.destroyed, 'emit');
item.ngOnDestroy();
fixture.detectChanges();
expect(item.destroyed.emit).toHaveBeenCalled();
});
});
});

Expand Down Expand Up @@ -109,6 +160,20 @@ describe('CdkAccordionItem', () => {
expect(firstItem.expanded).toBe(true);
expect(secondItem.expanded).toBe(true);
});

it('should not change expanded state for disabled items', () => {
firstItem.disabled = true;
expect(firstItem.expanded).toBe(false);
expect(secondItem.expanded).toBe(false);
firstItem.open();
fixture.detectChanges();
expect(firstItem.expanded).toBe(false);
expect(secondItem.expanded).toBe(false);
secondItem.open();
fixture.detectChanges();
expect(firstItem.expanded).toBe(false);
expect(secondItem.expanded).toBe(true);
});
});


Expand Down
18 changes: 15 additions & 3 deletions src/cdk/accordion/accordion-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ export class CdkAccordionItem implements OnDestroy {
}
private _expanded = false;

/** Whether the AccordionItem is disabled. */
@Input()
get disabled() { return this._disabled; }
set disabled(disabled: any) { this._disabled = coerceBooleanProperty(disabled); }
private _disabled: boolean = false;

/** Unregister function for _expansionDispatcher. */
private _removeUniqueSelectionListener: () => void = () => {};

Expand All @@ -101,16 +107,22 @@ export class CdkAccordionItem implements OnDestroy {

/** Toggles the expanded state of the accordion item. */
toggle(): void {
this.expanded = !this.expanded;
if (!this.disabled) {
this.expanded = !this.expanded;
}
}

/** Sets the expanded state of the accordion item to false. */
close(): void {
this.expanded = false;
if (!this.disabled) {
this.expanded = false;
}
}

/** Sets the expanded state of the accordion item to true. */
open(): void {
this.expanded = true;
if (!this.disabled) {
this.expanded = true;
}
}
}
2 changes: 1 addition & 1 deletion src/cdk/accordion/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class CdkAccordion {
/** A readonly id value to use for unique selection coordination. */
readonly id = `cdk-accordion-${nextId++}`;

/** Whether the accordion should allow multiple expanded accordion items simulateously. */
/** Whether the accordion should allow multiple expanded accordion items simultaneously. */
@Input()
get multi(): boolean { return this._multi; }
set multi(multi: boolean) { this._multi = coerceBooleanProperty(multi); }
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/accordion/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/

export {CdkAccordionItem} from './accordion-item';
export {CdkAccordionItem} from './accordion-item';
export {CdkAccordion} from './accordion';
export * from './accordion-module';
4 changes: 1 addition & 3 deletions src/lib/expansion/expansion-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import {MatAccordion} from './accordion';
import {MatExpansionPanelContent} from './expansion-panel-content';
import {
MatExpansionPanel,
MatExpansionPanelActionRow,
MatExpansionPanelBase
MatExpansionPanelActionRow
} from './expansion-panel';
import {
MatExpansionPanelDescription,
Expand All @@ -38,7 +37,6 @@ import {
MatExpansionPanelContent,
],
declarations: [
MatExpansionPanelBase,
MatAccordion,
MatExpansionPanel,
MatExpansionPanelActionRow,
Expand Down
4 changes: 1 addition & 3 deletions src/lib/expansion/expansion-panel-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ export class MatExpansionPanelHeader implements OnDestroy {

/** Toggles the expanded state of the panel. */
_toggle(): void {
if (!this.panel.disabled) {
this.panel.toggle();
}
this.panel.toggle();
}

/** Gets whether the panel is expanded. */
Expand Down
30 changes: 3 additions & 27 deletions src/lib/expansion/expansion-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
ChangeDetectorRef,
Component,
Directive,
forwardRef,
Host,
Input,
OnChanges,
Expand All @@ -25,7 +24,6 @@ import {
} from '@angular/core';
import {CdkAccordionItem} from '@angular/cdk/accordion';
import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
import {CanDisable, mixinDisabled} from '@angular/material/core';
import {TemplatePortal} from '@angular/cdk/portal';
import {Subject} from 'rxjs/Subject';
import {take} from 'rxjs/operators/take';
Expand All @@ -36,24 +34,6 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {MatExpansionPanelContent} from './expansion-panel-content';
import {matExpansionAnimations} from './expansion-animations';

// Boilerplate for applying mixins to MatExpansionPanel.
/** @docs-private */
@Component({
template: '',
moduleId: module.id,
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatExpansionPanelBase extends CdkAccordionItem {
constructor(accordion: MatAccordion,
_changeDetectorRef: ChangeDetectorRef,
_uniqueSelectionDispatcher: UniqueSelectionDispatcher) {
super(accordion, _changeDetectorRef, _uniqueSelectionDispatcher);
}
}
export const _MatExpansionPanelMixinBase = mixinDisabled(MatExpansionPanelBase);

/** MatExpansionPanel's states. */
export type MatExpansionPanelState = 'expanded' | 'collapsed';

Expand Down Expand Up @@ -82,14 +62,10 @@ let uniqueId = 0;
'class': 'mat-expansion-panel',
'[class.mat-expanded]': 'expanded',
'[class.mat-expansion-panel-spacing]': '_hasSpacing()',
},
providers: [
{provide: _MatExpansionPanelMixinBase, useExisting: forwardRef(() => MatExpansionPanel)}
],
}
})
export class MatExpansionPanel extends _MatExpansionPanelMixinBase
implements CanDisable, AfterContentInit, OnChanges, OnDestroy {

export class MatExpansionPanel extends CdkAccordionItem
implements AfterContentInit, OnChanges, OnDestroy {
/** Whether the toggle indicator should be hidden. */
@Input()
get hideToggle(): boolean { return this._hideToggle; }
Expand Down