# Tree API

## Introducing

EyzyTree includes a [basic API](/tree/api/basic.md) from under the hood. Much can be done with it. But sometimes you need to do something more complicated. In this case, you can use the **external API**.

A external API has to be included from separately file (module). It is similar to [Connection](/tree/api/basic.md#connection) way the Basic API.

## Connection

CDN:

```markup
<script src="https://cdn.jsdelivr.net/npm/eyzy-tree/dist/api.js"></script>
```

As ES6 module:

```javascript
import EyzyTreeApi from "eyzy-tree/api"
```

Using:

```javascript
import React from 'react'
import EyzyTree from 'eyzy-tree'
import EyzyTreeApi from "eyzy-tree/api"

class AwesomeComponent extends React.PureComponent {
    api = null
    
    handleTreeReady = (treeApi) => {
        // it is important to pass the Basic API as an argument
        this.api = new EyzyTreeApi(treeApi)
    }
    
    render() {
        return <EyzyTree 
            data={data}
            onReady={this.handleTreeReady}
        />
    }
}
```

## Methods

### find

* **Description**: Finds nodes by specified [Query](/tree/api/query.md)
* **Arguments**:&#x20;
  * `query`: [Query](/tree/api/query.md)
* **Returns**:&#x20;
  * [NodeAPI](/tree/api/node-api.md)
* **Usage:**&#x20;

```javascript
const awesomeNode = this.api.find({text: 'Awesome Node'})

awesomeNode.addClass('really')
```

###

### findAll

* **Description**: Similar to `find` method. But it returns all found nodes.
* **Arguments**:&#x20;
  * `query`: [Query](/tree/api/query.md)
* **Returns**:&#x20;
  * [NodeAPI](/tree/api/node-api.md)
* **Usage:**&#x20;

```javascript
const awesomeNode = this.api.findAll({text: 'Awesome Node'})
```

###

### remove

* **Description**: Removes matched node.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * `TreeNode`
  * `TreeNode[]`
  * `null`
* **Usage:**

```javascript
const removedNode = this.api.remove(/bad nodes/)

if (isNodeRemoved) {
    alert(`Congrat... node "${removedNode.text}" has removed!`)
}

// it will remove all `checked` nodes
this.api.remove({ checked: true }, true)
```

###

### empty

* **Description**: It removes all children nodes. Also it removes `isBatch` property (see [Acync](/tree/guides/async.md#nodes-property))
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * `boolean`
  * `null`
* **Usage:**

```javascript
const isNodeCleared = this.api.empty(/__test node__/)

if (isNodeCleared) {
    alert('Congrat... node has removed!')
} else {
    alert('Node doesn\'t has children')
}
```

###

### selected

{% hint style="info" %}
This method doesn't has a **multiple** argument. It depends on tree **multiple** prop.
{% endhint %}

* **Description**: It the same as [Basic:selected()](/tree/api/basic.md#selected), but it returns a [NodeAPI](/tree/api/node-api.md)
* **Returns:**&#x20;
  * [NodeAPI](/tree/api/node-api.md)
* **Usage:**

```javascript
// remove all selected node(s)
this.api.selected().remove()
```

###

### select

{% hint style="info" %}
When using **extendSelection** argument it will not extend selection for single mode.

In case if you want to to **select** multiple nodes and **extend** selection you need to use next hook: [Multiple Selection](/tree/api/useful-hooks.md#multiple-selection)
{% endhint %}

* **Description**: Selects matched node.
* **Arguments:**
  * `criteria`**:** [Find criteria](/tree/api/query.md)
  * `extendSelection`**:** boolean not required. For multiple mode adds the matched node to the list of selected items (it's like a selecting node via `Ctrl`)
  * `expandOnSelect` boolean, not required. `select` method will try to read this property from the tree props if **expandOnSelect** argument is not pass
* **Returns:**&#x20;
  * `boolean`
  * `null`
* **Usage:**

```javascript
this.api.select('Item 1')
this.api.select('Item 2', true) // will be selected: Item 1, Item 2
```

`expandOnSelect` example

```jsx
<EyzyTree 
    data={data}
    expandOnSelect={true}
/>

this.api.select(
    /node/,
    /* extend selection */ false,  
    /* expandOnSelect will be true (read from the tree) */
)

this.api.select(
    /node/,
    false,
    /* expandOnSelect is overrided */ false
)
```

###

### unselect

* **Description**: Removes Selection for matched node.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
// will be returned false if node is not selected overwise true
this.api.unselect('Item 1')

// yeah, u can do it
this.api.unselect({ selected: true })

// unselect ALL selected nodes (similar to unselectAll method)
this.api.unselect({ selected: true }, true)
```

###

### unselectAll

* **Description**: Removes selection for all selected nodes

###

### checked

* **Description**: For `checkable` mode the library will combine checked nodes into an array. There are different ways to select "checked" nodes by using `valueConsistsOf` argument.
  * `ALL` (default) it will gather all "checked" nodes
  * `BRANCH` if node has children and it is checked (and all of the children nodes are checked) then all children nodes will be excluded from the result
  * `LEAF` returns nodes which doesn't has children nodes
  * `WITH_INDETERMINATE` the same as `ALL`plus indeterminate nodes
* **Arguments**:&#x20;
  * `valueConsistsOf`: 'ALL' | 'BRANCH' | 'LEAF' | 'WITH\_INDETERMINATE'
  * `showDisabled`: boolean (default **false**)
* **Returns**:&#x20;
  * [NodeAPI](/tree/api/node-api.md)
* **Usage:**&#x20;

```javascript
this.api.checked('LEAF').addClass(['className'])
```

###

### check

* **Description**: Sets matched node as ticked(checked).
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
this.api.check('Item 1') // -> true
this.api.check({ disabledCheckbox: true }) // -> false

this.api.check(/item/, true) // multiple search
```

###

### uncheck

* **Description**: Sets matched node as **not** ticked(checked).
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
this.api.uncheck('Item 1') // -> false, because node was unchecked


this.api.uncheck({ checked: true }, true)
```

###

### uncheckAll

* **Description**: Uncheck all ticked nodes.

###

### disable

* **Description**: Sets matched node as disabled.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
this.api.disable('Item 1') // -> true
this.api.disable({ disabled: true }) // -> false, node already disabled
```

###

### enable

* **Description**: Sets matched node as enabled.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
this.api.enable('Item 1') // -> false, node already enabled
this.api.enable({ disabled: true }, true) // -> true
```

### enableCheckbox

* **Description**: Sets checkbox state for matched node as enabled.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
this.api.enableCheckbox('Item 1')
this.api.enableCheckbox({ disabledCheckbox: true }, true) // -> true
```

### disableCheckbox

* **Description**: Sets checkbox state for matched node as disabled.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
this.api.disableCheckbox('Item 1')
this.api.disableCheckbox({ checkbable: true }, true)
```

### expand

* **Description**: Expands matched node.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)&#x20;
  * `multiple`**:** boolean
  * `includingDisabled`: boolean (default **false**).
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
this.api.expand('Leaf Node') // -> false, node doesn't has children
this.api.expand({ expanded: false }, true) // -> all expanded
```

### collapse

* **Description**: Collapses matched node.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `multiple`**:** boolean
  * `includingDisabled`: boolean (default **false**).&#x20;
* **Returns:**&#x20;
  * **`boolean`**
* **Usage:**

```javascript
this.api.collapse('Leaf Node') // -> false, node doesn't has children
this.api.collapse({ expanded: true}, true, true) // -> all nodes including disabled
```

### data

{% hint style="info" %}
You can store here whatever you want.&#x20;

**It is impossible to set/get data for multiple nodes via this method. But it very easy to do it via** [**NodeAPI::data**](/tree/api/node-api.md#data)
{% endhint %}

* **Description**: It is getter/setter for the `data` property of the node.
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `key`: string | object
  * `value` : any (not required)
* **Returns:**&#x20;
  * `undefined`
  * `data object`
  * [NodeAPI](/tree/api/node-api.md)
* **Usage:**

```jsx
// tree data
const data = [
    { text: 'Item 1', data: { isSuper: true } },
    { text: 'Item 2' },
    { text: 'Item 3' }
]

// it will find the first item (!)
this.api.data(/Item/, 'isSuper', false)
// or
// data is instead extended by shallow merge
// node.data will be { isSuper: false, isSuper2: false }
this.api.data(/Item/, { isSuper2: false })
```

{% hint style="info" %}
This method has different return results
{% endhint %}

```jsx
// tree data
const data = [
    { text: 'Item 1', data: { isSuper: true } },
    { text: 'Item 2' },
    { text: 'Item 3' }
]

// return a value: value
this.api.data(/Item/, 'isSuper')

// get full data object: { isSuper: true, isSuper2: 'string' }
this.api.data(/Item/)

// setter: return NodeAPI
this.api.data(/Item/, { isSuper2: false })

// setter: return NodeAPI
this.api.data(/Item/, 'isSuper2', 'string')

// as you can see it's possible you use API after setting the data
this.api
    .data(/Item/, 'isSuper3', 'string3')
    .expand()
```

### hasClass

* **Description**: Checks if a node has a `className`
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `className`: string
* **Returns:**&#x20;
  * `boolean`
* **Usage:**

```javascript
const hasClass = this.api.hasClass(/excess/, 'highligted')
```

### addClass

* **Description**: It will add classNames for the node. This class will be added to the node with the class `.node-content` (check [Node's structure](/tree/customization.md#nodes-strcutrure))
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `Array<className>`: string\[]
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * `TreeNode` if node is found
  * `null` if node is not found
* **Usage:**

```javascript
this.api.addClass(/excess/, ['excess-node', 'you-can', 'pass', 'many', 'names'])
this.api.addClass(/excess/, ['red-border'], true)
```

###

### removeClass

* **Description**: The same behavior as `addClass` method, but it removes classNames
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `Array<className>`: string\[]
  * `multiple`**:** boolean
* **Returns:**&#x20;
  * `TreeNode` if node is found
  * `null` if node is not found
* **Usage:**

```javascript
this.api.removeClass(/excess/, ['excess-node', 'you-can', 'pass', 'many', 'names'])
this.api.removeClass(/focused/, ['focused'], true)
```

### append

* **Description**: Inserts nodes to the end of the matched node
* **Arguments:**
  * `query`: [Query](/tree/api/query.md)
  * `nodes`: *string | object | Promise*
  * `opts`: [Insertion options](/tree/guides/async.md#insertion-options)
* **Returns:**&#x20;
  * `Promiselike<TreeNode[] | null>` added nodes (always an array)
* **Usage:**

```javascript
const appendedNodes = this.api.append(
    'Item 1', // find criteria
    ['Item 1.1.', 'Item 1.2'], // nodes can be as string
    { expand: true } // expand node with text 'Item 1' (if node was found)
)

this.api.append(
    { selected: true },
    [
        { text: 'Selected children 1', disabled: true },
        { text: 'Selected children 2' }        
    ]
)

// it also can be a function, but it must return a Promise
this.api.append(
    'Selected children 2',
    (node) => {
        // node.text === 'Selected children 2'
        return fetch(`/api?childName=${node.text}`)
            .then(response => response.json())
    }
)

this.api
    .append('Item 1', 'Item 1.3')
    .then(node => { // see Node API page
        node.select()
    })
```

###

### prepend

* **Description**: This method is similar to `append`. But nodes inserting to the beginning of children list. (well ... you know, as well as jQuery :) )
* **Example:**

```javascript
// tree structure
/**
item 1
item 2
 item 2.1
 item 2.2
item 3
*/

this.api.append('item 2', [
 'item 2.3', 'item 2.4', { text: 'item 2.5', checked: true }
])

// will be:
/**
item 1
 item 2.3    << new node
 item 2.4    << new node
 item 2.5    << new node
 item 2.1
 item 2.2
item 2
item 3
*/
```

###

### before

* **Description**: This method is similar to `append`. But nodes inserting **before** matched node.
* **Example:**

```javascript
// tree structure
/**
item 1
item 2
item 3
*/

this.api.before(/item 2/, 'item n')

// will be:
/**
item 1
item n <<<<<<< -- added node
item 2
item 3
*/
```

###

### after

* **Description**: This method is similar to `append`. But nodes inserting **after** matched node.

```javascript
// tree structure
/**
item 1
item 2
item 3
*/

this.api.before(/item 2/, 'item n')

// will be:
/**
item 1
item 2
item n <<<<<<< -- added node
item 3
*/
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://eyzy.gitbook.io/tree/api/tree-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
