Skip to content

Commit 61f7753

Browse files
committed
Introduce config to decouple parent and child category nodes
1 parent fee0fed commit 61f7753

File tree

6 files changed

+58
-25
lines changed

6 files changed

+58
-25
lines changed

src/demo/book/book.component.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ <h4>Example 1: Primary features</h4>
2828
hasCollapseExpand
2929
</label>
3030
</div>
31+
<div class="form-check">
32+
<label class="form-check-label">
33+
<input type="checkbox" class="form-check-input" [(ngModel)]="config.decoupleChildFromParent">
34+
decoupleChildFromParent
35+
</label>
36+
</div>
3137
<div class="form-inline">
3238
<div class="form-group">
3339
<label for="maxHeight">maxHeight</label>

src/demo/book/book.component.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,17 @@ import { BookService } from './book.service';
1212
export class BookComponent implements OnInit {
1313
items: TreeviewItem[];
1414
values: number[];
15-
config = TreeviewConfig.create({
16-
hasAllCheckBox: true,
17-
hasFilter: true,
18-
hasCollapseExpand: true,
19-
maxHeight: 400
20-
});
2115

2216
constructor(
23-
private service: BookService
24-
) { }
17+
private service: BookService,
18+
private config: TreeviewConfig
19+
) {
20+
config.hasAllCheckBox = true;
21+
config.hasFilter = true;
22+
config.hasCollapseExpand = true;
23+
config.maxHeight = 400;
24+
config.decoupleChildFromParent = false;
25+
}
2526

2627
ngOnInit() {
2728
this.items = this.service.getBooks();

src/lib/treeview-config.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ describe('Treeview-Config', () => {
77
expect(config.hasFilter).toBe(false);
88
expect(config.hasCollapseExpand).toBe(false);
99
expect(config.maxHeight).toBe(500);
10+
expect(config.decoupleChildFromParent).toBe(false);
1011
});
1112
});

src/lib/treeview-config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export class TreeviewConfig {
66
hasFilter = false;
77
hasCollapseExpand = false;
88
maxHeight = 500;
9+
decoupleChildFromParent = false;
910

1011
get hasDivider(): boolean {
1112
return this.hasFilter || this.hasAllCheckBox || this.hasCollapseExpand;
@@ -15,7 +16,8 @@ export class TreeviewConfig {
1516
hasAllCheckBox?: boolean,
1617
hasFilter?: boolean,
1718
hasCollapseExpand?: boolean,
18-
maxHeight?: number
19+
maxHeight?: number,
20+
decoupleChildFromParent?: boolean
1921
}): TreeviewConfig {
2022
const config = new TreeviewConfig();
2123
Object.assign(config, fields);

src/lib/treeview-item.component.spec.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { Component, DebugElement } from '@angular/core';
2-
import { TestBed, ComponentFixture, fakeAsync, tick, async } from '@angular/core/testing';
1+
import { Component, DebugElement, Injectable } from '@angular/core';
2+
import { TestBed, ComponentFixture, fakeAsync, tick, async, inject } from '@angular/core/testing';
33
import { BrowserModule, By } from '@angular/platform-browser';
44
import { FormsModule } from '@angular/forms';
55
import * as _ from 'lodash';
66
import { expect, createGenericTestComponent } from '../testing';
7+
import { TreeviewConfig } from './treeview-config';
78
import { TreeviewItemComponent } from './treeview-item.component';
89
import { TreeviewItem } from './treeview-item';
910
import { fakeItemTemplate } from './treeview-item-template.spec';
@@ -18,6 +19,11 @@ const fakeData: FakeData = {
1819
checkedChange(checked: boolean) { }
1920
};
2021

22+
@Injectable()
23+
export class MockTreeviewConfig extends TreeviewConfig {
24+
decoupleChildFromParent = true;
25+
}
26+
2127
const testTemplate = fakeItemTemplate
2228
+ '<ngx-treeview-item [item]="item" [template]="itemTemplate" (checkedChange)="checkedChange($event)"></ngx-treeview-item>';
2329

@@ -43,10 +49,17 @@ describe('TreeviewItemComponent', () => {
4349
declarations: [
4450
TestComponent,
4551
TreeviewItemComponent
46-
]
52+
],
53+
providers: [TreeviewConfig]
4754
});
4855
});
4956

57+
it('should initialize with default config', () => {
58+
const defaultConfig = new TreeviewConfig();
59+
const component = TestBed.createComponent(TreeviewItemComponent).componentInstance;
60+
expect(component.config).toEqual(defaultConfig);
61+
});
62+
5063
describe('item', () => {
5164
it('should not have element with class "treeview-item" if no item provided', () => {
5265
const fixture = createTestComponent('<ngx-treeview-item></ngx-treeview-item>');

src/lib/treeview-item.component.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
22
import * as _ from 'lodash';
33
import { TreeviewItem } from './treeview-item';
4+
import { TreeviewConfig } from './treeview-config';
45
import { TreeviewItemTemplateContext } from './treeview-item-template-context';
56

67
@Component({
@@ -12,36 +13,45 @@ export class TreeviewItemComponent {
1213
@Input() template: TemplateRef<TreeviewItemTemplateContext>;
1314
@Input() item: TreeviewItem;
1415
@Output() checkedChange = new EventEmitter<boolean>();
16+
config: TreeviewConfig;
1517

18+
constructor(
19+
defaultConfig: TreeviewConfig
20+
) {
21+
this.config = defaultConfig;
22+
}
1623
onCollapseExpand = () => {
1724
this.item.collapsed = !this.item.collapsed;
1825
}
1926

2027
onCheckedChange = () => {
2128
const checked = this.item.checked;
22-
if (!_.isNil(this.item.children)) {
29+
if (!_.isNil(this.item.children) && !this.config.decoupleChildFromParent) {
2330
this.item.children.forEach(child => child.setCheckedRecursive(checked));
2431
}
2532
this.checkedChange.emit(checked);
2633
}
2734

2835
onChildCheckedChange(child: TreeviewItem, checked: boolean) {
29-
let itemChecked: boolean = null;
30-
for (const childItem of this.item.children) {
36+
if (!this.config.decoupleChildFromParent) {
37+
let itemChecked: boolean = null;
38+
for (const childItem of this.item.children) {
39+
if (itemChecked === null) {
40+
itemChecked = childItem.checked;
41+
} else if (itemChecked !== childItem.checked) {
42+
itemChecked = undefined;
43+
break;
44+
}
45+
}
46+
3147
if (itemChecked === null) {
32-
itemChecked = childItem.checked;
33-
} else if (itemChecked !== childItem.checked) {
34-
itemChecked = undefined;
35-
break;
48+
itemChecked = false;
3649
}
37-
}
3850

39-
if (itemChecked === null) {
40-
itemChecked = false;
41-
}
51+
if (this.item.checked !== itemChecked) {
52+
this.item.checked = itemChecked;
53+
}
4254

43-
if (this.item.checked !== itemChecked) {
44-
this.item.checked = itemChecked;
4555
}
4656

4757
this.checkedChange.emit(checked);

0 commit comments

Comments
 (0)