Skip to content
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(accordion): add animations #3766

Merged
merged 1 commit into from
Aug 5, 2020

Conversation

fbasso
Copy link
Member

@fbasso fbasso commented Jun 11, 2020

Cherry picked from #2817, with some changes.

The key points are:

  • Animations are managed one panel at a time, in the original code, a loop was done on all panels to guess if an animation is required, for each panel. The code is simpler this way, and aligned with ngbTransition API,
  • ngbCollapseChange event have been added. It follows the collapse widget, to discuss if the name/API must be changed,
  • A little change in ngbTransition has been required, to provide the context when animations are deactivated,
  • Tests have been done the same way the collpase widget,
  • Some detectChanges have been added in the previous tests, because of the changeDetector.detectChanges() required in _runTransition,
  • Only one commit in this PR, as there are only a few impacted files.

@fbasso fbasso force-pushed the animations-accordion branch 2 times, most recently from 4505ab1 to ee3e15f Compare June 11, 2020 08:29
@codecov-commenter
Copy link

codecov-commenter commented Jun 11, 2020

Codecov Report

Merging #3766 into animations will increase coverage by 0.04%.
The diff coverage is 100.00%.

Impacted file tree graph

@@              Coverage Diff               @@
##           animations    #3766      +/-   ##
==============================================
+ Coverage       91.78%   91.82%   +0.04%     
==============================================
  Files             107      107              
  Lines            3127     3145      +18     
  Branches          565      566       +1     
==============================================
+ Hits             2870     2888      +18     
  Misses            189      189              
  Partials           68       68              
Flag Coverage Δ
#e2e 55.23% <19.04%> (-0.23%) ⬇️
#unit 88.93% <100.00%> (+0.06%) ⬆️
Impacted Files Coverage Δ
src/accordion/accordion-config.ts 100.00% <100.00%> (ø)
src/accordion/accordion.ts 97.56% <100.00%> (+0.63%) ⬆️
src/util/transition/ngbTransition.ts 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5e941d7...a3a11bf. Read the comment docs.

Copy link
Member

@maxokorokov maxokorokov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, @fbasso!

Thanks, this is shorter than before! Left some comments.

  • first let's agree on the event API, I have my thoughts in the comment below
  • add tests for collapsing events with animations = false
  • check the payload of those events in tests
  • I think we can remove zone.onStable and all double fixture.detectChanges() from tests
  • don't run detectChanges() N times for N panels
  • Either remove the fix for the ngbRunTransition or add tests

Cheers,
Max

src/accordion/accordion.spec.ts Outdated Show resolved Hide resolved
/**
* If `true`, accordion will be animated.
*/
@Input() animation = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove = false

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not fixed

src/accordion/accordion.ts Outdated Show resolved Hide resolved
src/accordion/accordion.ts Outdated Show resolved Hide resolved
src/util/transition/ngbTransition.ts Outdated Show resolved Hide resolved
src/accordion/accordion.ts Outdated Show resolved Hide resolved
src/accordion/accordion.ts Outdated Show resolved Hide resolved
src/accordion/accordion.ts Outdated Show resolved Hide resolved
src/accordion/accordion.ts Outdated Show resolved Hide resolved
src/accordion/accordion.ts Outdated Show resolved Hide resolved
@fbasso fbasso force-pushed the animations-accordion branch 3 times, most recently from d0f666b to 45a0535 Compare June 22, 2020 14:41
Copy link
Member

@maxokorokov maxokorokov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, @fbasso!

LGTM for the code!
The comments I have mostly test- and documentation-related.

I guess that would be the last batch:

  • Please check shown/hidden is called in the tests (you're still not doing it when animations enabled)
  • Please remove animation = false in the NgbAccordion (you forgot to do it form the last review)
  • Please add comments in the code for "tricky" parts (ex. why do we need change detection and why we restart transition even thought it might already be running)
  • some other minor comments.

reduceMotion = true;
onShown = (panelId) => panelId;
onHidden = (panelId) => panelId;
onFirstPanelShown = () => {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. you're not using this in ANY tests, please add checks that these callbacks are actually called
  2. you could have 1 function and just check what id it is called with:
onPanelShown = () = {};
(shown)="onPanelShown('one')"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, I need only the check on panel one, so I'll use it without parameter.


// Select the first tab -> change event
getButton(fixture.nativeElement, 0).click();
fixture.detectChanges();
expect(fixture.componentInstance.changeCallback)
.toHaveBeenCalledWith(jasmine.objectContaining({panelId: 'one', nextState: true}));
expect(fixture.componentInstance.shownCallback).toHaveBeenCalledWith('one');
expect(fixture.componentInstance.panelShownCallback).toHaveBeenCalled();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we check with .toHaveBeenCalledWith(undefined) instead?


// Select the first tab again -> change event
getButton(fixture.nativeElement, 0).click();
fixture.detectChanges();
expect(fixture.componentInstance.changeCallback)
.toHaveBeenCalledWith(jasmine.objectContaining({panelId: 'one', nextState: false}));
expect(fixture.componentInstance.hiddenCallback).toHaveBeenCalledWith('one');
expect(fixture.componentInstance.panelHiddenCallback).toHaveBeenCalled();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we check with .toHaveBeenCalledWith(undefined) instead?

@@ -552,25 +555,37 @@ describe('ngb-accordion', () => {
expect(panelContents.length).toBe(3);
});

it('should emit panel change event when toggling panels', () => {
it('should emit panel events when toggling panels', () => {
const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();

fixture.componentInstance.changeCallback = () => {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove all these:

fuxture.componentInstance.xxx = () => {}

They're already declared in the TestComponent, no need to re-declare them

const onHiddenSpy = spyOn(fixture.componentInstance, 'onHidden');

// First we're going to collapse, then expand
let opened = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why have this flag? it's not used anywhere

/**
* If `true`, accordion will be animated.
*/
@Input() animation = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not fixed

@@ -216,7 +239,18 @@ export class NgbAccordion implements AfterContentChecked {
*/
@Output() panelChange = new EventEmitter<NgbPanelChangeEvent>();

constructor(config: NgbAccordionConfig) {
/**
* An event emitted when a panel is shown, after the transition. The payload is the panel id.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we be more specific, please ? meaning that "when the panel is shown" is not very clear...

Maybe An event emitted when the expanding animation is finished on the panel ?

@Output() shown = new EventEmitter<string>();

/**
* An event emitted when a panel is hidden, after the transition. The payload is the panel id.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, but collapsing animation. Would also be nice to precise, if DOM content is expected to be removed at this point or not.

src/accordion/accordion.ts Show resolved Hide resolved
src/accordion/accordion.ts Show resolved Hide resolved
@fbasso
Copy link
Member Author

fbasso commented Jul 7, 2020

I push again with all the requested changes (I hope I didn't forget anything !).

Unfortunately, I had to change the accordion code again. This is due to some failing tests on what classes are expected (after the ngbTransition refactor with the startFn): classes managed by the transitions shouldn't be managed by bindings.

I'm not very happy with the code produced, but this is due to the initial code which would require a BIG refactor, probably in order to avoid ngAfterContentChecked usage (in favor of ngChanges for the accordion, and (headerClick) usage in panels. There are also some inconsistency (in the base code), like:

  • activeIds documentation : An array or comma separated strings of panel ids that should be opened initially,
  • should toggle panels based on "activeIds" values testing just the opposite.

I did not want to include this refactor, otherwise the review would be much harder.

Copy link
Member

@maxokorokov maxokorokov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, @fbasso, just will put a quick summary here.

In the latest version:

  • demos are not working
  • by doing _runTransitions in the afterContentCheked we're triggering it on each CD. On top of this the first thing _runTrainsitions is doing is actually detectChanges(). I think we should find a way to trigger transitions the same way we're doing for the collapse → only on binding changes, manual clicks or imperative toggles

@fbasso
Copy link
Member Author

fbasso commented Jul 31, 2020

Last changes pushed !

I finally managed to eliminate the change detection change on AfterContentChecked, but the code required is (again) not satisfying in terms of simplicity and clarity ! The constraints given by the AfterContentChecked and the fact to not setup animation classes in the template (it produces other drawbacks and failures) is so hard that I failed to find something else 😞.

@maxokorokov , @benouat, don't hesitate to share if you have other ideas.

@fbasso fbasso force-pushed the animations-accordion branch 2 times, most recently from 156e642 to 388b90c Compare August 3, 2020 15:30
@maxokorokov maxokorokov merged commit 99de349 into ng-bootstrap:animations Aug 5, 2020
@fbasso fbasso deleted the animations-accordion branch August 5, 2020 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants