Skip to content
This repository has been archived by the owner on Nov 6, 2024. It is now read-only.

Commit

Permalink
Fix mz-collapsible-item *ngFor manipulation (#289)
Browse files Browse the repository at this point in the history
  • Loading branch information
jfcere authored and scote committed Feb 21, 2018
1 parent 24fe029 commit 5f4dc62
Show file tree
Hide file tree
Showing 10 changed files with 245 additions and 85 deletions.
30 changes: 30 additions & 0 deletions demo-app/src/app/collapsible/collapsible.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ <h3>Collapsible</h3>
<div class="section">
<app-code-snippet>import &#123; MzCollapsibleModule &#125; from 'ng2-materialize'</app-code-snippet>
</div>

<h5 class="light">Accordion</h5>

<div class="row">
Expand Down Expand Up @@ -143,6 +144,35 @@ <h5 class="light">Preselected Section</h5>
</p>
</div>

<div class="section">

<h5 class="light">Playground</h5>

<p>
The <code class="language-markup">mz-collapsible-item</code> component can be dynamically manipulated when used with <code class="language-markup">*ngFor</code> allowing you to add, remove or replace items in the list.
</p>

<div class="row">

<mz-collapsible class="col s12 m8 l6" mode="accordion">

<mz-collapsible-item *ngFor="let item of playgroundCollapsibleItems">
<mz-collapsible-item-header><i mz-icon-mdi [icon]="item.icon"></i>{{ item.header }}</mz-collapsible-item-header>
<mz-collapsible-item-body><p>{{ item.body }}</p></mz-collapsible-item-body>
</mz-collapsible-item>

</mz-collapsible>

<div class="col s12 m4 l6">

<button mz-button (click)="add()">Add new item</button>
<button mz-button (click)="remove()">Remove last item</button>
<button mz-button (click)="replace()">Replace all</button>

</div>
</div>
</div>

<div class="section">

<h5 class="light">HTML Structure</h5>
Expand Down
127 changes: 106 additions & 21 deletions demo-app/src/app/collapsible/collapsible.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,71 @@ import { IPropertyRow } from '../shared/properties-table/properties-table.compon
animations: [ROUTE_ANIMATION],
})
export class CollapsibleComponent {
collapsibleProperties: IPropertyRow[] = [

// fake data
simpleCollapsibleItems = [
{
icon: 'cloud',
header: 'First',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum
dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,

},
{
icon: 'flash',
header: 'Second',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,
},
{
icon: 'gamepad',
header: 'Third',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,
},
];

// playground
playgroundCollapsibleItems = [
{
icon: 'cloud',
header: 'First',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum
dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,

},
{
icon: 'flash',
header: 'Second',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,
},
{
icon: 'gamepad',
header: 'Third',
body: `
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`,
},
];

// table properties
collapsibleProperties: IPropertyRow[] = [
{ name: 'mode',
mandatory: false,
type: 'string',
Expand Down Expand Up @@ -46,10 +110,10 @@ export class CollapsibleComponent {
},
];

public simpleCollapsibleItems = [
{
icon: 'cloud',
header: 'First',
add() {
this.playgroundCollapsibleItems.push({
icon: 'plus',
header: 'Added',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
Expand All @@ -58,21 +122,42 @@ export class CollapsibleComponent {
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum
dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,
});
}

},
{
icon: 'flash',
header: 'Second',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,
},
{
icon: 'gamepad',
header: 'Third',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,
},
];
remove() {
this.playgroundCollapsibleItems.splice(this.playgroundCollapsibleItems.length - 1);
}

replace() {
this.playgroundCollapsibleItems = [
{
icon: 'account',
header: 'Fourth',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Lorem ipsum
dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,

},
{
icon: 'star',
header: 'Fifth',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,
},
{
icon: 'heart',
header: 'Sixth',
body: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`,
},
];
}
}
3 changes: 2 additions & 1 deletion demo-app/src/app/collapsible/collapsible.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MzCollapsibleModule, MzIconMdiModule } from 'ng2-materialize';
import { MzButtonModule, MzCollapsibleModule, MzIconMdiModule } from 'ng2-materialize';

import { CodeSnippetModule } from '../shared/code-snippet/code-snippet.module';
import { PropertiesTableModule } from '../shared/properties-table/properties-table.module';
Expand All @@ -12,6 +12,7 @@ import { ROUTES } from './collapsible.routing';
imports: [
CodeSnippetModule,
CommonModule,
MzButtonModule,
MzCollapsibleModule,
MzIconMdiModule,
PropertiesTableModule,
Expand Down
3 changes: 2 additions & 1 deletion src/app/collapsible/collapsible.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<ul #collapsible
class="collapsible"
[class.popout]="popout"
[hidden]="items.length === 0"
>
<ng-content select="mz-collapsible-item"></ng-content>
<ng-content></ng-content>
</ul>
11 changes: 4 additions & 7 deletions src/app/collapsible/collapsible.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
AfterViewInit,
ChangeDetectorRef,
Component,
ContentChildren,
ElementRef,
Expand All @@ -25,7 +24,9 @@ export class MzCollapsibleComponent implements AfterViewInit {
@ViewChild('collapsible') collapsible: ElementRef;
@ContentChildren(MzCollapsibleItemComponent) items: QueryList<MzCollapsibleItemComponent>;

constructor(public changeDetectorRef: ChangeDetectorRef, public renderer: Renderer) { }
constructor(
public renderer: Renderer,
) { }

ngAfterViewInit(): void {
this.handleDataCollapsible();
Expand All @@ -39,11 +40,7 @@ export class MzCollapsibleComponent implements AfterViewInit {
onOpen: this.onOpen,
};

// need setTimeout otherwise loading directly on the page cause an error
setTimeout(() => this.renderer.invokeElementMethod($(this.collapsible.nativeElement), 'collapsible', [options]));

// forcing changes detection for unit test
this.changeDetectorRef.detectChanges();
this.renderer.invokeElementMethod($(this.collapsible.nativeElement), 'collapsible', [options]);
}

handleDataCollapsible() {
Expand Down
21 changes: 2 additions & 19 deletions src/app/collapsible/collapsible.component.unit.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { MzCollapsibleComponent } from './collapsible.component';

Expand Down Expand Up @@ -71,11 +71,7 @@ describe('MzCollapsibleComponent:unit', () => {

describe('initCollapsible', () => {

function forceSetTimeoutEnd() {
tick(1); // force setTimeout execution
}

it('should initialize collapsible using jquery', fakeAsync(() => {
it('should initialize collapsible using jquery', async(() => {

component.onClose = () => {};
component.onOpen = () => {};
Expand All @@ -92,8 +88,6 @@ describe('MzCollapsibleComponent:unit', () => {

component.initCollapsible();

forceSetTimeoutEnd();

expect(component.renderer.invokeElementMethod)
.toHaveBeenCalledWith(
mockJQueryCollapsibleNativeElement,
Expand All @@ -104,16 +98,5 @@ describe('MzCollapsibleComponent:unit', () => {
}],
);
}));

it('should call detectChanges', () => {

component.mode = 'accordion';

spyOn(component.changeDetectorRef, 'detectChanges').and.callThrough();

component.initCollapsible();

expect(component.changeDetectorRef.detectChanges).toHaveBeenCalled();
});
});
});
45 changes: 31 additions & 14 deletions src/app/collapsible/collapsible.component.view.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { async, TestBed } from '@angular/core/testing';

import { buildComponent, MzTestWrapperComponent } from '../shared/test-wrapper';
import {
Expand Down Expand Up @@ -28,21 +28,17 @@ describe('MzCollapsibleComponent:view', () => {

let nativeElement: any;

function collapsible() {
function collapsible(): HTMLUListElement {
return nativeElement.querySelector('.collapsible');
}

function collapsibleItem() {
function collapsibleItem(): HTMLLIElement {
return collapsible().querySelector('li');
}

function forceSetTimeoutEnd() {
tick(1 * 1000000); // todo: understand why 1 is not working (setTimeOut is set to 0)
}

it('should display a collapsible', async(() => {

buildComponent<MzCollapsibleComponent>(`<mz-collapsible></mz-collapsible>`).then((fixture) => {
buildComponent(`<mz-collapsible></mz-collapsible>`).then((fixture) => {

nativeElement = fixture.nativeElement;
fixture.detectChanges();
Expand All @@ -53,7 +49,7 @@ describe('MzCollapsibleComponent:view', () => {

it('should have mode when provided', async(() => {

buildComponent<MzCollapsibleComponent>(`<mz-collapsible [mode]="'accordion'"></mz-collapsible>`).then((fixture) => {
buildComponent(`<mz-collapsible [mode]="'accordion'"></mz-collapsible>`).then((fixture) => {

nativeElement = fixture.nativeElement;
fixture.detectChanges();
Expand All @@ -64,7 +60,7 @@ describe('MzCollapsibleComponent:view', () => {

it('should have popout when provided', async(() => {

buildComponent<MzCollapsibleComponent>(`<mz-collapsible [popout]="true"></mz-collapsible>`).then((fixture) => {
buildComponent(`<mz-collapsible [popout]="true"></mz-collapsible>`).then((fixture) => {

nativeElement = fixture.nativeElement;
fixture.detectChanges();
Expand All @@ -73,9 +69,32 @@ describe('MzCollapsibleComponent:view', () => {
});
}));

it('should transclude collapsible item', fakeAsync(() => {
it('should be hidden when there is no collapsible items', async(() => {

buildComponent<{ visible: boolean }>(`
<mz-collapsible>
<mz-collapsible-item *ngIf="visible">
</mz-collapsible-item>
</mz-collapsible>
`, {
visible: true,
}).then((fixture) => {
const component = fixture.componentInstance;
nativeElement = fixture.nativeElement;
fixture.detectChanges();

expect(collapsible().hasAttribute('hidden')).toBeFalsy();

component.visible = false;
fixture.detectChanges();

expect(collapsible().hasAttribute('hidden')).toBeTruthy();
});
}));

it('should transclude collapsible item', async(() => {

buildComponent<MzCollapsibleComponent>(`
buildComponent(`
<mz-collapsible>
<mz-collapsible-item>
</mz-collapsible-item>
Expand All @@ -85,8 +104,6 @@ describe('MzCollapsibleComponent:view', () => {
nativeElement = fixture.nativeElement;
fixture.detectChanges();

forceSetTimeoutEnd();

const transcludeContentBody = collapsibleItem().querySelector('.collapsible-body');
const transcludeContentHeader = collapsibleItem().querySelector('.collapsible-header');

Expand Down
Loading

0 comments on commit 5f4dc62

Please sign in to comment.