Skip to content

Commit 1bd3b61

Browse files
henetirikiLouw Swart
authored andcommitted
feat(expansion): add accordion expand/collapse all (#6929)
Implements review feedback: * missing return type * updated JS Doc * internal-use only underscore * subscription in dedicated function * decoupled event handling from Material implementaion Closes #6929
1 parent f80cd96 commit 1bd3b61

File tree

4 files changed

+38
-23
lines changed

4 files changed

+38
-23
lines changed

src/demo-app/expansion/expansion-demo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {MatAccordion} from '@angular/material';
77
styleUrls: ['expansion-demo.css'],
88
templateUrl: 'expansion-demo.html',
99
encapsulation: ViewEncapsulation.None,
10-
preserveWhitespaces: true,
10+
preserveWhitespaces: false,
1111
})
1212
export class ExpansionDemo {
1313
@ViewChild(MatAccordion) accordion: MatAccordion;

src/lib/expansion/accordion-item.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,16 @@ import {
1616
ChangeDetectorRef,
1717
} from '@angular/core';
1818
import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
19+
import {CanDisable, mixinDisabled} from '@angular/material/core';
1920
import {CdkAccordion} from './accordion';
21+
import {Subscription} from 'rxjs/Subscription';
22+
23+
// Boilerplate for applying mixins to AccordionItem.
24+
/** @docs-private */
25+
export class AccordionItemBase {
26+
constructor() {}
27+
}
28+
export const _AccordionItemMixinBase = mixinDisabled(AccordionItemBase);
2029

2130
/** Used to generate unique ID for each expansion panel. */
2231
let nextId = 0;
@@ -26,7 +35,9 @@ let nextId = 0;
2635
* events and attributes needed to be managed by a CdkAccordion parent.
2736
*/
2837
@Injectable()
29-
export class AccordionItem implements OnDestroy {
38+
export class AccordionItem extends _AccordionItemMixinBase
39+
implements OnDestroy, CanDisable {
40+
private _expandCollapseAllSubscription = Subscription.EMPTY;
3041
/** Event emitted every time the AccordionItem is closed. */
3142
@Output() closed = new EventEmitter<void>();
3243
/** Event emitted every time the AccordionItem is opened. */
@@ -68,18 +79,25 @@ export class AccordionItem implements OnDestroy {
6879
constructor(@Optional() public accordion: CdkAccordion,
6980
private _changeDetectorRef: ChangeDetectorRef,
7081
protected _expansionDispatcher: UniqueSelectionDispatcher) {
82+
super();
7183
this._removeUniqueSelectionListener =
7284
_expansionDispatcher.listen((id: string, accordionId: string) => {
7385
if (this.accordion && !this.accordion.multi &&
7486
this.accordion.id === accordionId && this.id !== id) {
7587
this.expanded = false;
7688
}
7789
});
90+
91+
// When an accordion item is hosted in an accordion, subscribe to the expand/collapse subject.
92+
if (this.accordion) {
93+
this._expandCollapseAllSubscription = this._subscribeToExpandCollapseAllActions();
94+
}
7895
}
7996

8097
/** Emits an event for the accordion item being destroyed. */
8198
ngOnDestroy() {
8299
this.destroyed.emit();
100+
this._expandCollapseAllSubscription.unsubscribe();
83101
this._removeUniqueSelectionListener();
84102
}
85103

@@ -97,4 +115,14 @@ export class AccordionItem implements OnDestroy {
97115
open(): void {
98116
this.expanded = true;
99117
}
118+
119+
_subscribeToExpandCollapseAllActions(): Subscription {
120+
return this.accordion._expandCollapseAllActions
121+
.subscribe(expanded => {
122+
// Only change state if item is enabled
123+
if (!this.disabled) {
124+
this.expanded = expanded;
125+
}
126+
});
127+
}
100128
}

src/lib/expansion/accordion.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ export class CdkAccordion {
2727
/** A readonly id value to use for unique selection coordination. */
2828
readonly id = `cdk-accordion-${nextId++}`;
2929

30-
/** Stream that emits when expandAll or collapseAll is triggered. */
31-
readonly expandCollapseAllSubject: Subject<boolean> = new Subject<boolean>();
30+
/** Stream that emits true/false when expandAll/collapseAll is triggered. */
31+
readonly _expandCollapseAllActions: Subject<boolean> = new Subject<boolean>();
3232

3333
/** Whether the accordion should allow multiple expanded accordion items simultaneously. */
3434
@Input() get multi(): boolean { return this._multi; }
@@ -51,22 +51,22 @@ export class CdkAccordion {
5151
@Input() displayMode: MatAccordionDisplayMode = 'default';
5252

5353
/**
54-
* Expands all enabled expansion panels in an accordion where multi is enabled
54+
* Expands all enabled expansion panels in an accordion where multi is enabled.
5555
*/
56-
expandAll() {
56+
expandAll(): void {
5757
this._expandCollapseAll(true);
5858
}
5959

6060
/**
61-
* Collapses all enabled expansion panels in an accordion where multi is enabled
61+
* Collapses all enabled expansion panels in an accordion where multi is enabled.
6262
*/
63-
collapseAll() {
63+
collapseAll(): void {
6464
this._expandCollapseAll(false);
6565
}
6666

67-
_expandCollapseAll(expanded: boolean) {
67+
_expandCollapseAll(expanded: boolean): void {
6868
if (this.multi) {
69-
this.expandCollapseAllSubject.next(expanded);
69+
this._expandCollapseAllActions.next(expanded);
7070
}
7171
}
7272
}

src/lib/expansion/expansion-panel-header.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ import {EXPANSION_PANEL_ANIMATION_TIMING, MatExpansionPanel} from './expansion-p
8383
})
8484
export class MatExpansionPanelHeader implements OnDestroy {
8585
private _parentChangeSubscription = Subscription.EMPTY;
86-
private _expandCollapseAllSubscription = Subscription.EMPTY;
8786

8887
constructor(
8988
renderer: Renderer2,
@@ -102,17 +101,6 @@ export class MatExpansionPanelHeader implements OnDestroy {
102101
.subscribe(() => this._changeDetectorRef.markForCheck());
103102

104103
_focusMonitor.monitor(_element.nativeElement, renderer, false);
105-
106-
// When a panel is hosted in an accordion, subscribe to the expand/collapse subject
107-
if (this.panel.accordion) {
108-
this._expandCollapseAllSubscription =
109-
this.panel.accordion.expandCollapseAllSubject.subscribe((expanded: boolean) => {
110-
// Only toggle if current state is not the intended state
111-
if (!!this._isExpanded() !== expanded) {
112-
this._toggle();
113-
}
114-
});
115-
}
116104
}
117105

118106
/** Height of the header while the panel is expanded. */
@@ -164,7 +152,6 @@ export class MatExpansionPanelHeader implements OnDestroy {
164152

165153
ngOnDestroy() {
166154
this._parentChangeSubscription.unsubscribe();
167-
this._expandCollapseAllSubscription.unsubscribe();
168155
this._focusMonitor.stopMonitoring(this._element.nativeElement);
169156
}
170157
}

0 commit comments

Comments
 (0)