Skip to content

Commit

Permalink
feat(accordion): add output for isOpen state changes (#2619)
Browse files Browse the repository at this point in the history
* feat(accordion): add output for isOpen state changes

* feat(accordion): make isOpen two way bindable

* fix(accordion): fix isOpenChange, fix tests
  • Loading branch information
steelsojka authored and valorkin committed Oct 23, 2017
1 parent 479b046 commit 663f078
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 17 deletions.
8 changes: 4 additions & 4 deletions demo/src/app/components/+accordion/demos/basic/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
</div>
This is just some content to illustrate fancy headings.
</accordion-group>
<accordion-group heading="Content 1">
<p>Content 1</p>
<accordion-group heading="Group with isOpenChange event listener" (isOpenChange)="log($event)">
<p>Some content</p>
</accordion-group>
<accordion-group heading="Content 2">
<p>Content 2</p>
<accordion-group heading="Another group">
<p>Some content</p>
</accordion-group>
</accordion>
6 changes: 5 additions & 1 deletion demo/src/app/components/+accordion/demos/basic/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ import { Component } from '@angular/core';
selector: 'demo-accordion-basic',
templateUrl: './basic.html'
})
export class DemoAccordionBasicComponent {}
export class DemoAccordionBasicComponent {
log(event: boolean) {
console.log(`Accordion has been ${event ? 'opened' : 'closed'}`);
}
}
9 changes: 7 additions & 2 deletions demo/src/ng-api-doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,20 @@ export const ngdoc: any = {
{
"name": "isOpen",
"type": "boolean",
"description": "<p>Is accordion group open or closed </p>\n"
"description": "<p>Is accordion group open or closed. This property supports two-way binding </p>\n"
},
{
"name": "panelClass",
"type": "string",
"description": "<p>Provides an ability to use Bootstrap&#39;s contextual panel classes\n(<code>panel-primary</code>, <code>panel-success</code>, <code>panel-info</code>, etc...).\nList of all available classes [available here]\n(<a href=\"http://getbootstrap.com/components/#panels-alternatives\" target=\"_blank\" title=\"null\">http://getbootstrap.com/components/#panels-alternatives</a>)</p>\n"
}
],
"outputs": [],
"outputs": [
{
"name": "isOpenChange",
"description": "<p>Emits when the opened state changes </p>\n"
}
],
"properties": [],
"methods": []
},
Expand Down
19 changes: 13 additions & 6 deletions src/accordion/accordion-group.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
Component, HostBinding, Inject, Input, OnDestroy, OnInit
Component, HostBinding, Inject, Input, OnDestroy, OnInit, Output, EventEmitter
} from '@angular/core';
import { isBs3 } from '../utils/theme-provider';
import { AccordionComponent } from './accordion.component';
Expand Down Expand Up @@ -29,27 +29,34 @@ export class AccordionPanelComponent implements OnInit, OnDestroy {
@Input() panelClass: string;
/** if <code>true</code> — disables accordion group */
@Input() isDisabled: boolean;
/** Emits when the opened state changes */
@Output() isOpenChange: EventEmitter<boolean> = new EventEmitter();

// Questionable, maybe .panel-open should be on child div.panel element?
/** Is accordion group open or closed */
/** Is accordion group open or closed. This property supports two-way binding */
@HostBinding('class.panel-open')
@Input()
get isOpen(): boolean {
return this._isOpen;
}

set isOpen(value: boolean) {
this._isOpen = value;
if (value) {
this.accordion.closeOtherPanels(this);
if (value !== this.isOpen) {
if (value) {
this.accordion.closeOtherPanels(this);
}
this._isOpen = value;
Promise.resolve(null).then(() => {
this.isOpenChange.emit(value);
});
}
}

get isBs3(): boolean {
return isBs3();
}

protected _isOpen: boolean;
protected _isOpen = false;
protected accordion: AccordionComponent;

constructor(@Inject(AccordionComponent) accordion: AccordionComponent) {
Expand Down
36 changes: 32 additions & 4 deletions src/spec/accordion.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { AccordionConfig } from '../accordion/accordion.config';

import { AccordionModule } from '../accordion/accordion.module';
Expand All @@ -25,19 +25,19 @@ const html = `
<accordion [closeOthers]="oneAtATime">
<accordion-group heading="Panel 1"
[isOpen]="panels[0].isOpen"
[(isOpen)]="panels[0].isOpen"
[isDisabled]="panels[0].isDisabled">
Content of panel 1
</accordion-group>
<accordion-group heading="Panel 2"
[isOpen]="panels[1].isOpen"
[(isOpen)]="panels[1].isOpen"
[isDisabled]="panels[1].isDisabled">
Content of panel 2
</accordion-group>
<accordion-group heading="Panel 3"
[isOpen]="panels[2].isOpen"
[(isOpen)]="panels[2].isOpen"
[isDisabled]="panels[2].isDisabled">
Content of panel 3
</accordion-group>
Expand Down Expand Up @@ -166,4 +166,32 @@ describe('Component: Accordion', () => {
fixture.detectChanges();
expectOpenPanels(element, [false, false, false]);
});

it('should modify the parent isOpen state when changed internally (2 way binding)', fakeAsync(() => {
const headingLinks = element.querySelectorAll('.accordion-toggle');

// Clicking (internal state modified)
headingLinks[0].click();
tick();
fixture.detectChanges();
expect(context.panels[0].isOpen).toBe(true);
expect(context.panels[1].isOpen).toBe(false);
expect(context.panels[2].isOpen).toBe(false);

// State modified by parent component
headingLinks[2].click();
tick();
fixture.detectChanges();
expect(context.panels[0].isOpen).toBe(false);
expect(context.panels[1].isOpen).toBe(false);
expect(context.panels[2].isOpen).toBe(true);

// Modified by binding
context.panels[1].isOpen = true;
fixture.detectChanges();
tick();
expect(context.panels[0].isOpen).toBe(false);
expect(context.panels[1].isOpen).toBe(true);
expect(context.panels[2].isOpen).toBe(false);
}));
});

0 comments on commit 663f078

Please sign in to comment.