
Syncfusion Angular Dropdowntree
- 213 installs
- Updated August 4, 2026
- syncfusion/angular-ui-components-skills
Use syncfusion-angular-dropdowntree for development tasks
About
syncfusion-angular-dropdowntree: A skill for development. This provides functionality for development workflows.
- syncfusion-angular-dropdowntree
Syncfusion Angular Dropdowntree by the numbers
- 213 all-time installs (skills.sh)
- +12 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #1,894 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/angular-ui-components-skills --skill syncfusion-angular-dropdowntreeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 213 |
|---|---|
| Last updated | August 4, 2026 |
| Repository | syncfusion/angular-ui-components-skills ↗ |
What it does
Use syncfusion-angular-dropdowntree for development tasks
Files
Implementing Syncfusion Angular Dropdown Tree
The Dropdown Tree component allows you to select single or multiple values from hierarchical data in a tree-like structure. It provides essential features like data binding, checkboxes, templates, and accessibility, making it ideal for displaying categorized selections, organizational hierarchies, and nested data structures.
When to Use This Skill
Use the Dropdown Tree component when you need to:
- Hierarchical Selection - Allow users to select from nested, tree-structured data (categories, file hierarchies, organizational trees)
- Multi-Selection - Enable checkbox-based selection of multiple items with optional auto-check (parent-child sync)
- Dynamic Data - Bind local arrays, self-referential structures, or remote OData/REST endpoints
- Customized Display - Use item templates, value templates, headers, and footers for rich UI customization
- Large Datasets - Support remote data with lazy loading to optimize performance
- Localization - Adapt component text and messages for different cultures and languages
Component Overview
The Dropdown Tree provides a compact dropdown input that expands to show a full tree structure with powerful filtering, selection, and templating capabilities. Unlike flat dropdowns, it maintains hierarchical relationships, enabling intuitive navigation through multi-level data.
Key Characteristics:
- Single or multiple item selection
- Checkbox-based multi-selection with optional auto-check
- Local hierarchical and self-referential data binding
- Remote data binding with DataManager (OData, ODataV4, WebAPI)
- Rich templating: items, values, headers, footers, no-records, action-failure
- Built-in accessibility with keyboard navigation and ARIA attributes
- Full localization support
Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Dependencies and package setup
- Angular CLI configuration
- Module registration (@syncfusion/ej2-angular-dropdowns)
- CSS imports and theme configuration
- Basic component integration
- First working example with local data
Data Binding
📄 Read: references/data-binding.md
- Hierarchical data structure (nested arrays)
- Self-referential data binding (flat arrays with parentValue)
- Remote data with DataManager
- OData and ODataV4 adaptors
- WebAPI adaptor configuration
- Query-based filtering
Checkbox Features
📄 Read: references/checkbox-features.md
- Enable checkboxes with showCheckBox property
- Multi-selection without UI disruption
- Auto-check hierarchical behavior (parent-child sync)
- Select All feature (showSelectAll with custom labels)
- Checkbox state synchronization
- Intermediate states (partially checked)
Templates and Customization
📄 Read: references/templates.md
- Item template for custom tree item rendering
- Value template for selected item display
- Header and footer templates
- No records and action failure templates
- Custom display template for multi-selection (Custom mode)
- Template expressions and interpolation
Localization
📄 Read: references/localization.md
- Supported localization keys and default messages
- Setting locale and culture
- Customizing locale-specific strings
- Key messages: noRecordsTemplate, actionFailureTemplate, overflowCountTemplate, totalCountTemplate
- Multi-language configuration
API Reference
📄 Read: references/api-reference.md
- Core properties and field mappings
- TreeSettings configuration options
- Common events and callbacks
- Best practices for property configuration
- Performance optimization tips
Methods and Events
📄 Read: references/methods-and-events.md
- Component methods: showPopup(), hidePopup(), refresh(), clearSelection(), expandAll(), collapseAll()
- Selection events: change, select
- Popup events: open, close, beforeOpen
- Data events: dataBound, actionFailure, filtering
- Lifecycle events: created, destroyed
- User interaction events: focus, blur, keyPress
- Event arguments and signatures
- Complete working examples
Quick Start Example
Here's a minimal working example with hierarchical data:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-dropdown-tree',
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
placeholder='Select a category'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class AppComponent {
// Hierarchical data structure with nested arrays
public data = [
{
nodeId: '01', nodeText: 'Music',
nodeChild: [
{ nodeId: '01-01', nodeText: 'Gouttes.mp3' }
]
},
{
nodeId: '02', nodeText: 'Videos', expanded: true,
nodeChild: [
{ nodeId: '02-01', nodeText: 'Naturals.mp4' },
{ nodeId: '02-02', nodeText: 'Wild.mpeg' }
]
}
];
// Field mapping: value=nodeId, text=nodeText, child=nodeChild
public fields = {
dataSource: this.data,
value: 'nodeId',
text: 'nodeText',
child: 'nodeChild'
};
}Common Patterns
Pattern 1: Multi-Selection with Checkboxes
@Component({
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[showCheckBox]='true'
[showSelectAll]='true'
selectAllText='Check All'
unSelectAllText='Uncheck All'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class CheckboxExample {
public data = [
{ id: 1, name: 'Music', hasChild: true, expanded: true },
{ id: 2, pid: 1, name: 'Hot Singles' },
{ id: 3, pid: 1, name: 'Rising Artists' }
];
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
parentValue: 'pid',
hasChildren: 'hasChild'
};
}When to use: Allow users to select multiple items in a single interaction, with convenient "Select All" option. Use selectAllText for unchecked label and unSelectAllText for checked label.
Pattern 2: Auto-Check (Parent-Child Sync)
@Component({
template: `<ejs-dropdowntree [fields]='fields'
[showCheckBox]='true'
[treeSettings]='{ autoCheck: true }'></ejs-dropdowntree>`
})
export class AutoCheckExample {
public fields = { dataSource: this.data, /* ... */ };
}When to use: Enforce hierarchical consistency—checking a parent automatically checks all children, and unchecking the last child unchecks the parent (intermediate state for partial selection).
Pattern 3: Remote Data with OData
import { DataManager, ODataV4Adaptor, Query } from '@syncfusion/ej2-data';
@Component({
template: `<ejs-dropdowntree [fields]='fields'></ejs-dropdowntree>`
})
export class RemoteDataExample {
public data = new DataManager({
url: 'url',
adaptor: new ODataV4Adaptor,
crossDomain: true
});
public fields = {
dataSource: this.data,
query: new Query().from('Employees').select('EmployeeID,FirstName').take(5),
value: 'EmployeeID',
text: 'FirstName',
hasChildren: 'EmployeeID'
};
}When to use: Fetch hierarchical data from a remote server, reducing initial load and supporting large datasets.
Pattern 4: Custom Item Display
@Component({
template: `<ejs-dropdowntree [fields]='fields'
[itemTemplate]='itemTemplate'></ejs-dropdowntree>`
})
export class TemplateExample {
public itemTemplate = '<div><strong>${name}</strong> - ${type}</div>';
public fields = { dataSource: this.data, /* ... */ };
}When to use: Display rich, formatted content for each tree item (names, icons, metadata).
Key Features
| Feature | Use Case |
|---|---|
| Hierarchical Data | Organize items in parent-child relationships (categories, departments, file trees) |
| Checkboxes | Enable multi-selection without affecting dropdown UI |
| Auto-Check | Synchronize parent-child selection states automatically |
| Remote Binding | Fetch data from OData, REST APIs, or custom endpoints |
| Templates | Customize item display, headers, footers, and selected value format |
| Accessibility | Full keyboard navigation, ARIA attributes, screen reader support |
| Localization | Support for multiple languages and regional formats |
| Select All | Quickly select or deselect all items with a single click |
````markdown
API Reference for Angular Dropdown Tree - Comprehensive Guide
Complete reference documentation for all properties, methods, and events when implementing the Syncfusion Angular Dropdown Tree component. This guide covers every available property organized by category with practical examples and use cases.
Component Selector: <ejs-dropdowntree>
Module: DropDownTreeModule from @syncfusion/ej2-angular-dropdowns
TypeScript Interface: DropDownTreeComponent
Table of Contents
- Core Properties
- Fields Configuration
- Tree Settings
- Data Binding Examples
- Display Properties
- Selection Properties
- Template Properties
- Search and Filtering
- Localization and Accessibility
- State Management
- Individual Property Examples
- Common Events
- Methods
- Best Practices
- Troubleshooting
---
Core Properties
Essential Data Binding Properties
| Property | Type | Default | Required | Purpose |
|---|---|---|---|---|
fields | FieldsModel | - | ✓ | Maps data source properties to component fields |
value | string\ | string[] | null | - |
text | string | "" | - | Display text of selected item(s) |
enabled | boolean | true | - | Enable/disable component interactions |
placeholder | string | "" | - | Hint text displayed when no item is selected |
Basic Data Binding Example
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-basic-binding',
template: `
<div class="control-section">
<ejs-dropdowntree #ddt
id='dropdowntree'
[fields]='fields'
[(value)]='selectedValue'
placeholder='Select an item'>
</ejs-dropdowntree>
<p>Selected: {{ selectedValue }}</p>
</div>
`,
standalone: true,
imports: [DropDownTreeModule, FormsModule]
})
export class BasicBindingComponent {
public data = [
{ id: 1, name: 'Parent 1', hasChild: true, expanded: true },
{ id: 2, pid: 1, name: 'Child 1.1' },
{ id: 3, pid: 1, name: 'Child 1.2' },
{ id: 4, name: 'Parent 2', hasChild: true }
];
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
parentValue: 'pid',
hasChildren: 'hasChild'
};
public selectedValue: string = '';
}---
Display Properties
Complete control over component appearance and user interface.
| Property | Type | Default | Purpose |
|---|---|---|---|
popupHeight | string\ | number | "300px" |
popupWidth | string\ | number | auto |
width | string\ | number | auto |
cssClass | string | "" | CSS class(es) for custom styling (applied to component and popup) |
showDropDownIcon | boolean | true | Show/hide dropdown arrow button |
showClearButton | boolean | false | Show/hide clear button (X) to reset selection |
wrapText | boolean | false | Wrap long selected text to multiple lines |
zIndex | number | 1000 | Z-index value of popup for stacking context |
readonly | boolean | false | Make input read-only (popup still accessible) |
Display Configuration Example
@Component({
selector: 'app-display-config',
template: `
<ejs-dropdowntree [fields]='fields'
[popupHeight]='400'
[popupWidth]='350'
[width]='300'
[showClearButton]='true'
[showDropDownIcon]='true'
[wrapText]='true'
[readonly]='false'
cssClass='custom-dropdown-tree'
[zIndex]='1005'>
</ejs-dropdowntree>
`,
styles: [`
:host ::ng-deep .custom-dropdown-tree.e-dropdown-tree {
border: 2px solid #2196F3;
border-radius: 4px;
}
:host ::ng-deep .custom-dropdown-tree.e-dropdown-tree .e-input-group {
padding: 8px 12px;
}
`]
})
export class DisplayConfigComponent {
public fields = { /* ... */ };
}---
Selection Properties
Control selection behavior, modes, and multi-selection features.
| Property | Type | Default | Purpose |
|---|---|---|---|
showCheckBox | boolean | false | Display checkboxes for multi-selection |
allowMultiSelection | boolean | false | Enable multi-selection with Ctrl+Click/Shift+Click |
showSelectAll | boolean | false | Display "Select All" checkbox in popup header |
selectAllText | string | "Select All" | Label for Select All checkbox (unchecked state) |
unSelectAllText | string | "Unselect All" | Label for Select All checkbox (checked state) |
mode | "Default"\ | "Custom"\ | "Box"\ |
delimiterChar | string | "," | Delimiter for "Delimiter" mode (separates multiple selections) |
changeOnBlur | boolean | true | Fire change event on blur (false = on every selection) |
Selection Modes Explained
Mode: "Default"
- Single selection shows item name
- Multiple selections show "N item(s) selected"
Mode: "Box"
- Multiple selections display as individual chips/tags
- Each item has a remove button
- Wraps to multiple lines if needed
Mode: "Delimiter"
- Multiple selections shown as comma-separated text
- More compact than "Box" mode
Mode: "Custom"
- Use custom template to display selections
- Access
${value.length}in template
Multi-Selection Example
@Component({
selector: 'app-multi-selection',
template: `
<div class="section">
<h4>Independent Multi-Selection</h4>
<ejs-dropdowntree [fields]='fields'
[showCheckBox]='true'
mode='Delimiter'
delimiterChar=' | '
[allowMultiSelection]='true'
(change)='onSelectionChange($event)'>
</ejs-dropdowntree>
</div>
<div class="section">
<h4>With Auto-Check Hierarchy</h4>
<ejs-dropdowntree [fields]='fields'
[showCheckBox]='true'
[showSelectAll]='true'
selectAllText='Check All Items'
unSelectAllText='Uncheck All Items'
[treeSettings]='{ autoCheck: true }'
mode='Box'>
</ejs-dropdowntree>
</div>
`,
standalone: true,
imports: [DropDownTreeModule]
})
export class MultiSelectionComponent {
public fields = { /* ... */ };
onSelectionChange(event: any) {
console.log('Selected values:', event.value);
console.log('Item count:', event.value ? event.value.length : 0);
}
}---
Fields Configuration
The fields property (FieldsModel) maps data source properties to component fields.
Available Field Properties
| Property | Type | Purpose |
|---|---|---|
dataSource | Array\ | DataManager |
value | string | Required. Unique identifier field name |
text | string | Required. Display text field name |
child | string\ | FieldsModel |
parentValue | string | Required for hierarchy. Parent ID field (for flat/self-referential data) |
hasChildren | string | Indicates if node has children (boolean or count field) |
expanded | string | Field name to mark items expanded by default |
selected | string | Field name to mark items pre-selected |
query | Query | External DataManager query to execute |
tableName | string | Table name for server-side data fetching |
iconCss | string | CSS class field for item icons |
imageUrl | string | Image URL field for item images |
tooltip | string | Tooltip text field |
selectable | string | Boolean field to disable item selection |
htmlAttributes | string | HTML attributes field |
Complete Fields Configuration Example
@Component({
selector: 'app-fields-config',
template: `<ejs-dropdowntree [fields]='fields'></ejs-dropdowntree>`
})
export class FieldsConfigComponent {
public data = [
{
id: 1,
name: 'Engineering',
dept_code: 'ENG',
manager: 'John Doe',
hasChild: true,
expanded: true,
icon: 'e-icons e-people',
tooltip: 'Engineering Department',
children: [
{
id: 2,
pid: 1,
name: 'Frontend Team',
dept_code: 'ENG-FE',
manager: 'Jane Smith',
icon: 'e-icons e-settings',
tooltip: 'Frontend Development'
},
{
id: 3,
pid: 1,
name: 'Backend Team',
dept_code: 'ENG-BE',
manager: 'Bob Johnson',
icon: 'e-icons e-settings',
tooltip: 'Backend Development'
}
]
},
{
id: 4,
name: 'Marketing',
dept_code: 'MKT',
manager: 'Alice Wonder',
hasChild: false,
icon: 'e-icons e-megaphone',
tooltip: 'Marketing Department'
}
];
public fields = {
// Data source binding
dataSource: this.data,
// Identifier and display
value: 'id',
text: 'name',
// Hierarchical structure
child: 'children', // Use this for nested data
// OR
// parentValue: 'pid', // Use for flat data with parent IDs
// Visual indicators
hasChildren: 'hasChild',
expanded: 'expanded',
iconCss: 'icon',
tooltip: 'tooltip',
// Note: 'selected' is a field name, not a field configuration
// Use data[i].selected = true to pre-select items
};
}Fields Example with Remote Data
import { DataManager, ODataV4Adaptor } from '@syncfusion/ej2-data';
@Component({
template: `<ejs-dropdowntree [fields]='fields'></ejs-dropdowntree>`
})
export class RemoteDataComponent {
public data = new DataManager({
url: 'url',
adaptor: new ODataV4Adaptor,
crossDomain: true
});
public fields = {
dataSource: this.data,
value: 'departmentId',
text: 'departmentName',
hasChildren: 'hasSubDepartments',
child: {
dataSource: new DataManager({
url: 'url',
adaptor: new ODataV4Adaptor
}),
value: 'teamId',
text: 'teamName',
parentValue: 'parentDepartmentId'
}
};
}---
Tree Settings
The treeSettings property (TreeSettingsModel) controls tree-specific behaviors.
| Property | Type | Default | Purpose |
|---|---|---|---|
autoCheck | boolean | false | Synchronize parent-child checkbox states |
checkDisabledChildren | boolean | false | Include disabled children when parent is checked |
loadOnDemand | boolean | false | Lazy-load children on parent expansion (for remote data) |
expandOn | "Auto"\ | "Click"\ | "DblClick"\ |
Tree Settings Example
@Component({
selector: 'app-tree-settings',
template: `
<ejs-dropdowntree [fields]='fields'
[showCheckBox]='true'
[treeSettings]='treeSettings'></ejs-dropdowntree>
`
})
export class TreeSettingsComponent {
public treeSettings = {
autoCheck: true, // Parent-child sync on checkbox
checkDisabledChildren: false, // Don't check disabled children
expandOn: 'Click', // Single click to expand
loadOnDemand: false // Load all data at once
};
public fields = { /* ... */ };
}Lazy Loading with loadOnDemand
import { DataManager, ODataV4Adaptor } from '@syncfusion/ej2-data';
@Component({
template: `<ejs-dropdowntree [fields]='fields'
[treeSettings]='{ loadOnDemand: true }'></ejs-dropdowntree>`
})
export class LazyLoadComponent {
public data = new DataManager({
url: 'url',
adaptor: new ODataV4Adaptor
});
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
hasChildren: 'hasChild', // Critical: tells component which nodes are expandable
child: {
dataSource: new DataManager({
url: 'url/nodes?parentId=${id}',
adaptor: new ODataV4Adaptor
}),
value: 'id',
text: 'name',
parentValue: 'parentId'
}
};
}---
Template Properties
Comprehensive templating for custom UI rendering throughout the component.
| Property | Type | Purpose |
|---|---|---|
itemTemplate | string\ | Function |
valueTemplate | string\ | Function |
headerTemplate | string\ | Function |
footerTemplate | string\ | Function |
noRecordsTemplate | string\ | Function |
actionFailureTemplate | string\ | Function |
customTemplate | string\ | Function |
Item Template Example
@Component({
selector: 'app-item-template',
template: `
<ejs-dropdowntree [fields]='fields'
[itemTemplate]='itemTemplate'
[popupHeight]='300'></ejs-dropdowntree>
`,
styles: [`
.item-container { display: flex; gap: 10px; align-items: center; }
.item-icon { font-size: 18px; }
.item-info { display: flex; flex-direction: column; }
.item-title { font-weight: 500; }
.item-subtitle { font-size: 12px; color: #666; }
`]
})
export class ItemTemplateComponent {
public data = [
{ id: 1, name: 'John Doe', role: 'Manager', icon: '👨💼', hasChild: true },
{ id: 2, pid: 1, name: 'Jane Smith', role: 'Developer', icon: '👩💻' }
];
// Template syntax uses ${}
public itemTemplate =
`<div class="item-container">
<span class="item-icon">\${icon}</span>
<div class="item-info">
<span class="item-title">\${name}</span>
<span class="item-subtitle">\${role}</span>
</div>
</div>`;
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
parentValue: 'pid',
hasChildren: 'hasChild'
};
}Value Template Example
@Component({
template: `<ejs-dropdowntree [fields]='fields'
[valueTemplate]='valueTemplate'></ejs-dropdowntree>`
})
export class ValueTemplateComponent {
public data = [
{ id: 1, name: 'John', title: 'CEO' },
{ id: 2, name: 'Jane', title: 'CTO' }
];
public valueTemplate = '<div>\${name} - <strong>\${title}</strong></div>';
public fields = { /* ... */ };
}Custom Multi-Selection Template
@Component({
template: `<ejs-dropdowntree [fields]='fields'
[showCheckBox]='true'
mode='Custom'
[customTemplate]='customTemplate'></ejs-dropdowntree>`
})
export class CustomTemplateComponent {
public fields = { /* ... */ };
// Display count with icon
public customTemplate = '📋 \${value.length} item(s) selected';
// Alternative: Show first few items
// public customTemplate = '\${value.slice(0, 2).join(", ")}\${value.length > 2 ? " +" + (value.length - 2) : ""}';
}---
Search and Filtering
Enable interactive search/filtering in the dropdown popup.
| Property | Type | Default | Purpose |
|---|---|---|---|
allowFiltering | boolean | false | Show search bar in popup |
filterBarPlaceholder | string | "" | Placeholder text in filter bar |
filterType | "StartsWith"\ | "EndsWith"\ | "Contains" |
ignoreCase | boolean | true | Case-insensitive search |
ignoreAccent | boolean | false | Ignore diacritical marks (é, ñ, etc.) |
Filtering Example
@Component({
selector: 'app-filtering',
template: `
<ejs-dropdowntree [fields]='fields'
[allowFiltering]='true'
filterBarPlaceholder='Search departments...'
filterType='Contains'
[ignoreCase]='true'
[ignoreAccent]='false'
(filtering)='onFiltering($event)'>
</ejs-dropdowntree>
`
})
export class FilteringComponent {
public fields = { /* ... */ };
onFiltering(event: any) {
// Access current filter text
console.log('Filter text:', event.text);
// Can modify event.cancel = true to prevent filtering
}
}---
Localization and Accessibility
Support for multiple languages and accessibility features.
| Property | Type | Purpose |
|---|---|---|
locale | string | Language/culture code (e.g., "en", "es", "fr", "de", "ar") |
enableRtl | boolean | Enable right-to-left direction for RTL languages |
floatLabelType | "Never"\ | "Always"\ |
Localization Example
import { registerLocale, L10n } from '@syncfusion/ej2-base';
// Define custom translations
L10n.load({
'es': {
'dropdowntree': {
'actionFailureTemplate': 'No se pudo cargar los datos',
'noRecordsTemplate': 'Sin registros disponibles'
}
}
});
@Component({
template: `<ejs-dropdowntree [fields]='fields'
locale='es'></ejs-dropdowntree>`
})
export class LocaleComponent {
public fields = { /* ... */ };
}Accessibility Example
@Component({
template: `
<label for="ddt1" class="form-label">Select Department:</label>
<ejs-dropdowntree id='ddt1'
[fields]='fields'
floatLabelType='Auto'
[htmlAttributes]='{ "aria-label": "Department selection", "aria-describedby": "hint1" }'></ejs-dropdowntree>
<small id="hint1">Select one or more departments from the list</small>
`
})
export class AccessibilityComponent {
public fields = { /* ... */ };
}---
State Management
Control component persistence and state.
| Property | Type | Default | Purpose |
|---|---|---|---|
enablePersistence | boolean | false | Save state to localStorage on blur |
destroyPopupOnHide | boolean | true | Remove popup from DOM on hide (false keeps for performance) |
enableHtmlSanitizer | boolean | true | Sanitize HTML in templates to prevent XSS |
changeOnBlur | boolean | true | Trigger change event on blur only |
Persistence Example
@Component({
selector: 'app-persistence',
template: `<ejs-dropdowntree id='persistentDDT'
[fields]='fields'
[enablePersistence]='true'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule]
})
export class PersistenceComponent {
// Component value automatically restores on page reload
public fields = { /* ... */ };
}---
Individual Property Examples
Focused examples for each property without existing samples.
1. showClearButton - Display Clear Button
Shows an "X" button to clear the current selection.
@Component({
selector: 'app-clear-button',
template: `
<div class="example">
<h4>Without Clear Button</h4>
<ejs-dropdowntree [fields]='fields'
[showClearButton]='false'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
<div class="example">
<h4>With Clear Button</h4>
<ejs-dropdowntree [fields]='fields'
[showClearButton]='true'
placeholder='Select an item'
(change)='onValueChange($event)'>
</ejs-dropdowntree>
<p>Selected: {{ currentValue }}</p>
</div>
`,
styles: [`
.example { margin: 20px; }
`],
standalone: true,
imports: [DropDownTreeModule, CommonModule]
})
export class ClearButtonComponent {
public fields = {
dataSource: [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' }
],
value: 'id',
text: 'name'
};
public currentValue = '';
onValueChange(event: any) {
this.currentValue = event.value || 'None';
}
}2. wrapText - Wrap Long Selected Text
Controls whether long text wraps to multiple lines.
@Component({
selector: 'app-wrap-text',
template: `
<div class="example">
<h4>Without Text Wrapping (wrapText=false)</h4>
<ejs-dropdowntree [fields]='fields'
[wrapText]='false'
[width]='200'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
<div class="example">
<h4>With Text Wrapping (wrapText=true)</h4>
<ejs-dropdowntree [fields]='fields'
[wrapText]='true'
[width]='200'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
`,
styles: [`
.example { margin: 20px; }
`],
standalone: true,
imports: [DropDownTreeModule]
})
export class WrapTextComponent {
public fields = {
dataSource: [
{ id: 1, name: 'This is a very long item name that might exceed the width' },
{ id: 2, name: 'Another long product description here' },
{ id: 3, name: 'Short' }
],
value: 'id',
text: 'name'
};
}3. zIndex - Control Stacking Order
Adjusts the z-index of the dropdown popup for proper layering with other elements.
@Component({
selector: 'app-zindex',
template: `
<div class="modal-overlay" [style.zIndex]="1001">
<div class="modal-content">
<h4>Modal with Dropdown (zIndex=1005)</h4>
<ejs-dropdowntree [fields]='fields'
[zIndex]='1005'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
</div>
`,
styles: [`
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
width: 400px;
}
`],
standalone: true,
imports: [DropDownTreeModule, CommonModule]
})
export class ZIndexComponent {
public fields = { /* ... */ };
}4. changeOnBlur - Control Change Event Timing
Determines when the change event fires: on blur or on every selection.
@Component({
selector: 'app-change-on-blur',
template: `
<div class="example">
<h4>Change on Blur (changeOnBlur=true) - Default</h4>
<ejs-dropdowntree [fields]='fields'
[changeOnBlur]='true'
(change)='logChange("On Blur", $event)'
placeholder='Select an item'>
</ejs-dropdowntree>
<p>Change events: {{ changeCountBlur }}</p>
</div>
<div class="example">
<h4>Change on Every Selection (changeOnBlur=false)</h4>
<ejs-dropdowntree [fields]='fields'
[changeOnBlur]='false'
(change)='logChange("Every Selection", $event)'
placeholder='Select an item'>
</ejs-dropdowntree>
<p>Change events: {{ changeCountImmediate }}</p>
</div>
`,
styles: [`
.example { margin: 20px; border: 1px solid #ccc; padding: 15px; }
`],
standalone: true,
imports: [DropDownTreeModule, CommonModule]
})
export class ChangeOnBlurComponent {
public fields = { /* ... */ };
public changeCountBlur = 0;
public changeCountImmediate = 0;
logChange(mode: string, event: any) {
if (mode === 'On Blur') {
this.changeCountBlur++;
console.log(`Change event (${mode}):`, event.value);
} else {
this.changeCountImmediate++;
console.log(`Change event (${mode}):`, event.value);
}
}
}5. readonly - Read-Only Mode
Makes the input read-only while still allowing popup access.
@Component({
selector: 'app-readonly',
template: `
<div class="example">
<h4>Normal Mode (readonly=false)</h4>
<ejs-dropdowntree [fields]='fields'
[readonly]='false'
placeholder='Type or select an item'>
</ejs-dropdowntree>
</div>
<div class="example">
<h4>Read-Only Mode (readonly=true)</h4>
<p><small>Input cannot be typed, but popup still opens</small></p>
<ejs-dropdowntree [fields]='fields'
[readonly]='true'
[value]='preselectedValue'
placeholder='Cannot type here'>
</ejs-dropdowntree>
</div>
`,
styles: [`
.example { margin: 20px; }
`],
standalone: true,
imports: [DropDownTreeModule, CommonModule]
})
export class ReadOnlyComponent {
public fields = { /* ... */ };
public preselectedValue = '1';
}6. enableHtmlSanitizer - Security Control
Sanitizes HTML in templates to prevent XSS attacks.
@Component({
selector: 'app-html-sanitizer',
template: `
<div class="example">
<h4>HTML Sanitizer Enabled (Security ON)</h4>
<ejs-dropdowntree [fields]='fields'
[itemTemplate]='itemTemplateStr'
[enableHtmlSanitizer]='true'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
<div class="example">
<h4>HTML Sanitizer Disabled (USE WITH CAUTION)</h4>
<p><small style="color: red;">⚠️ Only disable if you trust all data sources</small></p>
<ejs-dropdowntree [fields]='fields'
[itemTemplate]='itemTemplateStr'
[enableHtmlSanitizer]='false'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
`,
styles: [`
.example { margin: 20px; }
`],
standalone: true,
imports: [DropDownTreeModule, CommonModule]
})
export class HtmlSanitizerComponent {
public fields = {
dataSource: [
{ id: 1, name: 'Safe Text', html: '<span>Item 1</span>' },
{ id: 2, name: 'With Formatting', html: '<strong>Item 2</strong>' }
],
value: 'id',
text: 'name'
};
public itemTemplateStr = '<div>\${html}</div>';
}7. floatLabelType - Floating Label Behavior
Controls how placeholder/label behaves in form layouts.
@Component({
selector: 'app-float-label',
template: `
<div class="form-group">
<h4>Float Label: Never</h4>
<ejs-dropdowntree [fields]='fields'
floatLabelType='Never'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
<div class="form-group">
<h4>Float Label: Always</h4>
<ejs-dropdowntree [fields]='fields'
floatLabelType='Always'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
<div class="form-group">
<h4>Float Label: Auto</h4>
<ejs-dropdowntree [fields]='fields'
floatLabelType='Auto'
placeholder='Select an item (floats on focus)'>
</ejs-dropdowntree>
</div>
`,
styles: [`
.form-group { margin: 30px 0; }
`],
standalone: true,
imports: [DropDownTreeModule]
})
export class FloatLabelComponent {
public fields = { /* ... */ };
}8. ignoreAccent - Accent-Insensitive Search
Search ignores diacritical marks (accents).
@Component({
selector: 'app-ignore-accent',
template: `
<div class="example">
<h4>Ignore Accents (ignoreAccent=true)</h4>
<p><small>Searching "café" will find "cafe" and vice versa</small></p>
<ejs-dropdowntree [fields]='fields'
[allowFiltering]='true'
filterBarPlaceholder='Search items...'
[ignoreAccent]='true'
filterType='Contains'>
</ejs-dropdowntree>
</div>
<div class="example">
<h4>Respect Accents (ignoreAccent=false)</h4>
<p><small>Searching "café" will NOT find "cafe"</small></p>
<ejs-dropdowntree [fields]='fields'
[allowFiltering]='true'
filterBarPlaceholder='Search items...'
[ignoreAccent]='false'
filterType='Contains'>
</ejs-dropdowntree>
</div>
`,
styles: [`
.example { margin: 20px; }
`],
standalone: true,
imports: [DropDownTreeModule]
})
export class IgnoreAccentComponent {
public fields = {
dataSource: [
{ id: 1, name: 'Café' },
{ id: 2, name: 'Naïve' },
{ id: 3, name: 'Résumé' },
{ id: 4, name: 'Piñata' }
],
value: 'id',
text: 'name'
};
}9. destroyPopupOnHide - Popup DOM Management
Controls whether the popup is removed from DOM on hide.
@Component({
selector: 'app-destroy-popup',
template: `
<div class="example">
<h4>Destroy on Hide (destroyPopupOnHide=true) - Default</h4>
<p><small>Popup removed from DOM when closed (lower memory)</small></p>
<ejs-dropdowntree [fields]='fields'
[destroyPopupOnHide]='true'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
<div class="example">
<h4>Keep in DOM (destroyPopupOnHide=false)</h4>
<p><small>Popup kept in DOM for performance (faster re-open)</small></p>
<ejs-dropdowntree [fields]='fields'
[destroyPopupOnHide]='false'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
`,
styles: [`
.example { margin: 20px; }
`],
standalone: true,
imports: [DropDownTreeModule]
})
export class DestroyPopupComponent {
public fields = { /* ... */ };
}10. sortOrder - Sort Data Items
Sorts the items in the popup list.
@Component({
selector: 'app-sort-order',
template: `
<div class="example">
<h4>No Sorting (sortOrder='None') - Default</h4>
<ejs-dropdowntree [fields]='fields'
sortOrder='None'
placeholder='Select an item'>
</ejs-dropdowntree>
</div>
<div class="example">
<h4>Ascending Order (sortOrder='Ascending')</h4>
<ejs-dropdowntree [fields]='fields'
sortOrder='Ascending'
placeholder='Select an item (A-Z)'>
</ejs-dropdowntree>
</div>
<div class="example">
<h4>Descending Order (sortOrder='Descending')</h4>
<ejs-dropdowntree [fields]='fields'
sortOrder='Descending'
placeholder='Select an item (Z-A)'>
</ejs-dropdowntree>
</div>
`,
styles: [`
.example { margin: 20px; }
`],
standalone: true,
imports: [DropDownTreeModule]
})
export class SortOrderComponent {
public fields = {
dataSource: [
{ id: 1, name: 'Zebra' },
{ id: 2, name: 'Apple' },
{ id: 3, name: 'Mango' },
{ id: 4, name: 'Banana' }
],
value: 'id',
text: 'name'
};
}11. htmlAttributes - Add Custom HTML Attributes
Add custom HTML attributes for accessibility and data attributes.
@Component({
selector: 'app-html-attributes',
template: `
<ejs-dropdowntree [fields]='fields'
[htmlAttributes]='customAttributes'
placeholder='Select a department'>
</ejs-dropdowntree>
`,
standalone: true,
imports: [DropDownTreeModule]
})
export class HtmlAttributesComponent {
public fields = {
dataSource: [
{ id: 1, name: 'Engineering', dept_code: 'ENG' },
{ id: 2, name: 'Marketing', dept_code: 'MKT' },
{ id: 3, name: 'Sales', dept_code: 'SAL' }
],
value: 'id',
text: 'name'
};
public customAttributes = {
'aria-label': 'Department selection dropdown',
'aria-describedby': 'dept-help-text',
'data-testid': 'department-selector',
'data-component': 'dropdown-tree',
'role': 'combobox',
'aria-expanded': 'false',
'aria-controls': 'popup-list'
};
}Combined Example - Multiple Properties
Real-world example combining multiple properties:
@Component({
selector: 'app-combined-properties',
template: `
<div class="container">
<h3>Advanced Configuration Example</h3>
<ejs-dropdowntree #advancedDDT
[fields]='fields'
[(value)]='selectedValue'
[showCheckBox]='true'
[showClearButton]='true'
[wrapText]='true'
[readonly]='false'
mode='Box'
[allowFiltering]='true'
filterBarPlaceholder='Search departments...'
filterType='Contains'
[ignoreAccent]='true'
[floatLabelType]='floatLabel'
[enablePersistence]='true'
[destroyPopupOnHide]='false'
[enableHtmlSanitizer]='true'
[changeOnBlur]='true'
[treeSettings]='{ autoCheck: true }'
[zIndex]='1005'
[htmlAttributes]='accessibilityAttrs'
sortOrder='Ascending'
(change)='onSelectionChange($event)'
(beforeOpen)='onBeforeOpen($event)'>
</ejs-dropdowntree>
<div class="info">
<p><strong>Selected Items:</strong> {{ selectedValue | json }}</p>
<p><strong>Item Count:</strong> {{ itemCount }}</p>
</div>
</div>
`,
styles: [`
.container { max-width: 600px; margin: 20px auto; }
.info { margin-top: 20px; padding: 15px; background: #f5f5f5; border-radius: 4px; }
`],
standalone: true,
imports: [DropDownTreeModule, CommonModule, JsonPipe]
})
export class CombinedPropertiesComponent {
@ViewChild('advancedDDT') dropdown!: DropDownTreeComponent;
public selectedValue: string[] = [];
public itemCount = 0;
public floatLabel: FloatLabelType = 'Auto';
public fields = {
dataSource: [
{
id: 1,
name: 'Engineering Department',
hasChild: true,
expanded: true,
children: [
{ id: 2, pid: 1, name: 'Frontend Development' },
{ id: 3, pid: 1, name: 'Backend Development' },
{ id: 4, pid: 1, name: 'DevOps' }
]
},
{
id: 5,
name: 'Sales Department',
hasChild: true,
children: [
{ id: 6, pid: 5, name: 'Sales Team North' },
{ id: 7, pid: 5, name: 'Sales Team South' }
]
}
],
value: 'id',
text: 'name',
hasChildren: 'hasChild',
expanded: 'expanded',
child: 'children'
};
public accessibilityAttrs = {
'aria-label': 'Department and team selection',
'data-testid': 'org-structure-selector'
};
onSelectionChange(event: any) {
this.itemCount = event.value ? event.value.length : 0;
console.log('Selection changed:', this.selectedValue);
}
onBeforeOpen(event: any) {
console.log('Popup about to open');
}
}---
Common Events
Events triggered during component lifecycle and user interactions.
Selection Events
| Event | Args | When | Usage |
|---|---|---|---|
change | DdtChangeEventArgs | Selection changes | Track value changes |
select | DdtSelectEventArgs | Item selected | Item-specific logic |
Popup Events
| Event | Args | When | Usage |
|---|---|---|---|
open | DdtPopupEventArgs | Popup opens (after animation) | Initialize popup content |
close | DdtPopupEventArgs | Popup closes (after animation) | Cleanup resources |
beforeOpen | DdtBeforeOpenEventArgs | Before popup opens | Validate/prevent opening |
Data Events
| Event | Args | When | Usage |
|---|---|---|---|
dataBound | DdtDataBoundEventArgs | Data loaded | Update UI after data load |
actionFailure | Object | Remote data fetch fails | Handle errors |
filtering | DdtFilteringEventArgs | Filter text entered | Custom filtering logic |
Component Events
| Event | Args | When | Usage |
|---|---|---|---|
created | Object | Component created | Initialize |
destroyed | Object | Component destroyed | Cleanup |
User Interaction Events
| Event | Args | When | Usage |
|---|---|---|---|
focus | DdtFocusEventArgs | Component gets focus | Track focus state |
blur | Object | Component loses focus | Validate on blur |
keyPress | DdtKeyPressEventArgs | Key pressed | Custom key handling |
Events Example
@Component({
selector: 'app-events',
template: `
<ejs-dropdowntree #ddt
[fields]='fields'
(change)='onSelectionChange($event)'
(open)='onPopupOpen($event)'
(close)='onPopupClose($event)'
(focus)='onFocus($event)'
(blur)='onBlur($event)'
(dataBound)='onDataBound($event)'
(actionFailure)='onDataError($event)'>
</ejs-dropdowntree>
`,
standalone: true,
imports: [DropDownTreeModule]
})
export class EventsComponent {
@ViewChild('ddt') dropdowntree!: DropDownTreeComponent;
public fields = { /* ... */ };
onSelectionChange(event: any) {
console.log('Value changed to:', event.value);
}
onPopupOpen(event: any) {
console.log('Popup opened');
}
onPopupClose(event: any) {
console.log('Popup closed');
}
onFocus(event: any) {
console.log('Component focused');
}
onBlur(event: any) {
console.log('Component lost focus');
}
onDataBound(event: any) {
console.log('Data bound, record count:', event.data.length);
}
onDataError(event: any) {
console.error('Data load failed:', event);
}
}---
Methods
Programmatic control of the component using ViewChild reference.
| Method | Parameters | Returns | Purpose |
|---|---|---|---|
showPopup() | - | void | Open the dropdown popup |
hidePopup() | - | void | Close the dropdown popup |
refresh() | - | void | Refresh component and data |
clearSelection() | - | void | Clear all selected values |
expandAll() | - | void | Expand all tree nodes |
collapseAll() | - | void | Collapse all tree nodes |
Methods Example
@Component({
selector: 'app-methods',
template: `
<ejs-dropdowntree #ddt [fields]='fields'></ejs-dropdowntree>
<div class="button-group">
<button (click)='openDropdown()'>Open</button>
<button (click)='closeDropdown()'>Close</button>
<button (click)='clearAll()'>Clear Selection</button>
<button (click)='expandAll()'>Expand All</button>
<button (click)='collapseAll()'>Collapse All</button>
<button (click)='getSelected()'>Get Selected</button>
</div>
<p>Selected: {{ selectedValues }}</p>
`,
standalone: true,
imports: [DropDownTreeModule, CommonModule]
})
export class MethodsComponent {
@ViewChild('ddt') dropdowntree!: DropDownTreeComponent;
public fields = { /* ... */ };
public selectedValues = '';
openDropdown() {
this.dropdowntree.showPopup();
}
closeDropdown() {
this.dropdowntree.hidePopup();
}
clearAll() {
this.dropdowntree.value = null;
}
expandAll() {
this.dropdowntree.expandAll();
}
collapseAll() {
this.dropdowntree.collapseAll();
}
getSelected() {
this.selectedValues = this.dropdowntree.value || 'None';
}
}---
Complete Properties Reference
Comprehensive Property List (All Properties)
| Category | Properties | Type | Default |
|---|---|---|---|
| Data Binding | fields, value, text | FieldsModel, string/string[], string | - |
| Enable/Disable | enabled, readonly | boolean | true, false |
| Display | placeholder, width, popupHeight, popupWidth | string | - |
| Selection UI | showCheckBox, allowMultiSelection, mode | boolean, Mode enum | false, "Default" |
| Checkbox Labels | showSelectAll, selectAllText, unSelectAllText | boolean, string | false, "Select All", "Unselect All" |
| Multi-Select Display | delimiterChar, customTemplate, wrapText | string | "," |
| Visual Styling | cssClass, showDropDownIcon, showClearButton, zIndex | string, boolean, number | - |
| Filtering | allowFiltering, filterBarPlaceholder, filterType | boolean, string, TreeFilterType | false |
| Filter Behavior | ignoreCase, ignoreAccent | boolean | true, false |
| Localization | locale, enableRtl, floatLabelType | string, boolean, FloatLabelType | "en-US", false |
| State Management | enablePersistence, destroyPopupOnHide | boolean | false, true |
| Security | enableHtmlSanitizer | boolean | true |
| Change Behavior | changeOnBlur | boolean | true |
| Sorting | sortOrder | SortOrder enum | "None" |
| HTML Attributes | htmlAttributes | Record<string, string> | {} |
Detailed Property Descriptions
Core Data Properties
// fields: FieldsModel - Maps data properties to component
fields: {
dataSource: array | DataManager, // Data source
value: string, // Unique ID field
text: string, // Display text field
child?: string, // Child items array (hierarchical)
parentValue?: string, // Parent ID field (self-referential)
hasChildren?: string, // Has children indicator field
expanded?: string, // Expanded state field
selected?: string, // Pre-selected state field
iconCss?: string, // Icon CSS class field
imageUrl?: string, // Image URL field
tooltip?: string, // Tooltip text field
selectable?: string, // Selectable state field
htmlAttributes?: string // HTML attributes field
}
// value: string | string[] - Selected item value(s)
value: '1' // Single selection
value: ['1', '2', '3'] // Multiple selections (with checkboxes)
// text: string | string[] - Display text of selected item(s)
text: 'Category Name' // Single selection
text: ['Item1', 'Item2'] // Multiple selectionsDisplay Properties
// placeholder: string - Hint text when no item selected
placeholder: 'Select a category'
// width: string | number - Component width
width: '300px' // String with unit
width: 300 // Number (interpreted as pixels)
width: '100%' // Percentage
// popupHeight: string | number - Dropdown popup height
popupHeight: '300px' // Fixed height with scrolling
popupHeight: 300
// popupWidth: string | number - Dropdown popup width (default: component width)
popupWidth: '400px'
popupWidth: '100%'
// cssClass: string - CSS classes for styling
cssClass: 'custom-dropdown-tree my-custom-style'
// showDropDownIcon: boolean - Show/hide dropdown arrow
showDropDownIcon: true
// showClearButton: boolean - Show/hide clear (X) button
showClearButton: true
// zIndex: number - Z-index stacking order
zIndex: 1005
// wrapText: boolean - Wrap text to multiple lines
wrapText: trueSelection Properties
// showCheckBox: boolean - Enable checkboxes for multi-selection
showCheckBox: true // Shows checkboxes before each item
// allowMultiSelection: boolean - Allow Ctrl+Click multi-selection
allowMultiSelection: true
// showSelectAll: boolean - Show "Select All" checkbox in header
showSelectAll: true
// selectAllText: string - Label when Select All is unchecked
selectAllText: 'Check All'
// unSelectAllText: string - Label when Select All is checked
unSelectAllText: 'Uncheck All'
// mode: Mode enum - How selected items display
mode: 'Default' // Shows "N items selected"
mode: 'Box' // Shows chips/tags
mode: 'Delimiter' // Shows comma-separated text
mode: 'Custom' // Uses customTemplate
// delimiterChar: string - Separator for Delimiter mode
delimiterChar: ',' // Default
delimiterChar: ' | ' // Custom separator
delimiterChar: ';'
// customTemplate: string | Function - Template for Custom mode
customTemplate: '${value.length} selected'
// changeOnBlur: boolean - Fire change event on blur (false = on every selection)
changeOnBlur: true // Default: only on blur
changeOnBlur: false // Fire on every selectionFiltering Properties
// allowFiltering: boolean - Enable search bar in popup
allowFiltering: true
// filterBarPlaceholder: string - Placeholder in filter bar
filterBarPlaceholder: 'Search items...'
// filterType: TreeFilterType - Filter matching strategy
filterType: 'StartsWith' // Match beginning of text
filterType: 'EndsWith' // Match end of text
filterType: 'Contains' // Match anywhere in text
// ignoreCase: boolean - Case-insensitive search
ignoreCase: true // 'ABC' matches 'abc'
// ignoreAccent: boolean - Ignore diacritical marks
ignoreAccent: true // 'café' matches 'cafe'
ignoreAccent: false // Exact accent matchingLocalization Properties
// locale: string - Language/culture code
locale: 'en' // English
locale: 'es' // Spanish
locale: 'fr' // French
locale: 'de' // German
locale: 'ar' // Arabic (with RTL)
// enableRtl: boolean - Right-to-left text direction
enableRtl: true // For Arabic, Hebrew, Urdu
// floatLabelType: FloatLabelType - Floating label behavior
floatLabelType: 'Never' // Label never floats
floatLabelType: 'Always' // Label always floats
floatLabelType: 'Auto' // Float on focus/valueState Management Properties
// enabled: boolean - Enable/disable component
enabled: true // Component enabled
enabled: false // Component disabled (grayed out)
// readonly: boolean - Read-only mode (popup still accessible)
readonly: false // Normal mode
readonly: true // Read-only, can't type
// enablePersistence: boolean - Save state to localStorage
enablePersistence: false // Default: no persistence
enablePersistence: true // Save value between page loads
// destroyPopupOnHide: boolean - Remove popup from DOM on hide
destroyPopupOnHide: true // Default: remove on hide
destroyPopupOnHide: false // Keep in DOM for performance
// enableHtmlSanitizer: boolean - Security: sanitize HTML in templates
enableHtmlSanitizer: true // Default: sanitize (safe)
enableHtmlSanitizer: false // Allow raw HTML (use with caution)
// sortOrder: SortOrder - Sort items
sortOrder: 'None' // No sorting (default)
sortOrder: 'Ascending' // A-Z
sortOrder: 'Descending' // Z-ATemplate Properties
// itemTemplate: string | Function - Template for each tree item
itemTemplate: '<div>${name} (${code})</div>'
// valueTemplate: string | Function - Template for selected display
valueTemplate: '<div>${name} - ${dept}</div>'
// headerTemplate: string | Function - Template above items
headerTemplate: '<div class="header">Select an item</div>'
// footerTemplate: string | Function - Template below items
footerTemplate: '<div class="footer">Total: ${count}</div>'
// noRecordsTemplate: string | Function - Template when no data
noRecordsTemplate: '<div>No items found</div>'
// actionFailureTemplate: string | Function - Template on error
actionFailureTemplate: '<div>Failed to load data</div>'HTML Attributes
// htmlAttributes: Record<string, string> - Add HTML attributes
htmlAttributes: {
'aria-label': 'Category selection',
'aria-describedby': 'cat-help',
'data-testid': 'category-dropdown'
}Best Practices
1. Correct Field Mapping
✓ Good: Clear, explicit field mapping matching your data structure
fields: {
dataSource: this.data,
value: 'employeeId', // Use descriptive names
text: 'employeeName',
parentValue: 'managerId',
hasChildren: 'hasReports'
}✗ Bad: Generic field names that don't match data
fields: {
dataSource: this.data,
value: 'id', // Generic, ambiguous
text: 'text', // Misleading
parentValue: 'parent'
}2. Performance Optimization
For Large Datasets (1000+ items):
// Enable lazy loading with remote data
treeSettings: {
loadOnDemand: true
},
fields: {
dataSource: new DataManager({ url: 'api/nodes' }),
hasChildren: 'hasChild', // Critical for lazy load
child: { /* child config */ }
}
// Use virtual scrolling in templates
popupHeight: '300px' // Fixed height triggers scroll3. Template Safety
✓ Good: Use Angular's interpolation safely
itemTemplate = '<div>${sanitize(name)}</div>';
enableHtmlSanitizer: true // Default security✗ Bad: Raw HTML that could contain XSS
itemTemplate = '<div>' + unsafeData + '</div>';4. Selection Validation
✓ Good: Validate selection before submission
onSubmit() {
if (!this.dropdowntree.value || this.dropdowntree.value.length === 0) {
this.showError('Please select at least one item');
return;
}
this.processSelection();
}5. Error Handling
✓ Good: Handle remote data failures
(actionFailure)='handleDataError($event)'
handleDataError(event: any) {
console.error('Data load failed:', event);
this.showNotification('Unable to load data. Please try again.');
}---
Troubleshooting
Data Not Displaying
Problem: Popup opens but no items visible
Solutions: 1. Verify field mappings - ensure value, text, and dataSource are correct 2. Check console for errors 3. Verify data structure matches field configuration 4. For hierarchical data, ensure parentValue or child is properly mapped
// Debug: Log the fields configuration
console.log('Fields:', this.fields);
console.log('Data:', this.data);Checkboxes Not Working
Problem: Checkboxes don't appear or don't function
Solutions: 1. Ensure showCheckBox: true is set 2. For auto-check, set treeSettings: { autoCheck: true } 3. Verify data has proper hierarchy (parent-child relationship) 4. Check that hasChildren field is correctly mapped
Remote Data Not Loading
Problem: DataManager fails to fetch data
Solutions: 1. Verify API endpoint URL is correct 2. Check CORS headers on server 3. Verify DataManager adaptor matches API type (ODataV4, RestAdapter, etc.) 4. Check network requests in browser DevTools 5. Implement actionFailure event handler for error logging
Template Not Rendering
Problem: Custom template shows raw text instead of formatted content
Solutions: 1. Use correct interpolation syntax: ${propertyName} 2. Ensure property names match data object 3. Use single quotes for strings: '${name}' 4. Test simple template first: '<div>${name}</div>'
---
Checkbox Features in Angular Dropdown Tree
Table of Contents
- Overview
- Enable Checkboxes
- Multi-Selection Behavior
- Auto-Check Functionality
- Select All Feature
- Checkbox State Management
- Code Examples
Overview
The Dropdown Tree checkbox feature enables multi-selection of tree items without affecting the dropdown's visual appearance. Users can check multiple items simultaneously across different hierarchical levels. The component supports three modes of checkbox behavior:
1. Independent - Each item checked/unchecked independently (default) 2. Auto-Check - Parent-child synchronization with hierarchical consistency 3. Select All - Convenient header checkbox to select/deselect all items at once
Enable Checkboxes
Enable checkboxes by setting the showCheckBox property to true:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-checkbox-example',
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[showCheckBox]='true'
placeholder='Select items (checkboxes enabled)'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class CheckboxExampleComponent {
public data = [
{ id: 1, name: 'Discover Music', hasChild: true, expanded: true },
{ id: 2, pid: 1, name: 'Hot Singles' },
{ id: 3, pid: 1, name: 'Rising Artists' },
{ id: 4, pid: 1, name: 'Live Music' },
{ id: 6, pid: 1, name: 'Best of 2017 So Far' },
{ id: 7, name: 'Sales and Events', hasChild: true },
{ id: 8, pid: 7, name: '100 Albums - $5 Each' },
{ id: 9, pid: 7, name: 'Hip-Hop and R&B Sale' },
{ id: 10, pid: 7, name: 'CD Deals' }
];
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
parentValue: 'pid',
hasChildren: 'hasChild'
};
}Result: A checkbox appears before each item text in the popup, allowing multi-selection without visual disruption to the compact dropdown UI.
Multi-Selection Behavior
When checkboxes are enabled (and autoCheck is false), each item can be independently checked or unchecked:
Example: Independent Checkbox Selection
@Component({
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[showCheckBox]='true'
(change)='onSelectionChanged($event)'></ejs-dropdowntree>`
})
export class IndependentCheckboxComponent {
public fields = { dataSource: this.data, /* ... */ };
onSelectionChanged(event: any) {
// Access selected items
const selectedItems = event.value; // Array of selected values
console.log('Selected:', selectedItems);
}
}Behavior:
- Checking a child item does NOT automatically check the parent
- Checking a parent item does NOT automatically check children
- Users have full control over selection combinations
- Display in input shows "2 item(s) selected" format
Use case: When selections are independent (e.g., selecting individual features to enable, not requiring parent-child consistency).
Auto-Check Functionality
Auto-check creates hierarchical checkbox behavior where parent and child selections are synchronized. Enable it through the treeSettings property:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-auto-check',
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[showCheckBox]='true'
[treeSettings]='{ autoCheck: true }'
placeholder='Select with hierarchical sync'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class AutoCheckComponent {
public data = [
{ id: 1, name: 'Discover Music', hasChild: true, expanded: true },
{ id: 2, pid: 1, name: 'Hot Singles' },
{ id: 3, pid: 1, name: 'Rising Artists' },
{ id: 4, pid: 1, name: 'Live Music' },
{ id: 7, name: 'Sales and Events', hasChild: true },
{ id: 8, pid: 7, name: '100 Albums - $5 Each' },
{ id: 9, pid: 7, name: 'Hip-Hop and R&B Sale' }
];
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
parentValue: 'pid',
hasChildren: 'hasChild'
};
}Auto-Check Rules
1. All children checked → Parent automatically checked
- When all child items are checked, the parent becomes fully checked
2. Some children checked → Parent becomes intermediate
- When only some children are checked, the parent shows a "partially filled" checkbox (intermediate state)
3. Parent checked → All children automatically checked
- Checking a parent automatically checks all its children recursively
4. Last child unchecked → Parent becomes unchecked
- When the last checked child is unchecked, the parent reverts to unchecked state
Example Scenario:
Initial state:
☐ Music
☐ Hot Singles
☐ Rising Artists
☐ Live Music
User checks "Hot Singles" and "Rising Artists":
☐ Music (becomes ◐ intermediate - 2/3 children checked)
☑ Hot Singles
☑ Rising Artists
☐ Live Music
User clicks parent checkbox:
☑ Music (now fully checked)
☑ Hot Singles
☑ Rising Artists
☑ Live Music (automatically checked)Use case: Hierarchical selections where checking a category should include all subcategories (permissions, product features, organizational units).
Select All Feature
The Select All feature adds a checkbox in the popup header to quickly select or deselect all items:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-select-all',
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[showCheckBox]='true'
[showSelectAll]='true'
selectAllText='Check All'
unSelectAllText='Uncheck All'
placeholder='Select with Select All option'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class SelectAllComponent {
public data = [
{ id: 1, name: 'Discover Music', hasChild: true, expanded: true },
{ id: 2, pid: 1, name: 'Hot Singles' },
{ id: 3, pid: 1, name: 'Rising Artists' },
{ id: 4, pid: 1, name: 'Live Music' },
{ id: 6, pid: 1, name: 'Best of 2017 So Far' },
{ id: 7, name: 'Sales and Events', hasChild: true },
{ id: 8, pid: 7, name: '100 Albums - $5 Each' },
{ id: 9, pid: 7, name: 'Hip-Hop and R&B Sale' },
{ id: 10, pid: 7, name: 'CD Deals' }
];
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
parentValue: 'pid',
hasChildren: 'hasChild'
};
}Select All Properties
| Property | Type | Default | Purpose |
|---|---|---|---|
showSelectAll | boolean | false | Enable/disable header checkbox |
selectAllText | string | "Select All" | Label when unchecked |
unSelectAllText | string | "Unselect All" | Label when checked |
Header behavior:
- Unchecked: Clicking selects all items + updates label to
unSelectAllText - Checked: Clicking deselects all items + updates label to
selectAllText - Partial: Shows intermediate state if some items are checked
Use case: For datasets with 5+ items where manual selection becomes tedious (bulk import/export, permission management).
Checkbox State Management
Accessing Selected Items
@Component({
selector: 'app-state-management',
template: `<ejs-dropdowntree id='dropdowntree'
#tree
[fields]='fields'
[showCheckBox]='true'></ejs-dropdowntree>
<button (click)='getSelectedItems()'>Get Selected</button>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class StateManagementComponent {
@ViewChild('tree') dropdowntree: DropDownTreeComponent;
public fields = { dataSource: this.data, /* ... */ };
getSelectedItems() {
// Access the dropdown tree component
const selectedValues = this.dropdowntree.value; // Array of checked item values
console.log('Checked items:', selectedValues);
}
}Pre-Selecting Items
Set selected: true in data to pre-check items:
public data = [
{ id: 1, name: 'Music', hasChild: true, selected: true }, // Pre-checked
{ id: 2, pid: 1, name: 'Hot Singles', selected: true }, // Pre-checked
{ id: 3, pid: 1, name: 'Rising Artists' }
];Note: When using auto-check with pre-selected items, ensure parent-child relationships are consistent or let auto-check synchronize them on load.
Programmatic Selection
@ViewChild('tree') dropdowntree: DropDownTreeComponent;
selectSpecificItems() {
// Programmatically set checked items
this.dropdowntree.value = [2, 3, 5]; // Check items with these values
}Intermediate State Detection
Auto-check intermediate states help users understand partial parent selection:
☐ No children checked → unchecked
◐ Some children checked → intermediate (visually distinct)
☑ All children checked → fully checkedThe intermediate checkbox is purely visual and updates automatically when auto-check is enabled.
Best Practices:
- Use auto-check for hierarchical permission/category selection
- Use independent checkboxes for unrelated multi-selection
- Use Select All for 5+ item lists to reduce selection time
- Combine with form validation to ensure valid selection states
Data Binding in Angular Dropdown Tree
Table of Contents
- Overview
- Local Data Binding
- Hierarchical Data Structure
- Self-Referential Data Structure
- Remote Data Binding
- DataManager Setup
- OData and ODataV4 Adaptors
- WebAPI Adaptor
- Field Mapping
- Code Examples
Overview
The Dropdown Tree supports flexible data binding from multiple sources: local arrays, hierarchical structures, self-referential data, and remote services. Data binding is configured through the fields property and the dataSource property, which determines the data source type and field mappings.
The component automatically handles hierarchical relationships and can optimize performance through lazy loading with loadOnDemand for remote data.
Local Data Binding
Hierarchical Data Structure
Hierarchical data contains nested arrays of JSON objects representing parent-child relationships through nesting. The actual field names vary (e.g., nodeChild, countries, children) depending on your data structure:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-hierarchical-data',
template: `<ejs-dropdowntree id='dropdownTree'
[fields]='fields'
placeholder='Select continent and country'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class HierarchicalDataComponent {
public data = [
{
code: 'AF', name: 'Africa', countries: [
{ code: 'NGA', name: 'Nigeria' },
{ code: 'EGY', name: 'Egypt' },
{ code: 'ZAF', name: 'South Africa' }
]
},
{
code: 'AS', name: 'Asia', expanded: true, countries: [
{ code: 'CHN', name: 'China' },
{ code: 'IND', name: 'India', selected: true },
{ code: 'JPN', name: 'Japan' }
]
},
{
code: 'EU', name: 'Europe', countries: [
{ code: 'DNK', name: 'Denmark' },
{ code: 'FIN', name: 'Finland' },
{ code: 'AUT', name: 'Austria' }
]
},
{
code: 'NA', name: 'North America', countries: [
{ code: 'USA', name: 'United States of America' },
{ code: 'CUB', name: 'Cuba' },
{ code: 'MEX', name: 'Mexico' }
]
},
{
code: 'SA', name: 'South America', countries: [
{ code: 'BRA', name: 'Brazil' },
{ code: 'COL', name: 'Colombia' },
{ code: 'ARG', name: 'Argentina' }
]
}
];
// Map: value → code, text → name, child → countries
public fields = {
dataSource: this.data,
value: 'code',
text: 'name',
child: 'countries'
};
}When to use: Use hierarchical data when you have naturally nested structures like:
- Categories with subcategories
- Departments with subdivisions
- Continents with countries (as shown above)
- Parent folders with subfolders
Key properties:
value: Unique identifier for each nodetext: Display name for each nodechild: Array property containing child itemsexpanded: Optional—set to true to expand by defaultselected: Optional—set to true to pre-select item
Self-Referential Data Structure
Self-referential data contains a flat array where parent-child relationships are defined through reference fields:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-self-referential',
template: `<ejs-dropdowntree id='dropdownTree'
[fields]='fields'
placeholder='Select a category'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class SelfReferentialComponent {
public data = [
{ id: 1, name: 'Discover Music', hasChild: true, expanded: true },
{ id: 2, pid: 1, name: 'Hot Singles' },
{ id: 3, pid: 1, name: 'Rising Artists' },
{ id: 4, pid: 1, name: 'Live Music' },
{ id: 6, pid: 1, name: 'Best of 2017 So Far' },
{ id: 7, name: 'Sales and Events', hasChild: true },
{ id: 8, pid: 7, name: '100 Albums - $5 Each' },
{ id: 9, pid: 7, name: 'Hip-Hop and R&B Sale' },
{ id: 10, pid: 7, name: 'CD Deals' },
{ id: 11, name: 'Categories', hasChild: true },
{ id: 12, pid: 11, name: 'Songs' },
{ id: 13, pid: 11, name: 'Bestselling Albums' },
{ id: 14, pid: 11, name: 'New Releases' },
{ id: 15, pid: 11, name: 'Bestselling Songs' }
];
// Map: value → id, parentValue → pid (flat structure)
// Root items have pid undefined (not assigned) or handled by component
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
parentValue: 'pid',
hasChildren: 'hasChild'
};
}When to use: Self-referential data is better for:
- Database-sourced hierarchies (easier to flatten from queries)
- Dynamic tree structures (easier to manipulate flat arrays)
- Complex hierarchies (avoids deeply nested objects)
- API responses that return flat arrays
Key properties:
value: Unique identifier for each nodetext: Display name for each nodeparentValue: Parent node's ID (null for root items)hasChildren: Boolean indicating if node has children (for UI optimization)
Root level items: Set parentValue to null or omit the field entirely for items without parents.
Remote Data Binding
DataManager Setup
Remote data binding fetches hierarchical data from web services using DataManager. This is essential for large datasets, reducing initial load and bandwidth consumption:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { DataManager, ODataV4Adaptor, Query } from '@syncfusion/ej2-data';
@Component({
selector: 'app-remote-data',
template: `<ejs-dropdowntree id='dropdownTree' [fields]='fields'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class RemoteDataComponent {
// DataManager with remote service endpoint
public data = new DataManager({
url: 'url',
adaptor: new ODataV4Adaptor,
crossDomain: true
});
// First level: Employees
public query = new Query()
.from('Employees')
.select('EmployeeID,FirstName,Title')
.take(5);
// Second level: Orders related to each employee
public query1 = new Query()
.from('Orders')
.select('OrderID,EmployeeID,ShipName')
.take(5);
// Field mapping with nested queries
public fields = {
dataSource: this.data,
query: this.query,
value: 'EmployeeID',
text: 'FirstName',
hasChildren: 'EmployeeID',
child: {
dataSource: this.data,
query: this.query1,
value: 'OrderID',
parentValue: 'EmployeeID',
text: 'ShipName'
}
};
}When to use: Remote binding is appropriate for:
- Large hierarchical datasets (100+ items)
- Data requiring authentication
- Real-time data updates
- Server-side filtering and searching
OData and ODataV4 Adaptors
ODataAdaptor (default for DataManager):
const data = new DataManager({
url: 'url',
adaptor: new ODataAdaptor,
crossDomain: true
});ODataV4Adaptor (modern OData standard):
const data = new DataManager({
url: 'url',
adaptor: new ODataV4Adaptor,
crossDomain: true
});Use ODataV4 for new projects; it's the current standard with better filtering and query support.
WebAPI Adaptor
For RESTful Web APIs following OData conventions:
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
const data = new DataManager({
url: 'url',
adaptor: new WebApiAdaptor,
crossDomain: true
});Field Mapping
Field mapping defines how component properties bind to data properties. Required fields depend on data type:
Local Hierarchical Data
fields: {
dataSource: localArray,
value: 'id', // Unique identifier
text: 'name', // Display text
child: 'children' // Array of child items
}Local Self-Referential Data
fields: {
dataSource: flatArray,
value: 'id', // Unique identifier
text: 'name', // Display text
parentValue: 'pid', // Parent ID reference
hasChildren: 'hasChild' // Boolean or count
}Remote Data with Query
fields: {
dataSource: new DataManager({ url: '...' }),
query: new Query().from('Table').select('...'),
value: 'id',
text: 'name',
hasChildren: 'id', // or boolean field name
child: {
dataSource: new DataManager({ url: '...' }),
query: new Query().from('ChildTable'),
value: 'childId',
parentValue: 'parentId',
text: 'childName'
}
}Optional fields:
expanded: Pre-expand nodesselected: Pre-select itemsimageUrl: Icon/avatar for itemstooltip: Hover text for items
Choose the data binding approach based on data source (local vs. remote), structure (hierarchical vs. flat), and dataset size.
Getting Started with Angular Dropdown Tree
Table of Contents
- Setup Angular Environment
- Installing Syncfusion Package
- Module Registration
- CSS Configuration
- Basic Component Integration
- Binding Local Data
- Running the Application
- Minimal Setup Example
These dependencies are automatically installed with the main package.
Setup Angular Environment
Install Angular CLI
First, install the Angular CLI globally:
npm install -g @angular/cliTo install a specific version:
npm install -g @angular/cli@21.0.0Create a New Application
Generate a new Angular application using the CLI:
ng new syncfusion-dropdown-tree-appWhen prompted, configure:
- Stylesheet format: CSS, SCSS, or Less
- Routing: Enable if needed for your application
- Server-side rendering (SSR): Choose based on your deployment needs
Navigate to your project:
cd syncfusion-dropdown-tree-appNote: Angular 20+ generates simpler file structures (app.ts, app.html, app.css). Earlier versions use .component.ts suffixes.
Installing Syncfusion Package
Ivy Library Distribution (Angular 12+)
For Angular 12 and above, use the Ivy library distribution package:
npm install @syncfusion/ej2-angular-dropdowns --saveThis is compatible with modern Angular versions (20+) and recommended for new projects.
Legacy ngcc Package (Angular < 12)
For Angular versions below 12, use the ngcc (Angular compatibility compiler) package:
npm install @syncfusion/ej2-angular-dropdowns@ngcc --saveUpdate your package.json:
{
"dependencies": {
"@syncfusion/ej2-angular-dropdowns": "20.2.38-ngcc"
}
}Module Registration
Import the DropDownTreeModule in your Angular component or module:
Standalone Component (Angular 14+)
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-dropdown-tree',
template: `<ejs-dropdowntree id='dropdowntree'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class AppComponent {}NgModule (Traditional)
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, DropDownTreeModule],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule {}CSS Configuration
Add Syncfusion CSS files to your src/styles.css:
@import 'node_modules/@syncfusion/ej2-base/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-buttons/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-dropdowns/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-navigations/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-inputs/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-popups/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-lists/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-angular-dropdowns/styles/material3.css';Alternative themes: Replace material3.css with:
bootstrap5.csstailwind.cssfluent.cssfabric.css
Using Custom Resource Generator (CRG):
For optimized, combined styles, use Syncfusion's CRG.
Basic Component Integration
Create a simple Dropdown Tree component in src/app/app.component.ts:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-root',
template: `<ejs-dropdowntree id='dropdowntree'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class AppComponent {}Binding Local Data
The real power of Dropdown Tree is hierarchical data binding. Here's a complete example:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-root',
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
placeholder='Select a category'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class AppComponent {
// Hierarchical data: each parent has a 'nodeChild' array
public data = [
{
nodeId: '01', nodeText: 'Music',
nodeChild: [
{ nodeId: '01-01', nodeText: 'Gouttes.mp3' }
]
},
{
nodeId: '02', nodeText: 'Videos', expanded: true,
nodeChild: [
{ nodeId: '02-01', nodeText: 'Naturals.mp4' },
{ nodeId: '02-02', nodeText: 'Wild.mpeg' }
]
},
{
nodeId: '03', nodeText: 'Documents',
nodeChild: [
{ nodeId: '03-01', nodeText: 'Environment Pollution.docx' },
{ nodeId: '03-02', nodeText: 'Global Warming.ppt' },
{ nodeId: '03-03', nodeText: 'Social Network.pdf' }
]
}
];
// Map data fields: value → nodeId, text → nodeText, child → nodeChild
public fields = {
dataSource: this.data,
value: 'nodeId',
text: 'nodeText',
child: 'nodeChild'
};
}Field mapping explained:
value: Unique identifier for each item (e.g.,nodeId)text: Display text shown in the tree (e.g.,nodeText)child: Array property containing child items (e.g.,nodeChild)
Running the Application
Start the development server:
ng serve --openThis will: 1. Compile your Angular application 2. Start a local development server (typically at http://localhost:4200) 3. Automatically open the application in your default browser
You should see the Dropdown Tree component rendered with the hierarchical data categories (Music, Videos, Documents).
Tip: The development server watches for file changes and automatically reloads when you modify code.
Minimal Setup Example
For a quick start with minimal configuration:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-minimal',
template: `<ejs-dropdowntree [fields]='fields' placeholder='Select'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class MinimalComponent {
public data = [
{ id: '1', text: 'Item 1', child: [{ id: '1-1', text: 'Item 1.1' }] },
{ id: '2', text: 'Item 2' }
];
public fields = { dataSource: this.data, value: 'id', text: 'text', child: 'child' };
}This is the bare minimum needed to render a functional Dropdown Tree component.
Troubleshooting
Issue: "DropDownTreeModule not found"
- Solution: Verify
@syncfusion/ej2-angular-dropdownsis installed:npm list @syncfusion/ej2-angular-dropdowns
Issue: Styles not applied
- Solution: Check CSS imports in
styles.css. Ensure all required Syncfusion CSS files are imported.
Issue: Data not displaying
- Solution: Verify field mappings in the
fieldsproperty match your data structure (value, text, child properties).
Issue: "Cannot find module '@syncfusion/ej2-data'"
- Solution: Install data module:
npm install @syncfusion/ej2-data --save
Localization in Angular Dropdown Tree
The Dropdown Tree component supports comprehensive localization to adapt text, messages, and user interface elements for different cultures and languages. This enables seamless integration into multi-language applications by customizing all user-facing strings according to specific cultural requirements.
Table of Contents
- Localization Keys and Default Messages
- Default Locale Configuration
- Customizing Locale-Specific Strings
- noRecordsTemplate Localization
- actionFailureTemplate Localization
- overflowCountTemplate Localization
- totalCountTemplate Localization
- Best Practices for Localization
- Language Support Example
Localization Keys and Default Messages
The component's default locale is en (English). The following table describes all localization keys and their corresponding default messages:
| Key | Default Text | Usage Context |
|---|---|---|
noRecordsTemplate | "No records found" | Displayed when no data matches filters or data source is empty |
actionFailureTemplate | "Request failed" | Shown when data loading operations fail at remote server |
overflowCountTemplate | "+${count} more.." | Appears when multiple items are selected and display shows summary count |
totalCountTemplate | "${count} selected" | Displays total number of selected items in multi-selection scenarios |
Default Locale Configuration
By default, the component uses English (en). All user-facing messages appear in English unless explicitly localized.
Default English messages:
{
noRecordsTemplate: "No records found",
actionFailureTemplate: "Request failed",
overflowCountTemplate: "+${count} more..",
totalCountTemplate: "${count} selected"
}Customizing Locale-Specific Strings
You can customize individual locale strings by setting the locale culture and providing custom message values:
Method 1: Override Specific Properties
For single component customization, directly set properties:
import { Component } from '@angular/core';
import { DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-localization',
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[noRecordsTemplate]='noRecordsMsg'
[actionFailureTemplate]='actionFailureMsg'
[showCheckBox]='true'
[mode]='mode'
[customTemplate]='customTemplate'></ejs-dropdowntree>`,
standalone: true,
imports: [DropDownTreeModule, FormsModule, ReactiveFormsModule]
})
export class LocalizationComponent {
public data = [
{ id: 1, name: 'Music', hasChild: true },
{ id: 2, pid: 1, name: 'Hot Singles' }
];
public fields = { dataSource: this.data, value: 'id', text: 'name', parentValue: 'pid', hasChildren: 'hasChild' };
// Custom localized messages for Spanish
public noRecordsMsg = '❌ No se encontraron registros';
public actionFailureMsg = '⚠️ Error al cargar datos';
// Multi-selection template in Spanish
public mode = 'Custom';
public customTemplate = '${value.length} elemento(s) seleccionado(s)';
}Result: When no items match a filter, users see: ❌ No se encontraron registros instead of English text.
Method 2: Global Locale Configuration
For application-wide localization, define translations in a service and inject them:
// locale.service.ts
import { Injectable } from '@angular/core';
export interface LocaleStrings {
noRecordsTemplate: string;
actionFailureTemplate: string;
overflowCountTemplate: string;
totalCountTemplate: string;
}
@Injectable({ providedIn: 'root' })
export class LocaleService {
private locales: { [key: string]: LocaleStrings } = {
en: {
noRecordsTemplate: 'No records found',
actionFailureTemplate: 'Request failed',
overflowCountTemplate: '+${count} more..',
totalCountTemplate: '${count} selected'
},
es: {
noRecordsTemplate: 'No se encontraron registros',
actionFailureTemplate: 'Error en la solicitud',
overflowCountTemplate: '+${count} más..',
totalCountTemplate: '${count} seleccionado(s)'
},
fr: {
noRecordsTemplate: 'Aucun enregistrement trouvé',
actionFailureTemplate: 'Échec de la requête',
overflowCountTemplate: '+${count} de plus..',
totalCountTemplate: '${count} sélectionné(s)'
},
de: {
noRecordsTemplate: 'Keine Datensätze gefunden',
actionFailureTemplate: 'Anfrage fehlgeschlagen',
overflowCountTemplate: '+${count} weitere..',
totalCountTemplate: '${count} ausgewählt'
}
};
getLocale(culture: string): LocaleStrings {
return this.locales[culture] || this.locales['en'];
}
}
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { LocaleService } from './locale.service';
@Component({
selector: 'app-root',
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[noRecordsTemplate]='currentLocale.noRecordsTemplate'
[actionFailureTemplate]='currentLocale.actionFailureTemplate'
[customTemplate]='customTemplate'></ejs-dropdowntree>`
})
export class AppComponent implements OnInit {
public currentLocale: any;
public customTemplate: string;
constructor(private localeService: LocaleService) {}
ngOnInit() {
// Get current user's culture (from browser, user settings, or config)
const culture = 'es'; // Example: Spanish
this.currentLocale = this.localeService.getLocale(culture);
// Update template for multi-selection display
if (culture === 'es') {
this.customTemplate = '${value.length} elemento(s) seleccionado(s)';
}
}
public fields = { /* ... */ };
}noRecordsTemplate Localization
This message appears when the data source is empty or no items match the current filter:
@Component({
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[noRecordsTemplate]='getNoRecordsMessage()'></ejs-dropdowntree>`
})
export class NoRecordsComponent {
private culture = 'es'; // Spanish example
getNoRecordsMessage(): string {
const messages: { [key: string]: string } = {
en: '❌ No records found',
es: '❌ No se encontraron registros',
fr: '❌ Aucun enregistrement trouvé'
};
return messages[this.culture] || messages['en'];
}
public fields = { /* ... */ };
}Scenarios:
- User performs a search that returns no results
- Data source is fetched but empty
- Initial state with no data provided
actionFailureTemplate Localization
This message appears when remote data fetch operations fail (network errors, timeout, server errors):
import { DataManager, ODataV4Adaptor } from '@syncfusion/ej2-data';
@Component({
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[actionFailureTemplate]='getActionFailureMessage()'></ejs-dropdowntree>`
})
export class ActionFailureComponent {
private culture = 'fr'; // French example
getActionFailureMessage(): string {
const messages: { [key: string]: string } = {
en: '⚠️ Request failed - please try again',
es: '⚠️ La solicitud falló - por favor intente nuevamente',
fr: '⚠️ La requête a échoué - veuillez réessayer'
};
return messages[this.culture] || messages['en'];
}
public data = new DataManager({
url: 'url',
adaptor: new ODataV4Adaptor,
crossDomain: true
});
public fields = { dataSource: this.data, /* ... */ };
}Scenarios:
- Remote API unreachable
- Network timeout during data fetch
- Server returns error status
- CORS issues prevent data loading
overflowCountTemplate Localization
This message appears when multiple items are selected but the display is limited to showing a count instead of all selected item names:
@Component({
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[showCheckBox]='true'
[mode]='mode'
[customTemplate]='getCustomTemplate()'></ejs-dropdowntree>`
})
export class OverflowCountComponent {
private culture = 'de'; // German example
getCustomTemplate(): string {
// Template showing overflow when too many items selected
const templates: { [key: string]: string } = {
en: '${value.length > 3 ? value.length + " items" : value.join(", ")}',
es: '${value.length > 3 ? value.length + " elementos" : value.join(", ")}',
de: '${value.length > 3 ? value.length + " Elemente" : value.join(", ")}',
fr: '${value.length > 3 ? value.length + " éléments" : value.join(", ")}'
};
return templates[this.culture] || templates['en'];
}
public mode = 'Custom';
public fields = { /* ... */ };
}Scenarios:
- 3+ items selected and display space is limited
- Custom template shows count overflow message
- Tooltips can display full selected item list
totalCountTemplate Localization
This message displays the total count of selected items when using multi-selection:
@Component({
template: `<ejs-dropdowntree id='dropdowntree'
[fields]='fields'
[showCheckBox]='true'
[mode]='mode'
[customTemplate]='getTotalCountTemplate()'></ejs-dropdowntree>`
})
export class TotalCountComponent {
private culture = 'it'; // Italian example
getTotalCountTemplate(): string {
const templates: { [key: string]: string } = {
en: 'Total selected: ${value.length}',
es: 'Total seleccionado: ${value.length}',
it: 'Totale selezionato: ${value.length}',
pt: 'Total selecionado: ${value.length}'
};
return templates[this.culture] || templates['en'];
}
public mode = 'Custom';
public fields = { /* ... */ };
}Scenarios:
- User selects multiple items with checkboxes
- Display shows running total of selected items
- Used in forms where item count is important (bulk operations, imports)
Best Practices for Localization
1. Centralize Translations: Use a service or configuration file for all localization strings 2. Match Browser/User Locale: Detect user's preferred language from browser settings or user profile 3. Provide Fallback: Always fall back to English if a locale isn't available 4. Test with RTL: If supporting RTL languages (Arabic, Hebrew), test layout and text direction 5. Use Locale Codes: Follow standard locale codes (en, es, fr, de, it, pt, ja, zh, etc.) 6. Document Translations: Maintain clear documentation of all supported locales 7. Update Consistently: When adding new locales, update all template properties
Language Support Example
// Complete multi-language support
const SUPPORTED_LOCALES = {
en: 'English',
es: 'Español',
fr: 'Français',
de: 'Deutsch',
it: 'Italiano',
pt: 'Português',
ja: '日本語',
zh: '中文'
};
// Get user's preferred locale
function getUserLocale(): string {
const browserLang = navigator.language.split('-')[0];
return SUPPORTED_LOCALES[browserLang] ? browserLang : 'en';
}Methods and Events Reference - Angular Dropdown Tree
Table of Contents
- Component Methods
- Selection Events
- Popup Events
- Data Events
- Component Lifecycle Events
- User Interaction Events
- Event Arguments Reference
- Complete Example
- Code Examples - Advanced Scenarios
---
Component Methods
Methods provide programmatic control over the Dropdown Tree component. Access them via ViewChild reference to the component.
showPopup()
Purpose: Programmatically open the dropdown popup.
Syntax:
showPopup(): voidExample:
@Component({
selector: 'app-methods',
template: `
<ejs-dropdowntree #ddt [fields]='fields'></ejs-dropdowntree>
<button (click)='openDropdown()'>Open Dropdown</button>
`,
standalone: true,
imports: [DropDownTreeModule, ButtonModule]
})
export class MethodsComponent {
@ViewChild('ddt') dropdowntree!: DropDownTreeComponent;
public fields = { /* ... */ };
openDropdown() {
this.dropdowntree.showPopup();
}
}Use Cases:
- Open dropdown on custom button click
- Auto-open on page load for first-time users
- Open dropdown after validation
- Open popup in response to other component events
---
hidePopup()
Purpose: Programmatically close the dropdown popup.
Syntax:
hidePopup(): voidExample:
@ViewChild('ddt') dropdowntree!: DropDownTreeComponent;
closeDropdown() {
this.dropdowntree.hidePopup();
}
autoCloseOnDelay() {
setTimeout(() => {
this.dropdowntree.hidePopup();
}, 3000); // Close after 3 seconds
}---
refresh()
Purpose: Refresh component data and UI rendering. Useful after dynamic data changes.
Syntax:
refresh(): voidExample:
@ViewChild('ddt') dropdowntree!: DropDownTreeComponent;
refreshDropdownData() {
// Modify data dynamically
this.data.push({
id: 100,
name: 'New Item',
hasChild: false
});
// Refresh component to display new data
this.dropdowntree.refresh();
}When to Use:
- After adding/removing items programmatically
- After remote data updates
- After filtering or sorting data
- After locale/theme changes
---
clearSelection()
Purpose: Clear all selected items and reset the component value to null.
Syntax:
clearSelection(): voidExample:
@ViewChild('ddt') dropdowntree!: DropDownTreeComponent;
clearAll() {
this.dropdowntree.clearSelection();
// Component now shows placeholder text
}
clearSelectionOnClose() {
this.dropdowntree.clearSelection();
this.dropdowntree.hidePopup();
}Use Cases:
- Reset form on "Clear" button click
- Clear selection before data reload
- Reset UI after submission
- Undo user selection
---
expandAll()
Purpose: Expand all parent nodes in the tree hierarchy. Child nodes become visible.
Syntax:
expandAll(): voidExample:
@ViewChild('ddt') dropdowntree!: DropDownTreeComponent;
expandAllNodes() {
this.dropdowntree.expandAll();
// All parent nodes expand, children become visible
}
expandOnOpen(event: any) {
// Auto-expand all when popup opens
this.dropdowntree.expandAll();
}Use Cases:
- Expand tree on first popup open
- Show full hierarchy for overview
- Expand after search
- Expand all for keyboard navigation
---
collapseAll()
Purpose: Collapse all parent nodes in the tree hierarchy. Children are hidden.
Syntax:
collapseAll(): voidExample:
@ViewChild('ddt') dropdowntree!: DropDownTreeComponent;
collapseAllNodes() {
this.dropdowntree.collapseAll();
// All parent nodes collapse, only root items visible
}
collapseOnClose() {
this.dropdowntree.collapseAll();
this.dropdowntree.hidePopup();
}Use Cases:
- Collapse tree to see root items only
- Clean up UI before taking screenshot
- Collapse after item selection
- Collapse for compact display
---
Selection Events
Selection events fire when user selects or deselects items.
change
Triggers: When selection changes (item selected/deselected or value programmatically set)
Event Arguments: DdtChangeEventArgs
interface DdtChangeEventArgs {
e: ChangeEventArgs; // Original change event
value: string | string[]; // Currently selected value(s)
text: string | string[]; // Display text of selected item(s)
item: any; // Selected data item
itemData: any; // Item data details
isInteracted: boolean; // True if user-triggered, false if programmatic
previousValue: any; // Previously selected value
previousText: any; // Previously selected text
changeOnBlur: boolean; // True if event fires on blur
}Example:
@Component({
template: `<ejs-dropdowntree #ddt
[fields]='fields'
(change)='onSelectionChange($event)'></ejs-dropdowntree>`
})
export class ChangeEventComponent {
public fields = { /* ... */ };
onSelectionChange(event: any) {
console.log('Selected value:', event.value);
console.log('Selected text:', event.text);
console.log('Full item:', event.item);
console.log('User triggered:', event.isInteracted);
// Update form
this.selectedItem = event.item;
this.formValue = event.value;
}
}Practical Use Cases:
- Save selection to local storage
- Validate selection
- Update dependent fields
- Trigger form submission
- Analytics/logging
---
select
Triggers: When user selects an item by clicking/tapping in the popup
Event Arguments: DdtSelectEventArgs
interface DdtSelectEventArgs {
e: PointerEvent; // Browser pointer event
item: any; // Selected data item
itemData: any; // Complete item data
value: string; // Selected value
text: string; // Selected text
node: HTMLElement; // DOM element of selected item
nodeData: TreeNodeData; // Tree node metadata
}Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(select)='onItemSelect($event)'></ejs-dropdowntree>`
})
export class SelectEventComponent {
public fields = { /* ... */ };
onItemSelect(event: any) {
console.log('Item selected:', event.text);
console.log('Item value:', event.value);
// Item-specific logic
if (event.value === 'special-item') {
this.handleSpecialItem(event.item);
}
}
}---
Popup Events
Popup events fire during popup open/close operations.
open
Triggers: When popup opens (after animation completes)
Event Arguments: DdtPopupEventArgs
interface DdtPopupEventArgs {
e: Event; // Original popup event
popup: HTMLElement; // Popup DOM element
items: HTMLElement[]; // Array of item elements
}Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(open)='onPopupOpen($event)'></ejs-dropdowntree>`
})
export class PopupOpenComponent {
onPopupOpen(event: any) {
console.log('Popup opened');
// Focus first item
const firstItem = event.items[0];
if (firstItem) firstItem.focus();
}
}---
close
Triggers: When popup closes (after animation completes)
Event Arguments: DdtPopupEventArgs
Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(close)='onPopupClose($event)'></ejs-dropdowntree>`
})
export class PopupCloseComponent {
onPopupClose(event: any) {
console.log('Popup closed');
// Cleanup resources
this.stopPolling();
}
}---
beforeOpen
Triggers: Before popup opens (before animation starts)
Event Arguments: DdtBeforeOpenEventArgs
interface DdtBeforeOpenEventArgs {
e: Event; // Original event
cancel: boolean; // Set true to prevent opening
}Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(beforeOpen)='onBeforeOpen($event)'></ejs-dropdowntree>`
})
export class BeforeOpenComponent {
onBeforeOpen(event: any) {
// Validate before opening
if (!this.isUserAuthorized()) {
event.cancel = true;
this.showAuthError();
}
}
}Use Cases:
- Validate user permissions before opening
- Load data dynamically before opening
- Prevent opening under certain conditions
- Log analytics about popup interactions
---
Data Events
Data events relate to data loading and binding.
dataBound
Triggers: When data source is loaded and rendered in the tree
Event Arguments: DdtDataBoundEventArgs
interface DdtDataBoundEventArgs {
e: Event; // Original event
data: any[]; // Loaded data array
count: number; // Number of items loaded
}Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(dataBound)='onDataBound($event)'></ejs-dropdowntree>`
})
export class DataBoundComponent {
onDataBound(event: any) {
console.log(`Data loaded: ${event.data.length} items`);
this.isLoading = false;
this.updateItemCount(event.count);
}
}---
actionFailure
Triggers: When remote data fetch fails (network error, timeout, API error)
Event Arguments: Error object
Example:
import { DataManager, ODataV4Adaptor } from '@syncfusion/ej2-data';
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(actionFailure)='onDataError($event)'></ejs-dropdowntree>`
})
export class ActionFailureComponent {
public data = new DataManager({
url: 'url',
adaptor: new ODataV4Adaptor
});
public fields = { dataSource: this.data, /* ... */ };
onDataError(event: any) {
console.error('Data loading failed:', event);
this.showErrorNotification('Failed to load data. Please try again.');
}
}---
filtering
Triggers: When user types in the filter bar (when allowFiltering is true)
Event Arguments: DdtFilteringEventArgs
interface DdtFilteringEventArgs {
e: Event; // Original event
text: string; // Filter text entered
cancel: boolean; // Set true to prevent filtering
}Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
[allowFiltering]='true'
(filtering)='onFilter($event)'></ejs-dropdowntree>`
})
export class FilteringComponent {
onFilter(event: any) {
console.log('Filtering for:', event.text);
// Custom filtering logic
if (event.text.length < 3) {
event.cancel = true; // Require minimum 3 characters
}
}
}---
Component Lifecycle Events
created
Triggers: When component is fully initialized and ready
Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(created)='onComponentCreated()'></ejs-dropdowntree>`
})
export class CreatedComponent {
onComponentCreated() {
console.log('Dropdown Tree component initialized');
this.initializeRelatedComponents();
}
}---
destroyed
Triggers: When component is destroyed (on component cleanup)
Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(destroyed)='onComponentDestroyed()'></ejs-dropdowntree>`
})
export class DestroyedComponent {
onComponentDestroyed() {
console.log('Dropdown Tree destroyed');
this.cleanup();
}
}---
User Interaction Events
focus
Triggers: When component input receives focus
Event Arguments: DdtFocusEventArgs
Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(focus)='onFocus($event)'></ejs-dropdowntree>`
})
export class FocusComponent {
onFocus(event: any) {
console.log('Component focused');
// Highlight component or show hints
}
}---
blur
Triggers: When component input loses focus
Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(blur)='onBlur($event)'></ejs-dropdowntree>`
})
export class BlurComponent {
onBlur(event: any) {
console.log('Component lost focus');
// Validate selected value
// Save to form
}
}---
keyPress
Triggers: When user presses a key in the component
Event Arguments: DdtKeyPressEventArgs
interface DdtKeyPressEventArgs {
e: KeyboardEvent; // Keyboard event
key: string; // Key pressed
action: string; // Action triggered (select, open, close, etc.)
cancel: boolean; // Set true to cancel key action
}Example:
@Component({
template: `<ejs-dropdowntree [fields]='fields'
(keyPress)='onKeyPress($event)'></ejs-dropdowntree>`
})
export class KeyPressComponent {
onKeyPress(event: any) {
if (event.key === 'Enter') {
// Submit form on Enter
this.submitForm();
}
}
}---
Event Arguments Reference
DdtChangeEventArgs
Fired when selection changes.
| Property | Type | Description |
|---|---|---|
value | string \ | string[] |
text | string \ | string[] |
item | any | Selected data item object |
itemData | any | Complete item data |
isInteracted | boolean | True if user-triggered, false if programmatic |
previousValue | any | Previously selected value |
previousText | any | Previously selected text |
DdtSelectEventArgs
Fired when user clicks an item.
| Property | Type | Description |
|---|---|---|
value | string | Selected value |
text | string | Selected text |
item | any | Selected data item |
node | HTMLElement | DOM element of selected item |
e | PointerEvent | Browser pointer event |
DdtPopupEventArgs
Fired when popup opens/closes.
| Property | Type | Description |
|---|---|---|
popup | HTMLElement | Popup DOM element |
items | HTMLElement[] | Array of tree item elements |
DdtBeforeOpenEventArgs
Fired before popup opens.
| Property | Type | Description |
|---|---|---|
cancel | boolean | Set true to prevent opening |
e | Event | Original event |
---
Complete Example
import { Component, ViewChild } from '@angular/core';
import { DropDownTreeComponent, DropDownTreeModule } from '@syncfusion/ej2-angular-dropdowns';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-methods-events',
template: `
<div class="demo-section">
<div class="control-section">
<h3>Dropdown Tree Methods and Events Demo</h3>
<ejs-dropdowntree #myDDT
[fields]='fields'
[showCheckBox]='true'
placeholder='Select items'
(change)='onValueChange($event)'
(open)='onOpen($event)'
(close)='onClose($event)'
(select)='onSelect($event)'
(focus)='onFocus($event)'
(blur)='onBlur($event)'>
</ejs-dropdowntree>
<div class="button-group">
<button ejs-button (click)='expandAll()'>Expand All</button>
<button ejs-button (click)='collapseAll()'>Collapse All</button>
<button ejs-button (click)='openPopup()'>Open</button>
<button ejs-button (click)='closePopup()'>Close</button>
<button ejs-button (click)='clear()'>Clear</button>
<button ejs-button (click)='refresh()'>Refresh</button>
</div>
<div class="info-panel">
<h4>Event Log:</h4>
<div class="log-content">
<p *ngFor='let log of eventLog'>{{ log }}</p>
</div>
</div>
</div>
</div>
`,
styles: [`
.button-group { margin-top: 20px; display: flex; gap: 10px; flex-wrap: wrap; }
.info-panel { margin-top: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 4px; }
.log-content { height: 150px; overflow-y: auto; background: #f5f5f5; padding: 10px; font-size: 12px; }
`],
standalone: true,
imports: [DropDownTreeModule, ButtonModule, FormsModule, ReactiveFormsModule]
})
export class MethodsEventsComponent {
@ViewChild('myDDT') dropdowntree!: DropDownTreeComponent;
public data = [
{ id: 1, name: 'Engineering', hasChild: true, expanded: true },
{ id: 2, pid: 1, name: 'Frontend' },
{ id: 3, pid: 1, name: 'Backend' },
{ id: 4, name: 'HR', hasChild: true },
{ id: 5, pid: 4, name: 'Recruitment' }
];
public fields = {
dataSource: this.data,
value: 'id',
text: 'name',
parentValue: 'pid',
hasChildren: 'hasChild'
};
public eventLog: string[] = [];
expandAll() {
this.dropdowntree.expandAll();
this.addLog('Expanded all nodes');
}
collapseAll() {
this.dropdowntree.collapseAll();
this.addLog('Collapsed all nodes');
}
openPopup() {
this.dropdowntree.showPopup();
}
closePopup() {
this.dropdowntree.hidePopup();
}
clear() {
this.dropdowntree.clearSelection();
this.addLog('Selection cleared');
}
refresh() {
this.dropdowntree.refresh();
this.addLog('Component refreshed');
}
onValueChange(event: any) {
this.addLog(`Value changed: ${event.value}`);
}
onOpen(event: any) {
this.addLog('Popup opened');
}
onClose(event: any) {
this.addLog('Popup closed');
}
onSelect(event: any) {
this.addLog(`Item selected: ${event.text}`);
}
onFocus(event: any) {
this.addLog('Component focused');
}
onBlur(event: any) {
this.addLog('Component lost focus');
}
private addLog(message: string) {
const timestamp = new Date().toLocaleTimeString();
this.eventLog.unshift(`[${timestamp}] ${message}`);
if (this.eventLog.length > 10) {
this.eventLog.pop();
}
}
}Key Takeaways:
- Use methods for programmatic control (open/close, expand/collapse, clear)
- Use selection events to track and respond to user choices
- Use popup events for UI coordination
- Use data events for error handling and data monitoring
- Use lifecycle events for initialization and cleanup