-
Notifications
You must be signed in to change notification settings - Fork 6.8k
feat(expansion): add accordion expand/collapse all (#6929) #7461
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
feat(expansion): add accordion expand/collapse all (#6929) #7461
Conversation
835b6fb
to
1a41208
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, just a few nit.
src/lib/expansion/accordion.ts
Outdated
/** | ||
* Expands all enabled expansion panels in an accordion where multi is enabled | ||
*/ | ||
expandAll() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add return type void
src/lib/expansion/accordion.ts
Outdated
/** | ||
* Collapses all enabled expansion panels in an accordion where multi is enabled | ||
*/ | ||
collapseAll() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add return type void
src/lib/expansion/accordion.ts
Outdated
this._expandCollapseAll(false); | ||
} | ||
|
||
_expandCollapseAll(expanded: boolean) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add return type void
|
||
@Component({ | ||
moduleId: module.id, | ||
selector: 'expansion-demo', | ||
styleUrls: ['expansion-demo.css'], | ||
templateUrl: 'expansion-demo.html', | ||
encapsulation: ViewEncapsulation.None, | ||
preserveWhitespaces: false, | ||
preserveWhitespaces: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to stay false
src/lib/expansion/accordion.ts
Outdated
@@ -25,7 +26,10 @@ 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. */ | |||
/** Stream that emits when expandAll or collapseAll is triggered. */ | |||
readonly expandCollapseAllSubject: Subject<boolean> = new Subject<boolean>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mark this with an underscore to denote that it is internal-only and add a JsDoc description (specifically that the boolean
denotes expanded/collapsed)
// When a panel is hosted in an accordion, subscribe to the expand/collapse subject | ||
if (this.panel.accordion) { | ||
this._expandCollapseAllSubscription = | ||
this.panel.accordion.expandCollapseAllSubject.subscribe((expanded: boolean) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type for expanded
doesn't need to be given here because it is inferred from the observable.
|
||
// When a panel is hosted in an accordion, subscribe to the expand/collapse subject | ||
if (this.panel.accordion) { | ||
this._expandCollapseAllSubscription = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move the contents of this if
block to a separate method? Something like _subscribeToAccordionActions
@@ -101,6 +102,17 @@ export class MatExpansionPanelHeader implements OnDestroy { | |||
.subscribe(() => this._changeDetectorRef.markForCheck()); | |||
|
|||
_focusMonitor.monitor(_element.nativeElement, renderer, false); | |||
|
|||
// When a panel is hosted in an accordion, subscribe to the expand/collapse subject | |||
if (this.panel.accordion) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By placing the logic for setting panel expansion state in the MatExpansionPanelHeader
it ties the logic specifically to the Material implementation rather than the CDK base.
I would suggestion adding this logic to the AccordionItem
class.
There you can set the expanded state directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need access to the disabled
state of the hosting panel to prevent disabled panels from being expanded/collapsed, which is why I used _toggle()
. Is there another way to get access to this property without too much refactoring?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think I may have solved it with mixinDisabled
- let me know if that is not a desired solution though. Cheers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We actually just removed the mixinDisabled from AccordionItem as we are moving it to CDK. You can see the move in #7530
I supposed you could bake the expandAll
/collapseAll
into the AccordionItem
, and then in MatExpansionPanel
, extend the setter of expanded
to respect disabled
. This would allow the expandAll
/collapseAll
functionality to live in the CDK, but work as expected in MatAccordion
. Admittedly I haven't thought this idea entirely through and would need to consider the ramifications a bit more before saying its definitely the best option or the option to go with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @josephperrott - I will wait for #7530 to be merged and then take it from there.
// Only toggle if current state is not the intended state | ||
if (!!this._isExpanded() !== expanded) { | ||
this._toggle(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coupled with the move to AccordionItem
, I would suggest just setting the expanded state directly rather than checking if a toggle needs to occur.
this.panel.accordion.expandCollapseAllSubject.subscribe(expanded => this.expanded = expanded);
src/lib/expansion/accordion.ts
Outdated
@@ -44,6 +48,26 @@ export class CdkAccordion { | |||
* elevation. | |||
*/ | |||
@Input() displayMode: MatAccordionDisplayMode = 'default'; | |||
|
|||
/** | |||
* Expands all enabled expansion panels in an accordion where multi is enabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsDoc comments should be complete sentences so add a .
here?
Thanks for the feedback @amcdnl, @jelbourn and @josephperrott - will get this sorted asap. Unable to figure out if the Travis Sauce Labs failures are just platform problems or issues with this ticket. Also, do I need to take any action on the Screenshot Tests? |
@ouq77 We have been having some issues with our saucelab tests, I don't think its from you. For the screenshot tests, no need to worrry about them unless they are we are seeing failures in the expansion panels. Once we get to a LGTM state on this PR, I can make the screenshot tests as good, however I want to wait as it will reset after every new push to the branch. |
9c95e7b
to
1bd3b61
Compare
18f0593
to
e4dca02
Compare
@josephperrott I attempted your suggestion of adding the functionality in the CDK, but couldn't find an elegant way of accessing the Since this is mainly a Material concern, leaving it in this layer is probably acceptable. Let me know if this is not an ideal and I can rethink it. Is there any chance that the |
I spoke with @jelbourn and there does not seem to be an issue with moving some of the |
Is this something I can help with @josephperrott? Should probably be done against a separate issue? |
@ouq77 You definitely can move it to the CDK if you would like. It should be done in another pull ideally. |
@josephperrott should this PR be revisited? |
@josephperrott and @jelbourn - this PR is blocked until (and will be reworked after) #8201 has been dealt with. I've been keeping that one up to date hoping it will be revisited soon. Cheers. |
PR is now unblocked with the merge of #8201 |
23cc812
to
1b2aaa8
Compare
Knew I forgot something - updated now :) |
1b2aaa8
to
0bff53f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just the one comment, then it looks good to me. Though the change to naming will likely have some precipitating effects.
src/cdk/accordion/accordion.ts
Outdated
@@ -28,4 +32,20 @@ export class CdkAccordion { | |||
get multi(): boolean { return this._multi; } | |||
set multi(multi: boolean) { this._multi = coerceBooleanProperty(multi); } | |||
private _multi: boolean = false; | |||
|
|||
/** Expands all enabled accordion items in an accordion where multi is enabled. */ | |||
expandAll(): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should likely be openAll
and closeAll
to match the naming convention used in CdkAccordionItem
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
12ab88a
to
12e74a9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
src/cdk/accordion/accordion-item.ts
Outdated
@@ -125,4 +134,13 @@ export class CdkAccordionItem implements OnDestroy { | |||
this.expanded = true; | |||
} | |||
} | |||
|
|||
private _subscribeToExpandCollapseAllActions(): Subscription { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method should likely be called subscribetoOpenCloseAllActions()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/cdk/accordion/accordion.ts
Outdated
this._expandCollapseAll(false); | ||
} | ||
|
||
private _expandCollapseAll(expanded: boolean): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be _openCloseAll()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Adds openAll()/closeAll() to perform expand/collapse all on multiple expandable accordions. Closes angular#6929
12e74a9
to
7c2e39e
Compare
} | ||
|
||
private _openCloseAll(expanded: boolean): void { | ||
if (this.multi) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some cases, even for [multi]="false"
, where you don't care which CdkAccordionItem
is open, you just want to make sure that all are closed and it would be nice to also cover that use case, but I'm not sure how this could be done without confusing developers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you could do this.multi || !expanded
? Will have to experiment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be a solution, but we could have a "cleaner" solution, if I may use this word.
This would be a good solution for this particular case. But maybe we could find a more generic solution that could be used in other cases and not confuse people to much, openAll()
won't work in single mode, but we could have open()
that works for single mode, opening the first item or in multi mode.
If you look at something like the SelectionModel
for tables, select and chips, the selection has a getMultipleValuesInSingleSelectionError
, we could use something like that. And MatSelectionList.selectedOptions
exposes the model for anyone to use. But probably a model would be an overkill for this situation, I'm not sure in how many places we could reuse it.
Also, MatDrawerContainer
container has a similar behavior but it doesn't add the All
suffix and it uses @ContentChildren
to keep a list of children and then call open/close on each children, instead of emitting events, here's a snippet from it:
@ContentChildren(MatDrawer) _drawers: QueryList<MatDrawer>;
/** Calls `open` of both start and end drawers */
open(): void {
this._drawers.forEach(drawer => drawer.open());
}
/** Calls `close` of both start and end drawers */
close(): void {
this._drawers.forEach(drawer => drawer.close());
}
Using ContentChildren
instead of emitting an event and rename to open/close
in order to support "multi/single" mode, would be great.
P.S. Thanks for the work you did on this PR!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This maybe warrants a separate issue to investigate?
I created a demo using the example in the demo-app , but expand-all/collapse-all isn't working. |
@pankajsri03 - you are using cdk and material v5.2.1 in your example. This change will only be available in v6. (It is currently in beta) |
@pankajsri03 and @ouq77
|
As of NGMD 6.2.1, the problem persist: "openAll is not a function". Do I miss something? or someone in the NGMD team had forgotten to merge? |
@zijianhuang I assume your |
@ouq77, yes, the root element of consult-item is So, after NG rendering, mat-expansion-panel is hosted directly inside the mat-accordion. |
In the other parts of the program, I do have mat-expansion-panel directly inside the mat-accordion, however, openalll is still not function. After a few NG and MD releases, this is still not fixed. Now I just go with my own workaround or solution: publish an event, and all expansion panels subscribe it; when the parent component fire the event, all subscribers just open the expansion panels. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Add
expandAll()
/collapseAll()
to perform expand/collapse all on multiple expandable accordions.Closes #6929