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

Commit

Permalink
fix(fxLayoutGap): fxLayoutWrap to apply gap logic for reverse directi…
Browse files Browse the repository at this point in the history
…ons (#148)

*  `margin-right` be used with `fxLayout="row" fxLayoutWrap fxLayoutGap` combinations
*  `margin-bottom` be used with `fxLayout="column" fxLayoutWrap fxLayoutGap` combinations

fixes #108.
  • Loading branch information
ThomasBurleson authored and tinayuangao committed Feb 8, 2017
1 parent dad69fe commit 9f7137e
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 54 deletions.
115 changes: 82 additions & 33 deletions src/lib/flexbox/api/layout-gap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
import {Component, OnInit} from '@angular/core';
import {CommonModule} from '@angular/common';
import {TestBed, ComponentFixture} from '@angular/core/testing';
import {TestBed, ComponentFixture, async} from '@angular/core/testing';

import {BreakPointsProvider} from '../../media-query/breakpoints/break-points';
import {BreakPointRegistry} from '../../media-query/breakpoints/break-point-registry';
Expand Down Expand Up @@ -54,7 +54,10 @@ describe('layout-gap directive', () => {
fixture1.detectChanges();

const nodes = queryFor(fixture1, 'span');
expect(nodes[1].nativeElement).toHaveCssStyle({[marginKey]: margin});
const styles = {[marginKey]: margin};

expect(nodes[0].nativeElement).toHaveCssStyle(styles);
expect(nodes[1].nativeElement).not.toHaveCssStyle(styles);
}

describe('with static features', () => {
Expand All @@ -65,9 +68,7 @@ describe('layout-gap directive', () => {
<div fxFlex></div>
</div>
`;
expectDomForQuery(template, "[fxFlex]").not.toHaveCssStyle({
'margin-left': '13px;',
});
expectDomForQuery(template, "[fxFlex]").not.toHaveCssStyle({'margin-right': '13px;'});
});

it('should add gap styles to all children except the 1st child', () => {
Expand All @@ -83,9 +84,10 @@ describe('layout-gap directive', () => {

let nodes = queryFor(fixture, "[fxFlex]");
expect(nodes.length).toEqual(3);
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-left': '13px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-left': '13px'});
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-left': '13px'});
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-right': '13px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '13px'});
expect(nodes[2].nativeElement).not.toHaveCssStyle({'margin-right': '13px'});
expect(nodes[2].nativeElement).not.toHaveCssStyle({'margin-right': '0px'});
});

it('should add gap styles to dynamics rows EXCEPT first', () => {
Expand All @@ -100,15 +102,15 @@ describe('layout-gap directive', () => {

let nodes = queryFor(fixture, "[fxFlex]");
expect(nodes.length).toEqual(4);
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-left': '13px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-left': '13px'});
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-left': '13px'});
expect(nodes[3].nativeElement).toHaveCssStyle({'margin-left': '13px'});
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-right': '13px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '13px'});
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-right': '13px'});
expect(nodes[3].nativeElement).not.toHaveCssStyle({'margin-right': '13px'});
expect(nodes[3].nativeElement).not.toHaveCssStyle({'margin-right': '0px'});
});

it('should add update gap styles when row items are removed', () => {
let nodes,
template = `
it('should add update gap styles when row items are removed', async(() => {
let template = `
<div fxLayoutAlign="center center" fxLayoutGap="13px">
<div fxFlex *ngFor="let row of rows"></div>
</div>
Expand All @@ -117,22 +119,29 @@ describe('layout-gap directive', () => {
fixture.componentInstance.direction = "row";
fixture.detectChanges();

nodes = queryFor(fixture, "[fxFlex]");
let nodes = queryFor(fixture, "[fxFlex]");
expect(nodes.length).toEqual(4);

fixture.componentInstance.rows.shift();
fixture.componentInstance.rows = new Array(3);
fixture.detectChanges();

nodes = queryFor(fixture, "[fxFlex]");
expect(nodes.length).toEqual(3);
setTimeout(() => {
// Since the layoutGap directive detects the *ngFor changes by using a MutationObserver, the
// browser will take up some time, to actually announce the changes to the directive.
// (Kudos to @DevVersion)

expect(nodes[0].nativeElement).toHaveCssStyle({'margin-left': '0px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-left': '13px'});
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-left': '13px'});
});
nodes = queryFor(fixture, "[fxFlex]");
expect(nodes.length).toEqual(3);

expect(nodes[0].nativeElement).toHaveCssStyle({'margin-right': '13px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '13px'});
expect(nodes[2].nativeElement).not.toHaveCssStyle({'margin-right': '13px'});
});

}));

it('should apply margin-top for column layouts', () => {
verifyCorrectMargin('column', 'margin-top');
verifyCorrectMargin('column', 'margin-bottom');
});

it('should apply margin-right for row-reverse layouts', () => {
Expand All @@ -158,26 +167,26 @@ describe('layout-gap directive', () => {
fixture.detectChanges();
let nodes = queryFor(fixture, 'span');

expect(nodes[1].nativeElement).not.toHaveCssStyle({'margin-left': '8px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-top': '8px'});
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-right': '8px'});
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-bottom': '8px'});


// layout = column-reverse, use margin-bottom
instance.direction = "column-reverse";
fixture.detectChanges();
nodes = queryFor(fixture, 'span');

expect(nodes[1].nativeElement).not.toHaveCssStyle({'margin-top': '8px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-bottom': '8px'});
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-right': '8px'});
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-bottom': '8px'});


// layout = row-reverse, use margin-right
instance.direction = "row-reverse";
fixture.detectChanges();
nodes = queryFor(fixture, 'span');

expect(nodes[1].nativeElement).not.toHaveCssStyle({'margin-bottom': '8px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '8px'});
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-bottom': '8px'});
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-right': '8px'});
});

it('should recognize hidden elements when applying gaps', () => {
Expand All @@ -196,10 +205,50 @@ describe('layout-gap directive', () => {
let nodes = queryFor(fixture, '[fxFlex]');

expect(nodes.length).toEqual(3);
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-left': '0px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-left': '0px'});
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-left': '16px'});
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-right': '0px'});
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-right': '16px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '16px'});
expect(nodes[2].nativeElement).not.toHaveCssStyle({'margin-right': '16px'});

});

it('should adjust gaps based on layout-wrap presence', () => {
let styles = ['.col1 { display:none !important;'];
let template = `
<div class="container"
[fxLayout]="direction"
[fxLayoutGap]="gap"
fxLayoutWrap>
<div fxFlex class="col1">Div 1</div>
<div fxFlex class="col2">Div 2</div>
<div fxFlex class="col3">Div 2</div>
<div fxFlex class="col4">Div 3</div>
</div>
`;
fixture = createTestComponent(template, styles);
fixture.componentInstance.gap = '16px';
fixture.componentInstance.direction = 'row';
fixture.detectChanges();

let nodes = queryFor(fixture, '[fxFlex]');

expect(nodes.length).toEqual(4);
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-right': '16px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '16px'});
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-right': '16px'});
expect(nodes[3].nativeElement).not.toHaveCssStyle({'margin-right': '16px'});

fixture.componentInstance.gap = '8px';
fixture.componentInstance.direction = 'column';
fixture.detectChanges();

nodes = queryFor(fixture, '[fxFlex]');

expect(nodes.length).toEqual(4);
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-bottom': '8px'});
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-bottom': '8px'});
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-bottom': '8px'});
expect(nodes[3].nativeElement).not.toHaveCssStyle({'margin-bottom': '8px'});
});
});

Expand Down
46 changes: 25 additions & 21 deletions src/lib/flexbox/api/layout-gap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,15 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI
*/
private _watchContentChanges() {
let onMutationCallback = (mutations) => {
// update gap styles only for 'addedNodes' events
mutations
.filter((it: MutationRecord) => it.addedNodes && it.addedNodes.length)
.map(() => this._updateWithValue());
let validatedChanges = (it: MutationRecord) => {
return (it.addedNodes && it.addedNodes.length) ||
(it.removedNodes && it.removedNodes.length);
};

// update gap styles only for child 'added' or 'removed' events
if (mutations.filter(validatedChanges).length) {
this._updateWithValue();
}
};

this._observer = new MutationObserver(onMutationCallback);
Expand Down Expand Up @@ -173,23 +178,28 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI

// Gather all non-hidden Element nodes
let items = this.childrenNodes
.filter(el => (el.nodeType === 1)) // only Element types
.filter(el => this._getDisplayStyle(el) != "none");
.filter(el => (el.nodeType === 1)) // only Element types
.filter(el => this._getDisplayStyle(el) != "none");
let numItems = items.length;

// Reset 1st child element to 0px gap
let skipped = items.filter((el, j) => j == 0);
this._applyStyleToElements(this._buildCSS(0), skipped);
if (numItems > 1) {
let lastItem = items[numItems - 1];

// For each `element` child, set the padding styles...
items = items.filter((el, j) => j > 0); // skip first element since gaps are needed
this._applyStyleToElements(this._buildCSS(value), items);
// For each `element` children EXCEPT the last,
// set the margin right/bottom styles...
items = items.filter((el, j) => j < numItems - 1);
this._applyStyleToElements(this._buildCSS(value), items);

// Clear all gaps for all visible elements
this._applyStyleToElements(this._buildCSS(), [lastItem]);
}
}

/**
* Prepare margin CSS, remove any previous explicitly
* assigned margin assignments
*/
private _buildCSS(value) {
private _buildCSS(value: any = null) {
let key, margins = {
'margin-left': null,
'margin-right': null,
Expand All @@ -199,19 +209,13 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI

switch (this._layout) {
case 'column':
key = 'margin-top';
break;
case 'column-reverse':
key = 'margin-bottom';
break;
case 'row-reverse':
key = 'margin-right';
break;
case "row" :
key = 'margin-left';
break;
case 'row-reverse':
default :
key = 'margin-left';
key = 'margin-right';
break;
}
margins[key] = value;
Expand Down

0 comments on commit 9f7137e

Please sign in to comment.