# Angular IVH Treeview
[ ![Build Status][travis-img] ][travis-link]
> A treeview for AngularJS with filtering, checkbox support, custom templates,
> and more.
## Contents
- [Getting Started](#getting-started)
- [Example Usage](#example-usage)
- [Options](#options)
- [Filtering](#filtering)
- [Expanded by Default](#expanded-by-default)
- [Default Selected State](#default-selected-state)
- [Validate on Startup](#validate-on-startup)
- [Twisties](#twisties)
- [Templates and Skins](#templates-and-skins)
- [Toggle Handlers](#toggle-handlers)
- [Select/Deselect Handlers](#selectdeselect-handlers)
- [All the Options](#all-the-options)
- [Treeview Manager Service](#treeview-manager-service)
- [`ivhTreeviewMgr.select(tree, node[, opts][, isSelected])`](#ivhtreeviewmgrselecttree-node-opts-isselected)
- [`ivhTreeviewMgr.selectAll(tree[, opts][, isSelected])`](#ivhtreeviewmgrselectalltree-opts-isselected)
- [`ivhTreeviewMgr.selectEach(tree, nodes[, opts][, isSelected])`](#ivhtreeviewmgrselecteachtree-nodes-opts-isselected)
- [`ivhTreeviewMgr.deselect(tree, node[, opts])`](#ivhtreeviewmgrdeselecttree-node-opts)
- [`ivhTreeviewMgr.deselectAll(tree[, opts])`](#ivhtreeviewmgrdeselectalltree-opts)
- [`ivhTreeviewMgr.deselectEach(tree, nodes[, opts])`](#ivhtreeviewmgrdeselecteachtree-nodes-opts)
- [`ivhTreeviewMgr.expand(tree, node[, opts][, isExpanded])`](#ivhtreeviewmgrexpandtree-node-opts-isexpanded)
- [`ivhTreeviewMgr.expandRecursive(tree[, node[, opts][,isExpanded]])`](#ivhtreeviewmgrexpandrecursivetree-node-opts-isexpanded)
- [`ivhTreeviewMgr.expandTo(tree, node[, opts][, isExpanded])`](#ivhtreeviewmgrexpandtotree-node-opts-isexpanded)
- [`ivhTreeviewMgr.collapse(tree, node[, opts])`](#ivhtreeviewmgrcollapsetree-node-opts)
- [`ivhTreeviewMgr.collapseRecursive(tree[, node[, opts]])`](#ivhtreeviewmgrcollapserecursivetree-node-opts)
- [`ivhTreeviewMgr.collapseParents(tree, node[, opts])`](#ivhtreeviewmgrcollapseparentstree-node-opts)
- [`ivhTreeviewMgr.validate(tree[, opts][, bias])`](#ivhtreeviewmgrvalidatetree-opts-bias)
- [Dynamic Changes](#dynamic-changes)
- [Tree Traversal](#tree-traversal)
- [`ivhTreeviewBfs(tree[, opts][, cb])`](#ivhtreeviewbfstree-opts-cb)
- [Optimizations and Known Limitations](#optimizations-and-known-limitations)
- [Reporting Issues](#reporting-issues)
- [Contributing](#contributing)
- [Release History](#release-history)
- [License](#license)
## Getting Started
IVH Treeview can be installed with bower and npm:
```
bower install angular-ivh-treeview
# or
npm install angular-ivh-treeview
```
Once installed, include the following files in your app:
- `dist/ivh-treeview.js`
- `dist/ivh-treeview.css`
- `dist/ivh-treeview-theme-basic.css` (optional minimalist theme)
And add the `ivh.treeview` module to your main Angular module:
```javascript
angular.module('myApp', [
'ivh.treeview'
// other module dependencies...
]);
```
You're now ready to use the `ivh-treeview` directive, `ivhTreeviewMgr` service,
and `ivhTreeviewBfs` service.
## Example Usage
In your controller...
```javascript
app.controller('MyCtrl', function() {
this.bag = [{
label: 'Glasses',
value: 'glasses',
children: [{
label: 'Top Hat',
value: 'top_hat'
},{
label: 'Curly Mustache',
value: 'mustachio'
}]
}];
this.awesomeCallback = function(node, tree) {
// Do something with node or tree
};
this.otherAwesomeCallback = function(node, isSelected, tree) {
// Do soemthing with node or tree based on isSelected
}
});
```
In your view...
```html
<div ng-controller="MyCtrl as fancy">
<input type="text" ng-model="bagSearch" />
<div
ivh-treeview="fancy.bag"
ivh-treeview-filter="bagSearch">
</div>
</div>
```
## Options
IVH Treeview is pretty configurable. By default it expects your elements to have
`label` and `children` properties for node display text and child nodes
respectively. It'll also make use of a `selected` attribute to manage selected
states. If you would like to pick out nodes by ID rather than reference it'll
also use an `id` attribute. Those attributes can all be changed, for example:
```html
<div ng-controller="MyCtrl as fancy">
<div ivh-treeview="fancy.bag"
ivh-treeview-id-attribute="'uuid'"
ivh-treeview-label-attribute="'text'"
ivh-treeview-children-attribute="'items'"
ivh-treeview-selected-attribute="'isSelected'">
</div>
```
IVH Treeview attaches checkboxes to each item in your tree for a hierarchical
selection model. If you'd rather not have these checkboxes use
`ivh-treeview-use-checkboxes="false"`:
```html
<div ng-controller="MyCtrl as fancy">
<div ivh-treeview="fancy.bag"
ivh-treeview-use-checkboxes="false">
</div>
```
There's also a provider if you'd like to change the global defaults:
```javascript
app.config(function(ivhTreeviewOptionsProvider) {
ivhTreeviewOptionsProvider.set({
idAttribute: 'id',
labelAttribute: 'label',
childrenAttribute: 'children',
selectedAttribute: 'selected',
useCheckboxes: true,
expandToDepth: 0,
indeterminateAttribute: '__ivhTreeviewIndeterminate',
expandedAttribute: '__ivhTreeviewExpanded',
defaultSelectedState: true,
validate: true,
twistieExpandedTpl: '(-)',
twistieCollapsedTpl: '(+)',
twistieLeafTpl: 'o',
nodeTpl: '...'
});
});
```
Note that you can also use the `ivhTreeviewOptions` service to inspect global
options at runtime. For an explanation of each option see the comments in the
[source for ivhTreeviewOptions][trvw-opts].
```javascript
app.controller('MyCtrl', function(ivhTreeviewOptions) {
var opts = ivhTreeviewOptions();
// opts.idAttribute === 'id'
// opts.labelAttribute === 'label'
// opts.childrenAttribute === 'children'
// opts.selectedAttribute === 'selected'
// opts.useCheckboxes === true
// opts.expandToDepth === 0
// opts.indeterminateAttribute === '__ivhTreeviewIndeterminate'
// opts.expandedAttribute === '__ivhTreeviewExpanded'
// opts.defaultSelectedState === true
// opts.validate === true
// opts.twistieExpandedTpl === '(-)'
// opts.twistieCollapsedTpl === '(+)'
// opts.twistieLeafTpl === 'o'
// opts.nodeTpl =(eh)= '...'
});
```
### Filtering
We support filtering through the `ivh-treeview-filter` attribute, this value is
supplied to Angular's `filterFilter` and applied to each node individually.
IVH Treeview uses `ngHide` to hide filtered out nodes. If you would like to
customize the hide/show behavior of nodes as they are filtered in and out of
view (e.g. with `ngAnimate`) you can target elements with elements with the
`.ivh-treeview-node` class:
```css
/* with e.g. keyframe animations */
.ivh-treeview-node.ng-enter {
animation: my-enter-animation 0.5s linear;
}
.ivh-treeview-node.ng-leave {
animation: my-leave-animation 0.5s linear;
}
/* or class based animations */
.ivh-treeview-node.ng-hide {
transition: 0.5s linear all;
opacity: 0;
}
/* alternatively, just strike-through filtered out nodes */
.ivh-treeview-node.ng-hide {
display: block !important;
}
.ivh-treeview-node.ng-hide .ivh-treeview-node-label {
color: red;
text-decoration: line-through;
}
```
***Demo***: [Filtering](http://jsbin.com/zitiri/edit?html,output)
### Expanded by Default
If you want the tree to start out expanded to a certain depth use the
`ivh-treeview-expand-to-depth` attribute:
```html
<div ng-controller="MyCtrl as fancy">
<div
ivh-treeview="fancy.bag"
ivh-treeview-expand-to-depth="2"
ivh-treeview-use-checkboxes="false">
</div>
```
You can also use the `ivhTreeviewOptionsProvider` to set a global default.
If you want the tree *entirely* expanded use a depth of `-1`. Providing a depth
greater than your tree's maximum depth will cause the entire tree to be
initially expanded.
***Demo***: [Expand to depth on
load](http://jsbin.com/ruxedo/edit?html,js,output)
### Default Selected State
Whe