The Dropdown class creates a dropdown select input for choosing one or more options from a list. It extends SelectableNode and supports both single and multiple selection modes, with options that can be loaded synchronously, asynchronously, or from an Observable.
Inheritance
ObjectBase → NodeBase → SelectableNode → Dropdown
Constructor
new Dropdown(
id: string,
placeholder?: string,
value?: OptionChild[] | Promise<OptionChild[]> | Observable<OptionChild[]>,
selected?: string,
multiple?: boolean,
singleLine?: boolean,
icon?: string,
errorMessage?: string,
disabled?: boolean,
validator?: Validator,
asyncValidator?: AsyncValidator,
action?: Action | Action[]
)
Parameters
The unique identifier for the dropdown in the DOM.
The placeholder text displayed when no option is selected.
value
OptionChild[] | Promise<OptionChild[]> | Observable<OptionChild[]>
The list of options to display in the dropdown. Can be:
- An array of
OptionChild objects
- A Promise that resolves to an array of
OptionChild objects
- An Observable that emits an array of
OptionChild objects
The initial selected value (the value property of an OptionChild).
Whether multiple options can be selected.
Whether the dropdown should be displayed in a single line layout.
Material icon name to display alongside the dropdown.
Custom error message to display when validation fails.
Whether the dropdown is disabled.
Synchronous validator(s) to apply to the dropdown. Can be a single ValidatorFn, an array of ValidatorFn, or null.
Asynchronous validator(s) to apply to the dropdown. Can be a single AsyncValidatorFn, an array of AsyncValidatorFn, or null.
Action(s) to execute when the dropdown selection changes.
Properties
| Property | Type | Description |
|---|
id | string | The unique identifier for the dropdown |
placeholder | string | The placeholder text |
type | NodeType | The type of node (set to 'dropdown') |
value | OptionChild[] | The list of available options |
selectedValue | string | The currently selected value(s) |
multiple | boolean | Whether multiple selection is enabled |
singleLine | boolean | Single line layout flag |
icon | string | Material icon name |
errorMessage | string | Custom error message |
disabled | boolean | Disabled state |
validator | Validator | AbstractControlOptions | Synchronous validators |
asyncValidator | AsyncValidatorFn | Asynchronous validator |
action | Action | Action[] | Associated actions |
hint | string | Hint text displayed below the dropdown |
Methods
getOptions()
Returns the list of options for the dropdown.
getOptions(): OptionChild[]
apply()
Inherited from ObjectBase. Applies additional properties to the node instance.
apply(options: Partial<Dropdown>): this
getNativeElement()
Returns the native DOM element for this dropdown.
getNativeElement(): HTMLElement | null
OptionChild Class
Options for the dropdown are defined using the OptionChild class:
new OptionChild(label: string, value: any)
label - The text displayed to the user
value - The actual value stored when the option is selected
Usage Examples
Basic Dropdown
import { Dropdown, OptionChild } from 'mat-dynamic-form';
import { Validators } from '@angular/forms';
const countryDropdown = new Dropdown('country', 'Select Country', [
new OptionChild('United States', 'US'),
new OptionChild('Canada', 'CA'),
new OptionChild('Mexico', 'MX'),
new OptionChild('United Kingdom', 'UK')
]).apply({
icon: 'public',
validator: Validators.required
});
Dropdown with Initial Selection
const languageDropdown = new Dropdown('language', 'Language', [
new OptionChild('English', 'en'),
new OptionChild('Spanish', 'es'),
new OptionChild('French', 'fr'),
new OptionChild('German', 'de')
], 'en').apply({ // 'en' is pre-selected
icon: 'language',
hint: 'Select your preferred language'
});
Multiple Selection Dropdown
const skillsDropdown = new Dropdown('skills', 'Skills', [
new OptionChild('JavaScript', 'js'),
new OptionChild('TypeScript', 'ts'),
new OptionChild('Python', 'python'),
new OptionChild('Java', 'java'),
new OptionChild('C#', 'csharp')
], undefined, true).apply({ // true enables multiple selection
icon: 'code',
hint: 'Select all that apply',
validator: Validators.required
});
Dropdown with Async Options (Promise)
import { Dropdown, OptionChild } from 'mat-dynamic-form';
// Function that returns a Promise
function fetchCountries(): Promise<OptionChild[]> {
return fetch('/api/countries')
.then(response => response.json())
.then(data => data.map(country =>
new OptionChild(country.name, country.code)
));
}
const countryDropdown = new Dropdown('country', 'Country', fetchCountries()).apply({
icon: 'public',
validator: Validators.required,
hint: 'Loading countries...'
});
Dropdown with Observable Options
import { Dropdown, OptionChild } from 'mat-dynamic-form';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
export class MyComponent {
constructor(private http: HttpClient) {}
createDropdown() {
const cities$: Observable<OptionChild[]> = this.http.get('/api/cities').pipe(
map((data: any[]) => data.map(city =>
new OptionChild(city.name, city.id)
))
);
const cityDropdown = new Dropdown('city', 'City', cities$).apply({
icon: 'location_city',
validator: Validators.required
});
return cityDropdown;
}
}
Dropdown with Action
const stateDropdown = new Dropdown('state', 'State', [
new OptionChild('California', 'CA'),
new OptionChild('Texas', 'TX'),
new OptionChild('New York', 'NY'),
new OptionChild('Florida', 'FL')
]).apply({
icon: 'map',
action: {
type: 'valueChange',
onEvent: (param) => {
console.log('Selected state:', param.event);
// Load cities for the selected state
loadCitiesForState(param.event, param.structure);
}
}
});
function loadCitiesForState(stateCode: string, structure: FormStructure) {
fetch(`/api/cities?state=${stateCode}`)
.then(response => response.json())
.then(cities => {
const cityOptions = cities.map(city => new OptionChild(city.name, city.id));
const cityDropdown = structure.getNodeById('city');
if (cityDropdown) {
cityDropdown.value = cityOptions;
}
});
}
Cascading Dropdowns
import { FormStructure, Dropdown, OptionChild } from 'mat-dynamic-form';
import { Validators } from '@angular/forms';
const formStructure = new FormStructure();
formStructure.nodes = [
// Country dropdown
new Dropdown('country', 'Country', [
new OptionChild('United States', 'US'),
new OptionChild('Canada', 'CA'),
new OptionChild('Mexico', 'MX')
]).apply({
validator: Validators.required,
action: {
type: 'valueChange',
onEvent: (param) => {
// Fetch and update states based on country
const stateDropdown = param.structure.getNodeById('state');
if (stateDropdown) {
stateDropdown.value = getStatesForCountry(param.event);
stateDropdown.selectedValue = null; // Reset selection
}
// Clear city dropdown
const cityDropdown = param.structure.getNodeById('city');
if (cityDropdown) {
cityDropdown.value = [];
cityDropdown.selectedValue = null;
cityDropdown.disabled = true;
}
}
}
}),
// State dropdown
new Dropdown('state', 'State', []).apply({
disabled: true,
validator: Validators.required,
action: {
type: 'valueChange',
onEvent: (param) => {
// Fetch and update cities based on state
const cityDropdown = param.structure.getNodeById('city');
if (cityDropdown) {
cityDropdown.value = getCitiesForState(param.event);
cityDropdown.selectedValue = null;
cityDropdown.disabled = false;
}
}
}
}),
// City dropdown
new Dropdown('city', 'City', []).apply({
disabled: true,
validator: Validators.required
})
];
function getStatesForCountry(countryCode: string): OptionChild[] {
// Return states based on country
// This would typically be an API call
return [];
}
function getCitiesForState(stateCode: string): OptionChild[] {
// Return cities based on state
// This would typically be an API call
return [];
}
Role Selection
const roleDropdown = new Dropdown('role', 'Role', [
new OptionChild('Administrator', 'admin'),
new OptionChild('Manager', 'manager'),
new OptionChild('Employee', 'employee'),
new OptionChild('Guest', 'guest')
]).apply({
icon: 'admin_panel_settings',
validator: Validators.required,
hint: 'Select user role',
action: {
type: 'valueChange',
onEvent: (param) => {
console.log('Role selected:', param.event);
// Show/hide additional fields based on role
if (param.event === 'admin') {
// Add admin-specific fields
}
}
}
});
Priority Dropdown
const priorityDropdown = new Dropdown('priority', 'Priority', [
new OptionChild('🔴 Critical', 'critical'),
new OptionChild('🟠 High', 'high'),
new OptionChild('🟡 Medium', 'medium'),
new OptionChild('🟢 Low', 'low')
], 'medium').apply({
icon: 'priority_high',
validator: Validators.required
});
Multi-Select with Select All
const interestsDropdown = new Dropdown('interests', 'Interests', [
new OptionChild('Technology', 'tech'),
new OptionChild('Sports', 'sports'),
new OptionChild('Music', 'music'),
new OptionChild('Travel', 'travel'),
new OptionChild('Food', 'food'),
new OptionChild('Art', 'art')
], undefined, true).apply({
icon: 'interests',
hint: 'Select multiple interests'
});
Dynamic Options Based on Another Field
import { Input, Dropdown, OptionChild } from 'mat-dynamic-form';
const searchInput = new Input('search', 'Search').apply({
icon: 'search',
action: {
type: 'valueChange',
onEvent: (param) => {
const query = param.event;
if (query && query.length >= 3) {
// Fetch filtered options
fetch(`/api/search?q=${query}`)
.then(response => response.json())
.then(results => {
const dropdown = param.structure.getNodeById('results');
if (dropdown) {
dropdown.value = results.map(r => new OptionChild(r.name, r.id));
}
});
}
}
}
});
const resultsDropdown = new Dropdown('results', 'Results', []).apply({
hint: 'Search results will appear here'
});
Best Practices
-
Clear Labels: Use descriptive placeholder text and labels
-
Validation: Add
Validators.required for mandatory selections
-
Icons: Use relevant icons to make dropdowns more recognizable
-
Hints: Provide helpful hints, especially for multiple selection
-
Loading States: Handle loading states for async options gracefully
-
Error Handling: Implement error handling for failed async loads
-
Default Selection: Set appropriate default values when applicable
-
Option Limits: For very large lists, consider using autocomplete instead
-
Cascading Updates: Clear dependent dropdowns when parent selection changes
-
Accessibility: Ensure keyboard navigation works properly
- RadioGroup - Single selection with radio buttons
- AutoComplete - Searchable dropdown with filtering
- Checkbox - Boolean input for single option
- Switch - Toggle switch for boolean values