Skip to content

Commit 9c95e7b

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 35af242 commit 9c95e7b

File tree

4 files changed

+38
-24
lines changed

4 files changed

+38
-24
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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,16 @@ import {
1515
Optional,
1616
ChangeDetectorRef,
1717
} from '@angular/core';
18-
import {UniqueSelectionDispatcher} from '@angular/material/core';
18+
import {CanDisable, mixinDisabled, UniqueSelectionDispatcher} from '@angular/material/core';
1919
import {CdkAccordion} from './accordion';
20+
import {Subscription} from 'rxjs/Subscription';
21+
22+
// Boilerplate for applying mixins to AccordionItem.
23+
/** @docs-private */
24+
export class AccordionItemBase {
25+
constructor() {}
26+
}
27+
export const _AccordionItemMixinBase = mixinDisabled(AccordionItemBase);
2028

2129
/** Used to generate unique ID for each expansion panel. */
2230
let nextId = 0;
@@ -26,7 +34,9 @@ let nextId = 0;
2634
* events and attributes needed to be managed by a CdkAccordion parent.
2735
*/
2836
@Injectable()
29-
export class AccordionItem implements OnDestroy {
37+
export class AccordionItem extends _AccordionItemMixinBase
38+
implements OnDestroy, CanDisable {
39+
private _expandCollapseAllSubscription = Subscription.EMPTY;
3040
/** Event emitted every time the AccordionItem is closed. */
3141
@Output() closed = new EventEmitter<void>();
3242
/** Event emitted every time the AccordionItem is opened. */
@@ -68,18 +78,25 @@ export class AccordionItem implements OnDestroy {
6878
constructor(@Optional() public accordion: CdkAccordion,
6979
private _changeDetectorRef: ChangeDetectorRef,
7080
protected _expansionDispatcher: UniqueSelectionDispatcher) {
81+
super();
7182
this._removeUniqueSelectionListener =
7283
_expansionDispatcher.listen((id: string, accordionId: string) => {
7384
if (this.accordion && !this.accordion.multi &&
7485
this.accordion.id === accordionId && this.id !== id) {
7586
this.expanded = false;
7687
}
7788
});
89+
90+
// When an accordion item is hosted in an accordion, subscribe to the expand/collapse subject.
91+
if (this.accordion) {
92+
this._expandCollapseAllSubscription = this._subscribeToExpandCollapseAllActions();
93+
}
7894
}
7995

8096
/** Emits an event for the accordion item being destroyed. */
8197
ngOnDestroy() {
8298
this.destroyed.emit();
99+
this._expandCollapseAllSubscription.unsubscribe();
83100
this._removeUniqueSelectionListener();
84101
}
85102

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

src/lib/expansion/accordion.ts

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

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

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

5252
/**
53-
* Expands all enabled expansion panels in an accordion where multi is enabled
53+
* Expands all enabled expansion panels in an accordion where multi is enabled.
5454
*/
55-
expandAll() {
55+
expandAll(): void {
5656
this._expandCollapseAll(true);
5757
}
5858

5959
/**
60-
* Collapses all enabled expansion panels in an accordion where multi is enabled
60+
* Collapses all enabled expansion panels in an accordion where multi is enabled.
6161
*/
62-
collapseAll() {
62+
collapseAll(): void {
6363
this._expandCollapseAll(false);
6464
}
6565

66-
_expandCollapseAll(expanded: boolean) {
66+
_expandCollapseAll(expanded: boolean): void {
6767
if (this.multi) {
68-
this.expandCollapseAllSubject.next(expanded);
68+
this._expandCollapseAllActions.next(expanded);
6969
}
7070
}
7171
}

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)