1 | # :herb: ng2-tree
|
2 |
|
3 | [![npm](https://img.shields.io/npm/v/ng2-tree.svg?style=flat-square)](https://www.npmjs.com/package/ng2-tree)
|
4 | [![Travis](https://img.shields.io/travis/valor-software/ng2-tree.svg?style=flat-square)](https://travis-ci.org/valor-software/ng2-tree)
|
5 | [![Codecov](https://img.shields.io/codecov/c/github/valor-software/ng2-tree.svg?style=flat-square)](https://codecov.io/github/valor-software/ng2-tree)
|
6 |
|
7 |
|
8 |
|
9 | * [:clapper: Usage](#clapper-usage)
|
10 | * [:eyes: Demo](#eyes-demo)
|
11 | * [:wrench: API](#wrench-api)
|
12 | * [tree](#tree)
|
13 | * [[tree]](#tree)
|
14 | * [Load children asynchronously](#load-children-asynchronously)
|
15 | * [Load children using ngrx (or any redux-like library)](#load-children-using-ngrx-or-any-redux-like-library)
|
16 | * [Configure node via TreeModelSettings](#configure-node-via-treemodelsettings)
|
17 | * [[settings]](#settings)
|
18 | * [`Tree` class](#tree-class)
|
19 | * [events (nodeMoved, nodeSelected, nodeRenamed, nodeRemoved, nodeCreated, nodeExpanded, nodeCollapsed)](#events-nodemoved-nodeselected-noderenamed-noderemoved-nodecreated-nodeexpanded-nodecollapsed)
|
20 | * [NodeSelectedEvent](#nodeselectedevent)
|
21 | * [NodeMovedEvent](#nodemovedevent)
|
22 | * [NodeRemovedEvent](#noderemovedevent)
|
23 | * [NodeCreatedEvent](#nodecreatedevent)
|
24 | * [NodeRenamedEvent](#noderenamedevent)
|
25 | * [NodeExpandedEvent](#nodeexpandedevent)
|
26 | * [NodeCollapsedEvent](#nodecollapsedevent)
|
27 | * [LoadNextLevelEvent](#loadnextlevelevent)
|
28 | * [:gun: Controller](#gun-controller)
|
29 | * [select - selects a node](#select---selects-a-node)
|
30 | * [isSelected - checks whether a node is selected](#isselected---checks-whether-a-node-is-selected)
|
31 | * [collapse - collapses a node](#collapse---collapses-a-node)
|
32 | * [isCollapsed - check whether a node is collapsed](#iscollapsed---check-whether-a-node-is-collapsed)
|
33 | * [expand - expands a node](#expand---expands-a-node)
|
34 | * [isExpanded - checks whether a node is expanded](#isexpanded---checks-whether-a-node-is-expanded)
|
35 | * [toTreeModel - converts a tree to a TreeModel instance](#totreemodel---converts-a-tree-to-a-treemodel-instance)
|
36 | * [rename - renames a node (changes its value underneath)](#rename---renames-a-node-changes-its-value-underneath)
|
37 | * [startRenaming - changes the node template so that text input appears and lets a user type a new name](#startrenaming---changes-the-node-template-so-that-text-input-appears-and-lets-a-user-type-a-new-name)
|
38 | * [remove - removes a node from the tree](#remove---removes-a-node-from-the-tree)
|
39 | * [addChild - creates a new child node](#addchild---creates-a-new-child-node)
|
40 | * [changeNodeId - changes node's id](#changenodeid---changes-nodes-id)
|
41 | * [reloadChildren - loads async children once more](#reloadchildren---loads-async-children-once-more)
|
42 | * [setChildren - changes children of a node;](#setchildren---changes-children-of-a-node)
|
43 | * [SystemJS](#systemjs)
|
44 | * [Changes that should be taken into account in order to migrate from **ng2-tree V1** to **ng2-tree V2**](#changes-that-should-be-taken-into-account-in-order-to-migrate-from-__ng2-tree-v1__-to-__ng2-tree-v2__)
|
45 | * [:bulb: Want to help?](#bulb-want-to-help)
|
46 |
|
47 |
|
48 |
|
49 | ## :clapper: Usage
|
50 |
|
51 | Ok, let's start with an installation - all you need to do is:
|
52 |
|
53 | `npm install --save ng2-tree`
|
54 |
|
55 | Now when you have `ng2-tree` installed, you are in a few steps from having tree in your application:
|
56 |
|
57 | 1. Add the `TreeModule` to your application's module `imports` section:
|
58 |
|
59 | ```typescript
|
60 | import { NgModule } from '@angular/core';
|
61 | import { AppComponent } from './app.component';
|
62 | import { BrowserModule } from '@angular/platform-browser';
|
63 | import { TreeModule } from 'ng2-tree';
|
64 |
|
65 | @NgModule({
|
66 | declarations: [MyComponent],
|
67 | imports: [BrowserModule, TreeModule],
|
68 | bootstrap: [MyComponent]
|
69 | })
|
70 | export class MyModule {}
|
71 | ```
|
72 |
|
73 | 2. As soon as the previous step is done we need to give ng2-tree a model to render - this can be accomplished by populating its `[tree]` attribute with an object that conforms to the `TreeModel` interface (see [API](#wrench-api)):
|
74 |
|
75 | ```typescript
|
76 | // 1 - import required classes and interfaces
|
77 | import { TreeModel } from 'ng2-tree';
|
78 |
|
79 | @Component({
|
80 | selector: 'myComp',
|
81 | // 2 - set [tree] attribute to tree object
|
82 | template: `<tree [tree]="tree"></tree>`
|
83 | })
|
84 | class MyComponent {
|
85 | // 3 - make sure that tree object conforms to the TreeModel interface
|
86 | public tree: TreeModel = {
|
87 | value: 'Programming languages by programming paradigm',
|
88 | children: [
|
89 | {
|
90 | value: 'Object-oriented programming',
|
91 | children: [{ value: 'Java' }, { value: 'C++' }, { value: 'C#' }]
|
92 | },
|
93 | {
|
94 | value: 'Prototype-based programming',
|
95 | children: [{ value: 'JavaScript' }, { value: 'CoffeeScript' }, { value: 'Lua' }]
|
96 | }
|
97 | ]
|
98 | };
|
99 | }
|
100 | ```
|
101 |
|
102 | 3. Apart from that, in order to have usable tree in the browser, you need to add **ng2-tree styles** which you can find in your `node_modules/ng2-tree/styles.css`
|
103 |
|
104 | In Angular 2/4 cli projects, modify **.angular-cli.json** as below:
|
105 |
|
106 | ```typescript
|
107 | "styles": [
|
108 | "styles.css",
|
109 | "../node_modules/ng2-tree/styles.css"
|
110 | ],
|
111 | ```
|
112 |
|
113 | 4. And finally, I suppose, you'd want to listen to events generated by ng2-tree (for a full list of supported events look at the [API](#wrench-api)). No problem, this is also easy to do - for example let's add a listener for `node was selected` kind of events:
|
114 |
|
115 | ```typescript
|
116 | // 1 - import required classes and interfaces
|
117 | import { TreeModel, NodeEvent } from 'ng2-tree';
|
118 |
|
119 | @Component({
|
120 | selector: 'myComp',
|
121 | // 2 - listent for nodeSelected events and handle them
|
122 | template: `<tree [tree]="tree" (nodeSelected)="logEvent($event)"></tree>`
|
123 | })
|
124 | class MyComponent {
|
125 | public tree: TreeModel = { ... };
|
126 |
|
127 | // 3 - print caught event to the console
|
128 | public logEvent(e: NodeEvent): void {
|
129 | console.log(e);
|
130 | }
|
131 | }
|
132 | ```
|
133 |
|
134 | Voila! That's pretty much it - enjoy :blush:
|
135 |
|
136 | ## :eyes: Demo
|
137 |
|
138 | Feel free to examine the [demo](https://valor-software.github.io/ng2-tree/index.html) and its [sources](src/demo) to find out how things are wired.
|
139 | Also, there is [another demo built with Angular CLI](https://github.com/rychkog/ng2-tree-demo).
|
140 |
|
141 | ## :wrench: API
|
142 |
|
143 | Here is the fully stuffed _tree_ tag that you can use in your templates:
|
144 |
|
145 | ```html
|
146 | <tree
|
147 | [tree]="tree"
|
148 | [settings]="settings"
|
149 | (nodeRemoved)="handleRemoved($event)"
|
150 | (nodeRenamed)="handleRenamed($event)"
|
151 | (nodeSelected)="handleSelected($event)"
|
152 | (nodeMoved)="handleMoved($event)"
|
153 | (nodeCreated)="handleCreated($event)"
|
154 | (nodeExpanded)="handleExpanded($event)"
|
155 | (nodeCollapsed)="handleCollapsed($event)"
|
156 | (loadNextLevel)="handleNextLevel($event)">
|
157 | </tree>
|
158 | ```
|
159 |
|
160 | Let's go through every element of this structure one by one.
|
161 |
|
162 | ### tree
|
163 |
|
164 | `tree` is the selector for `TreeComponent` which is bundled into `TreeModule`:
|
165 |
|
166 | ### [tree]
|
167 |
|
168 | `tree` has a `[tree]` attribute which needs to be populated with an object implementing `TreeModel` interface. You can import this interface like below:
|
169 |
|
170 | ```typescript
|
171 | import { TreeModel } from 'ng2-tree';
|
172 | ```
|
173 |
|
174 | Here is the definition of the `TreeModel` interface:
|
175 |
|
176 | ```typescript
|
177 | interface TreeModel {
|
178 | value: string | RenamableNode;
|
179 | id: string | number;
|
180 | children?: Array<TreeModel>;
|
181 | loadChildren?: ChildrenLoadingFunction;
|
182 | settings?: TreeModelSettings;
|
183 | }
|
184 | ```
|
185 |
|
186 | As you can see - an object that conforms to this interface has a recursive nature, an example can be seen below:
|
187 |
|
188 | ```typescript
|
189 | {
|
190 | value: 'Programming languages by programming paradigm',
|
191 | children: [
|
192 | {
|
193 | value: 'Object-oriented programming',
|
194 | children: [
|
195 | {value: 'Java'},
|
196 | {value: 'C++'},
|
197 | {value: 'C#'}
|
198 | ]
|
199 | },
|
200 | {
|
201 | value: 'Prototype-based programming',
|
202 | children: [
|
203 | {value: 'JavaScript'},
|
204 | {value: 'CoffeeScript'},
|
205 | {value: 'Lua'}
|
206 | ]
|
207 | }
|
208 | ]
|
209 | }
|
210 | ```
|
211 |
|
212 | Property `value` can be of type `string` or `RenamableNode`.
|
213 | `RenamableNode` gives you an additional control over the way node is renamed and rendered (by rendered I mean its text representation). Here is the definition of the `RenamableNode` interface:
|
214 |
|
215 | ```typescript
|
216 | interface RenamableNode {
|
217 | // This method will be invoked in order to apply new value to this kind of node
|
218 | setName(name: string): void;
|
219 |
|
220 | // This method will be invoked in order to get a text for rendering as a node value
|
221 | toString(): string;
|
222 | }
|
223 | ```
|
224 |
|
225 | Here is an example of such a node in the `TreeModel` object:
|
226 |
|
227 | ```typescript
|
228 | {
|
229 | value: 'Programming languages by programming paradigm',
|
230 | children: [
|
231 | {
|
232 | value: 'Object-oriented programming',
|
233 | children: [
|
234 | {
|
235 | // I am a RenamableNode. Yeah, that's me :)
|
236 | value: <RenamableNode>{
|
237 | name: 'Java',
|
238 | setName(name: string): void {
|
239 | this.name = name;
|
240 | },
|
241 | toString(): string {
|
242 | return this.name;
|
243 | }
|
244 | }
|
245 | },
|
246 | {value: 'C++'},
|
247 | {value: 'C#'}
|
248 | ]
|
249 | },
|
250 | {
|
251 | value: 'Prototype-based programming',
|
252 | loadChildren: (callback) => {
|
253 | setTimeout(() => {
|
254 | callback([
|
255 | {value: 'JavaScript'},
|
256 | {value: 'CoffeeScript'},
|
257 | {value: 'TypeScript'}
|
258 | ]);
|
259 | }, 5000);
|
260 | }
|
261 | }
|
262 | ]
|
263 | };
|
264 | ```
|
265 |
|
266 | #### Load children asynchronously
|
267 |
|
268 | Another worth noting thing is `loadChildren`. This function on `TreeModel` allows you to load its **children asynchronously**.
|
269 |
|
270 | ```typescript
|
271 | {
|
272 | value: 'Prototype-based programming',
|
273 | loadChildren: (callback) => {
|
274 | setTimeout(() => {
|
275 | callback([
|
276 | {value: 'JavaScript'},
|
277 | {value: 'CoffeeScript'},
|
278 | {value: 'TypeScript'}
|
279 | ]);
|
280 | }, 5000);
|
281 | }
|
282 | }
|
283 | ```
|
284 |
|
285 | Node that defines this function is collapsed by default. At the moment of clicking 'Expand' arrow, it starts loading its children by calling given function.
|
286 | If `loadChildren` function is given to the node - `children` property is ignored. For more details - have a look at the [Demo](#eyes-demo).
|
287 |
|
288 | #### Load children using ngrx (or any redux-like library)
|
289 |
|
290 | You can also load children by changing the tree state using ngrx.
|
291 | The tree can emit an appropriate event notifying you to dispatch a new action in order to load the branch's children.
|
292 |
|
293 | To enable this feature you should set the `TreeModel.emitLoadNextLevel` property to true:
|
294 |
|
295 | ```typscript
|
296 | const model: TreeModel = {
|
297 | emitLoadNextLevel : true
|
298 | }
|
299 | ```
|
300 |
|
301 | Now on the first time the node is expanded a **LoadNextLevelEvent** will be fired (via the **loadNextLevel** EventEmitter in the tree) containing the node that requested a next level (its children) loading.
|
302 |
|
303 | In your code make sure you change the tree state and add the children to the model.
|
304 |
|
305 | In addition the regular **NodeExpanded** event will be fired.
|
306 |
|
307 | **NOTICE**: if both `emitLoadNextLevel` and `loadChildren` are provided, the tree will ignore the `emitLoadNextLevel` and the `LoadNextLevelEvent` won't be fired.
|
308 |
|
309 | #### Configure node via TreeModelSettings
|
310 |
|
311 | Apart from that `TreeModel` interface has an optional field called `settings` of type `TreeModelSettings`.
|
312 |
|
313 | Here is an example of its usage:
|
314 |
|
315 | ```typescript
|
316 | {
|
317 | value: 'Prototype-based programming',
|
318 | settings: {
|
319 | 'static': true,
|
320 | 'rightMenu': true,
|
321 | 'leftMenu': true,
|
322 | 'cssClasses': {
|
323 | 'expanded': 'fa fa-caret-down fa-lg',
|
324 | 'collapsed': 'fa fa-caret-right fa-lg',
|
325 | 'leaf': 'fa fa-lg',
|
326 | 'empty': 'fa fa-caret-right disabled'
|
327 | },
|
328 | 'templates': {
|
329 | 'node': '<i class="fa fa-folder-o fa-lg"></i>',
|
330 | 'leaf': '<i class="fa fa-file-o fa-lg"></i>',
|
331 | 'leftMenu': '<i class="fa fa-navicon fa-lg"></i>'
|
332 | },
|
333 | 'menuItems': [
|
334 | { action: NodeMenuItemAction.Custom, name: 'Foo', cssClass: 'fa fa-arrow-right' },
|
335 | { action: NodeMenuItemAction.Custom, name: 'Bar', cssClass: 'fa fa-arrow-right' },
|
336 | { action: NodeMenuItemAction.Custom, name: 'Baz', cssClass: 'fa fa-arrow-right'}
|
337 | ]
|
338 | }
|
339 | },
|
340 | children: [
|
341 | {value: 'JavaScript'},
|
342 | {value: 'CoffeeScript'},
|
343 | {value: 'Lua'}
|
344 | ]
|
345 | }
|
346 | ```
|
347 |
|
348 | * `static` - Boolean - This option makes it impossible to drag a tree or modify it in a some way, though you still can select nodes in the static tree and appropriate events will be generated.
|
349 | * `isCollapsedOnInit` - Boolean - This option makes a tree to be collapsed on first load (this option cascades to its children).
|
350 | * `rightMenu` - Boolean - This option allows you to activate (true, by default) or deactivate (false) right menu when clicking with right button of a mouse.
|
351 | * `leftMenu` - Boolean - This option allows you to activate (true) or deactivate (false, by default) left menu.
|
352 | * `cssClasses` - Object:
|
353 | * `expanded` - String - It specifies a css class (or classes) for an item which represents expanded state of a node. The item is clickable and it transitions the node to the collapsed state
|
354 | * `collapsed` - String - It specifies a css class (or classes) for an item which represents collapsed state of a node. The item is clickable and it transitions the node to the expanded state
|
355 | * `leaf` - String - It specifies a css class (or classes) for an item which represents a node without an option to expand or collapse - in other words: a leaf node.
|
356 | * `empty` - String - Node is considered empty when it has no children. Once this condition is satisfied - appropriate css class will be applied to the node.
|
357 | * `templates` - Object:
|
358 | * `node` - String - It specifies a html template which will be included to the left of the node's value.
|
359 | * `leaf` - String - It specifies a html template which will be included to the left of the leaf's value.
|
360 | * `leftMenu` - String - It specifies a html template to the right of the node's value. This template becomes clickable and shows a menu on node's click.
|
361 | * `menuItems` - here you can specify your custom menu items. You should feed an array of NodeMenuItem instances to this setting. Once done - setup a subscription to `MenuItemSelectedEvent`s by listening to `(menuItemSelected)="onMenuItemSelected($event)"` on the tree.
|
362 |
|
363 | All options that are defined on a `parent` are automatically applied to children. If you want you can override them by `settings` of the child node.
|
364 |
|
365 | ### [settings]
|
366 |
|
367 | Object that should be passed to `[settings]` must be of type [`Ng2TreeSettings`](src/tree.types.ts). This attribute is **optional**. Right now only one setting is available in there - `rootIsVisible`. This setting allows you to make a root node of the tree _invisible_:
|
368 |
|
369 | ```typescript
|
370 | const treeSettings: Ng2TreeSettings = {
|
371 | rootIsVisible: false
|
372 | };
|
373 | ```
|
374 |
|
375 | By default `rootIsVisible` equals to `true`
|
376 |
|
377 | ### `Tree` class
|
378 |
|
379 | Also in the next section, you'll be reading about events generated by the `ng2-tree`. And here [Tree](src/tree.ts) class comes in handy for us, because its instances propagated with event objects. Under the hood, `ng2-tree` wraps a `TreeModel` provided by the user in `Tree`. And `Tree` in turn has lots of useful methods and properties (like `parent`, `hasChild()`, `isRoot()` etc.)
|
380 |
|
381 | ### events (nodeMoved, nodeSelected, nodeRenamed, nodeRemoved, nodeCreated, nodeExpanded, nodeCollapsed)
|
382 |
|
383 | `NodeEvent` is the root of the tree events' hierarchy. It defines property `node` that contains a receiver of the event action (`node` is an instance of the `Tree` class).
|
384 |
|
385 | `NodeDestructiveEvent` is the parent for all events that cause changes to the structure of the tree or to the node's value.
|
386 |
|
387 | #### NodeSelectedEvent
|
388 |
|
389 | You can subscribe to the `NodeSelectedEvent` by attaching listener to the `(nodeSelected)` attribute
|
390 |
|
391 | ```html
|
392 | <tree
|
393 | [tree]="tree"
|
394 | (nodeSelected)="handleSelected($event)">
|
395 | </tree>
|
396 | ```
|
397 |
|
398 | `NodeSelectedEvent` has just one property `node` which contains a `Tree` object representing selected node.
|
399 |
|
400 | ```typescript
|
401 | {node: <Tree>{...}}
|
402 | ```
|
403 |
|
404 | #### NodeMovedEvent
|
405 |
|
406 | You can subscribe to `NodeMovedEvent` by attaching listener to `(nodeMoved)` attribute
|
407 |
|
408 | ```html
|
409 | <tree
|
410 | [tree]="tree"
|
411 | (nodeMoved)="handleMoved($event)">
|
412 | </tree>
|
413 | ```
|
414 |
|
415 | `NodeMovedEvent` has two properties `node` and `previousParent` both of which contain `Tree` objects:
|
416 |
|
417 | * `node` contains a moved node;
|
418 | * `previousParent` contains a previous parent of the moved node;
|
419 |
|
420 | ```typescript
|
421 | {node: <Tree>{...}, previousParent: <Tree>{...}}
|
422 | ```
|
423 |
|
424 | #### NodeRemovedEvent
|
425 |
|
426 | You can subscribe to `NodeRemovedEvent` by attaching listener to `(nodeRemoved)` attribute
|
427 |
|
428 | ```html
|
429 | <tree
|
430 | [tree]="tree"
|
431 | (nodeRemoved)="handleRemoved($event)">
|
432 | </tree>
|
433 | ```
|
434 |
|
435 | `NodeRemovedEvent` has a `node` property, which contains removed node (of type `Tree`).
|
436 |
|
437 | ```typescript
|
438 | {node: <Tree>{...}}
|
439 | ```
|
440 |
|
441 | #### NodeCreatedEvent
|
442 |
|
443 | You can subscribe to `NodeCreatedEvent` by attaching listener to `(nodeCreated)` attribute
|
444 |
|
445 | ```html
|
446 | <tree
|
447 | [tree]="tree"
|
448 | (nodeCreated)="handleCreated($event)">
|
449 | </tree>
|
450 | ```
|
451 |
|
452 | `NodeCreatedEvent` has a `node` property of type `Tree`, which contains a created node and a `controller` property, which will give you access to node's controller.
|
453 |
|
454 | ```typescript
|
455 | {node: <Tree>{...}}
|
456 | ```
|
457 |
|
458 | #### NodeRenamedEvent
|
459 |
|
460 | You can subscribe to `NodeRenamedEvent` by attaching listener to `(nodeRenamed)` attribute
|
461 |
|
462 | ```html
|
463 | <tree
|
464 | [tree]="tree"
|
465 | (nodeRenamed)="handleRenamed($event)">
|
466 | </tree>
|
467 | ```
|
468 |
|
469 | `NodeRenamedEvent` has three properties:
|
470 |
|
471 | * `node` contains a node that was renamed ( an instance of `Tree`).
|
472 | * `oldValue` contains a value, that node used to have (it might be `string` or `RenamableNode`)
|
473 | * `newValue` contains a new value of the node (it might be `string` or `RenamableNode`)
|
474 |
|
475 | ```typescript
|
476 | {
|
477 | node: <Tree>{...},
|
478 | oldValue: <string|RenamableNode>{...},
|
479 | newValue: <string|RenamableNode>{...}
|
480 | }
|
481 | ```
|
482 |
|
483 | #### NodeExpandedEvent
|
484 |
|
485 | You can subscribe to `NodeExpandedEvent` by attaching listener to `(nodeExpanded)` attribute, this event wont fire on initial expansion
|
486 |
|
487 | ```html
|
488 | <tree
|
489 | [tree]="tree"
|
490 | (nodeExpanded)="handleExpanded($event)">
|
491 | </tree>
|
492 | ```
|
493 |
|
494 | `NodeExpandedEvent` has a `node` property of type `Tree`, which contains an expanded node.
|
495 |
|
496 | ```typescript
|
497 | {node: <Tree>{...}}
|
498 | ```
|
499 |
|
500 | #### NodeCollapsedEvent
|
501 |
|
502 | You can subscribe to `NodeCollapsedEvent` by attaching listener to `(nodeCollapsed)` attribute
|
503 |
|
504 | ```html
|
505 | <tree
|
506 | [tree]="tree"
|
507 | (nodeCollapsed)="handleCollapsed($event)">
|
508 | </tree>
|
509 | ```
|
510 |
|
511 | `NodeCollapsedEvent` has a `node` property of type `Tree`, which contains a collapsed node.
|
512 |
|
513 | ```typescript
|
514 | {node: <Tree>{...}}
|
515 | ```
|
516 |
|
517 | #### LoadNextLevelEvent
|
518 |
|
519 | You can subscribe to `LoadNextLevelEvent` by attaching a listener to `(loadNextLevel)` attribute.
|
520 | Relevant for loading children via ngrx (or any redux-inspired library).
|
521 |
|
522 | ```html
|
523 | <tree
|
524 | [tree]="tree"
|
525 | (loadNextLevel)="handleNextLevel($event)">
|
526 | </tree>
|
527 | ```
|
528 |
|
529 | `LoadNextLevelEvent` has a `node` property of the type `Tree`, which contains a node for which next level (its children) should be loaded.
|
530 |
|
531 | ```typescript
|
532 | {node: <Tree>{...}}
|
533 | ```
|
534 |
|
535 | ## :gun: Controller
|
536 |
|
537 | First of all you should know how to get a controller of a particular node. You can get a controller of a node only if you set an id property of a node.
|
538 |
|
539 | > TIP: Ids for nodes created via the context menu or using a TreeController instance get populated automatically unless nodes had ids before there were added to the tree
|
540 |
|
541 | For example, your tree structure should look like:
|
542 |
|
543 | ```typescript
|
544 | public tree: TreeModel = {
|
545 | value: 'Programming languages by programming paradigm',
|
546 | id: 1,
|
547 | children: [
|
548 | {
|
549 | value: 'Object-oriented programming',
|
550 | id: 2,
|
551 | children: [
|
552 | {value: 'Java', id: 3},
|
553 | {value: 'C++', id: 4},
|
554 | {value: 'C#', id 5},
|
555 | ]
|
556 | },
|
557 | {
|
558 | value: 'Prototype-based programming',
|
559 | id: 6,
|
560 | children: [
|
561 | {value: 'JavaScript', id: 7},
|
562 | {value: 'CoffeeScript', id: 8},
|
563 | {value: 'Lua', id: 9},
|
564 | ]
|
565 | }
|
566 | ]
|
567 | };
|
568 | ```
|
569 |
|
570 | Ids must be unique within a one tree, otherwise, some controllers will be overwritten and you won't be able to acquire them.
|
571 | In order to get a node's controller you need to create an Angular local variable out of tree component via hash binding in the template:
|
572 |
|
573 | ```typescript
|
574 | @Component({
|
575 | template: '<tree [tree]="tree" #treeComponent></tree>'
|
576 | })
|
577 | class TheComponent implements AfterViewInit {
|
578 | tree: TreeModel = {
|
579 | value: 'Programming languages by programming paradigm',
|
580 | id: 1,
|
581 | children: [
|
582 | {
|
583 | value: 'Object-oriented programming',
|
584 | id: 2,
|
585 | children: [
|
586 | {value: 'Java', id: 3},
|
587 | {value: 'C++', id: 4},
|
588 | {value: 'C#', id 5},
|
589 | ]
|
590 | },
|
591 | {
|
592 | value: 'Prototype-based programming',
|
593 | id: 6,
|
594 | children: [
|
595 | {value: 'JavaScript', id: 7},
|
596 | {value: 'CoffeeScript', id: 8},
|
597 | {value: 'Lua', id: 9},
|
598 | ]
|
599 | }
|
600 | ]
|
601 | };
|
602 |
|
603 | @ViewChild('treeComponent') treeComponent;
|
604 |
|
605 | ngAfterViewInit(): void {
|
606 | // ... make use of this.treeComponent ...
|
607 | }
|
608 | }
|
609 | ```
|
610 |
|
611 | then by executing `this.treeComponent.getControllerByNodeId(PUT_HERE_YOUR_NODE_ID)` you'll get an instance of a TreeController (another couple steps and the world is yours =) )
|
612 |
|
613 | Below are more detailed explanations of the TreeController and its usage. Let's go method by method:
|
614 |
|
615 | ```typescript
|
616 | const oopNodeController = this.treeComponent.getControllerByNodeId(2);
|
617 | ```
|
618 |
|
619 | #### select - selects a node
|
620 |
|
621 | ```typescript
|
622 | oopNodeController.select();
|
623 | ```
|
624 |
|
625 | This method selects the node and unselects all the other nodes, also it fires a select event.
|
626 |
|
627 | #### isSelected - checks whether a node is selected
|
628 |
|
629 | ```typescript
|
630 | oopNodeController.isSelected();
|
631 | ```
|
632 |
|
633 | This method returns true if the node is selected and false if it isn't.
|
634 |
|
635 | #### collapse - collapses a node
|
636 |
|
637 | ```typescript
|
638 | oopNodeController.collapse();
|
639 | ```
|
640 |
|
641 | This method collapses a node if the node is collapsible (for example we cannot collapse a leaf). If the node gets collapsed successfully - a collapse event gets fired.
|
642 |
|
643 | #### isCollapsed - check whether a node is collapsed
|
644 |
|
645 | ```typescript
|
646 | oopNodeController.isCollapsed();
|
647 | ```
|
648 |
|
649 | This method returns true if the node is collapsed and false otherwise.
|
650 |
|
651 | #### expand - expands a node
|
652 |
|
653 | ```typescript
|
654 | oopNodeController.expand();
|
655 | ```
|
656 |
|
657 | This method expands the node in case it can be expanded. On successful expanding the expand event is fired.
|
658 |
|
659 | #### expandToParent - expands a node and its parents up to the root
|
660 |
|
661 | ```typescript
|
662 | oopNodeController.expandToParent();
|
663 | ```
|
664 |
|
665 | This method expands the node even if it is a leaf. Expand event is fired for every expanded parent up to the root.
|
666 |
|
667 | **Important:** For this to work - `keepNodesInDOM: true` should be set on the appropriate tree.
|
668 |
|
669 | #### isExpanded - checks whether a node is expanded
|
670 |
|
671 | ```typescript
|
672 | oopNodeController.isExpanded();
|
673 | ```
|
674 |
|
675 | #### toTreeModel - converts a tree to a TreeModel instance
|
676 |
|
677 | Actually controller makes and returns a clone of tree's underlying model
|
678 |
|
679 | ```typescript
|
680 | oopNodeController.toTreeModel();
|
681 | ```
|
682 |
|
683 | This method returns true if the node is expanded and false otherwise.
|
684 |
|
685 | #### rename - renames a node (changes its value underneath)
|
686 |
|
687 | ```typescript
|
688 | oopNodeController.rename('new value');
|
689 | ```
|
690 |
|
691 | This method accepts a string and sets it as a node's new value, this action also fires rename event.
|
692 |
|
693 | #### startRenaming - changes the node template so that text input appears and lets a user type a new name
|
694 |
|
695 | ```typescript
|
696 | oopNodeController.startRenaming();
|
697 | ```
|
698 |
|
699 | After the user entered the new name a rename event will be fired.
|
700 |
|
701 | #### remove - removes a node from the tree
|
702 |
|
703 | ```typescript
|
704 | oopNodeController.remove();
|
705 | ```
|
706 |
|
707 | This method removes the node and its children and fires remove event.
|
708 |
|
709 | #### addChild - creates a new child node
|
710 |
|
711 | ```typescript
|
712 | let newNode: TreeModel = {
|
713 | value: 'Go',
|
714 | children: []
|
715 | };
|
716 | oopNodeController.addChild(newNode);
|
717 | ```
|
718 |
|
719 | This method accepts a TreeModel and adds it as a child of the parent or as a sibling (depends on which controller this was called - branch controller or a leaf controller).
|
720 |
|
721 | ### changeNodeId - changes node's id
|
722 |
|
723 | ```typescript
|
724 | oopNodeController.changeNodeId(10);
|
725 | ```
|
726 |
|
727 | This method can change a node's id. When the user creates a node from node's menu you will access the new node after it's created and this method will provide a way to change the node's id.
|
728 |
|
729 | ### reloadChildren - loads async children once more
|
730 |
|
731 | ```typescript
|
732 | oopNodeController.reloadChildren();
|
733 | ```
|
734 |
|
735 | ### setChildren - changes children of a node;
|
736 |
|
737 | ```typescript
|
738 | let newChildren: Array<TreeModel> = [
|
739 | { value: 'new children 1' },
|
740 | { value: 'new children 2' },
|
741 | { value: 'new children 3' }
|
742 | ];
|
743 | oopNodeController.setChildren(newChildren);
|
744 | ```
|
745 |
|
746 | This method replaces all existing children of the node with new ones.
|
747 |
|
748 | ## SystemJS
|
749 |
|
750 | If you are using SystemJS, then you need
|
751 |
|
752 | ```javascript
|
753 | System.config({
|
754 | // ...
|
755 | map: {
|
756 | // ...
|
757 | 'ng2-tree': 'node_modules/ng2-tree/bundles/ng2-tree.umd.min.js',
|
758 | // ...
|
759 | },
|
760 | // ...
|
761 | }
|
762 | ```
|
763 |
|
764 | ## Changes that should be taken into account in order to migrate from **ng2-tree V1** to **ng2-tree V2**
|
765 |
|
766 | * Events were reworked:
|
767 | * In V1 all events that were inherited from NodeDestructiveEvent used to have property `parent`. It's not the case anymore. If you need a parent you should get it from `node` in event object like `node.parent`;
|
768 | * All events used to have `node` property of type `TreeModel`. Now `node` is of type [Tree](#tree-class) (as well as `node.parent`);
|
769 | * `NodeMovedEvent` now has property `previousParent`, which contains tree in which moved node used to be.
|
770 | * CSS styles in **ng2-tree V2** are distributed as separate file which you can find in `node_modules/ng2-tree/styles.css`. That allows you to override ng2-tree styles more easily.
|
771 |
|
772 | ## :bulb: Want to help?
|
773 |
|
774 | I am very appreciate for your ideas, proposals and found bugs which you can put in [github issues](https://github.com/valor-software/ng2-tree/issues). Thanks in advance!
|
775 |
|
776 | **P.S.** If you find it hard going through the documentation, please, let me know which parts of it was difficult to grasp and I will improve them.
|