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

Commit 9f7137e

Browse files
ThomasBurlesontinayuangao
authored andcommitted
fix(fxLayoutGap): fxLayoutWrap to apply gap logic for reverse directions (#148)
* `margin-right` be used with `fxLayout="row" fxLayoutWrap fxLayoutGap` combinations * `margin-bottom` be used with `fxLayout="column" fxLayoutWrap fxLayoutGap` combinations fixes #108.
1 parent dad69fe commit 9f7137e

File tree

2 files changed

+107
-54
lines changed

2 files changed

+107
-54
lines changed

src/lib/flexbox/api/layout-gap.spec.ts

Lines changed: 82 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
import {Component, OnInit} from '@angular/core';
99
import {CommonModule} from '@angular/common';
10-
import {TestBed, ComponentFixture} from '@angular/core/testing';
10+
import {TestBed, ComponentFixture, async} from '@angular/core/testing';
1111

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

5656
const nodes = queryFor(fixture1, 'span');
57-
expect(nodes[1].nativeElement).toHaveCssStyle({[marginKey]: margin});
57+
const styles = {[marginKey]: margin};
58+
59+
expect(nodes[0].nativeElement).toHaveCssStyle(styles);
60+
expect(nodes[1].nativeElement).not.toHaveCssStyle(styles);
5861
}
5962

6063
describe('with static features', () => {
@@ -65,9 +68,7 @@ describe('layout-gap directive', () => {
6568
<div fxFlex></div>
6669
</div>
6770
`;
68-
expectDomForQuery(template, "[fxFlex]").not.toHaveCssStyle({
69-
'margin-left': '13px;',
70-
});
71+
expectDomForQuery(template, "[fxFlex]").not.toHaveCssStyle({'margin-right': '13px;'});
7172
});
7273

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

8485
let nodes = queryFor(fixture, "[fxFlex]");
8586
expect(nodes.length).toEqual(3);
86-
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-left': '13px'});
87-
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-left': '13px'});
88-
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-left': '13px'});
87+
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-right': '13px'});
88+
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '13px'});
89+
expect(nodes[2].nativeElement).not.toHaveCssStyle({'margin-right': '13px'});
90+
expect(nodes[2].nativeElement).not.toHaveCssStyle({'margin-right': '0px'});
8991
});
9092

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

101103
let nodes = queryFor(fixture, "[fxFlex]");
102104
expect(nodes.length).toEqual(4);
103-
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-left': '13px'});
104-
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-left': '13px'});
105-
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-left': '13px'});
106-
expect(nodes[3].nativeElement).toHaveCssStyle({'margin-left': '13px'});
105+
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-right': '13px'});
106+
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '13px'});
107+
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-right': '13px'});
108+
expect(nodes[3].nativeElement).not.toHaveCssStyle({'margin-right': '13px'});
109+
expect(nodes[3].nativeElement).not.toHaveCssStyle({'margin-right': '0px'});
107110
});
108111

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

120-
nodes = queryFor(fixture, "[fxFlex]");
122+
let nodes = queryFor(fixture, "[fxFlex]");
121123
expect(nodes.length).toEqual(4);
122124

123-
fixture.componentInstance.rows.shift();
125+
fixture.componentInstance.rows = new Array(3);
124126
fixture.detectChanges();
125127

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

129-
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-left': '0px'});
130-
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-left': '13px'});
131-
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-left': '13px'});
132-
});
133+
nodes = queryFor(fixture, "[fxFlex]");
134+
expect(nodes.length).toEqual(3);
135+
136+
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-right': '13px'});
137+
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '13px'});
138+
expect(nodes[2].nativeElement).not.toHaveCssStyle({'margin-right': '13px'});
139+
});
140+
141+
}));
133142

134143
it('should apply margin-top for column layouts', () => {
135-
verifyCorrectMargin('column', 'margin-top');
144+
verifyCorrectMargin('column', 'margin-bottom');
136145
});
137146

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

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

164173

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

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

173182

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

179-
expect(nodes[1].nativeElement).not.toHaveCssStyle({'margin-bottom': '8px'});
180-
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '8px'});
188+
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-bottom': '8px'});
189+
expect(nodes[0].nativeElement).toHaveCssStyle({'margin-right': '8px'});
181190
});
182191

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

198207
expect(nodes.length).toEqual(3);
199-
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-left': '0px'});
200-
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-left': '0px'});
201-
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-left': '16px'});
208+
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-right': '0px'});
209+
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-right': '16px'});
210+
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '16px'});
211+
expect(nodes[2].nativeElement).not.toHaveCssStyle({'margin-right': '16px'});
212+
213+
});
202214

215+
it('should adjust gaps based on layout-wrap presence', () => {
216+
let styles = ['.col1 { display:none !important;'];
217+
let template = `
218+
<div class="container"
219+
[fxLayout]="direction"
220+
[fxLayoutGap]="gap"
221+
fxLayoutWrap>
222+
<div fxFlex class="col1">Div 1</div>
223+
<div fxFlex class="col2">Div 2</div>
224+
<div fxFlex class="col3">Div 2</div>
225+
<div fxFlex class="col4">Div 3</div>
226+
</div>
227+
`;
228+
fixture = createTestComponent(template, styles);
229+
fixture.componentInstance.gap = '16px';
230+
fixture.componentInstance.direction = 'row';
231+
fixture.detectChanges();
232+
233+
let nodes = queryFor(fixture, '[fxFlex]');
234+
235+
expect(nodes.length).toEqual(4);
236+
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-right': '16px'});
237+
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-right': '16px'});
238+
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-right': '16px'});
239+
expect(nodes[3].nativeElement).not.toHaveCssStyle({'margin-right': '16px'});
240+
241+
fixture.componentInstance.gap = '8px';
242+
fixture.componentInstance.direction = 'column';
243+
fixture.detectChanges();
244+
245+
nodes = queryFor(fixture, '[fxFlex]');
246+
247+
expect(nodes.length).toEqual(4);
248+
expect(nodes[0].nativeElement).not.toHaveCssStyle({'margin-bottom': '8px'});
249+
expect(nodes[1].nativeElement).toHaveCssStyle({'margin-bottom': '8px'});
250+
expect(nodes[2].nativeElement).toHaveCssStyle({'margin-bottom': '8px'});
251+
expect(nodes[3].nativeElement).not.toHaveCssStyle({'margin-bottom': '8px'});
203252
});
204253
});
205254

src/lib/flexbox/api/layout-gap.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,15 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI
141141
*/
142142
private _watchContentChanges() {
143143
let onMutationCallback = (mutations) => {
144-
// update gap styles only for 'addedNodes' events
145-
mutations
146-
.filter((it: MutationRecord) => it.addedNodes && it.addedNodes.length)
147-
.map(() => this._updateWithValue());
144+
let validatedChanges = (it: MutationRecord) => {
145+
return (it.addedNodes && it.addedNodes.length) ||
146+
(it.removedNodes && it.removedNodes.length);
147+
};
148+
149+
// update gap styles only for child 'added' or 'removed' events
150+
if (mutations.filter(validatedChanges).length) {
151+
this._updateWithValue();
152+
}
148153
};
149154

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

174179
// Gather all non-hidden Element nodes
175180
let items = this.childrenNodes
176-
.filter(el => (el.nodeType === 1)) // only Element types
177-
.filter(el => this._getDisplayStyle(el) != "none");
181+
.filter(el => (el.nodeType === 1)) // only Element types
182+
.filter(el => this._getDisplayStyle(el) != "none");
183+
let numItems = items.length;
178184

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

183-
// For each `element` child, set the padding styles...
184-
items = items.filter((el, j) => j > 0); // skip first element since gaps are needed
185-
this._applyStyleToElements(this._buildCSS(value), items);
188+
// For each `element` children EXCEPT the last,
189+
// set the margin right/bottom styles...
190+
items = items.filter((el, j) => j < numItems - 1);
191+
this._applyStyleToElements(this._buildCSS(value), items);
192+
193+
// Clear all gaps for all visible elements
194+
this._applyStyleToElements(this._buildCSS(), [lastItem]);
195+
}
186196
}
187197

188198
/**
189199
* Prepare margin CSS, remove any previous explicitly
190200
* assigned margin assignments
191201
*/
192-
private _buildCSS(value) {
202+
private _buildCSS(value: any = null) {
193203
let key, margins = {
194204
'margin-left': null,
195205
'margin-right': null,
@@ -199,19 +209,13 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI
199209

200210
switch (this._layout) {
201211
case 'column':
202-
key = 'margin-top';
203-
break;
204212
case 'column-reverse':
205213
key = 'margin-bottom';
206214
break;
207-
case 'row-reverse':
208-
key = 'margin-right';
209-
break;
210215
case "row" :
211-
key = 'margin-left';
212-
break;
216+
case 'row-reverse':
213217
default :
214-
key = 'margin-left';
218+
key = 'margin-right';
215219
break;
216220
}
217221
margins[key] = value;

0 commit comments

Comments
 (0)