Angular ng-select - All in One UI Select, Multiselect and Autocomplete library providing comprehensive select component functionality
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Angular ng-select provides a comprehensive template directive system allowing complete customization of every visual aspect of the select component. These directives enable developers to create custom layouts, styling, and behavior for options, labels, headers, footers, and various UI states.
Template directives for customizing how items and selections are displayed.
/**
* Template directive for customizing individual option display in dropdown
* Access to: item, item.label, item.value, item.disabled, index, searchTerm
*/
@Directive({ selector: '[ng-option-tmp]' })
export class NgOptionTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for customizing selected item label display
* Access to: item, clear function, item.label, item.value
*/
@Directive({ selector: '[ng-label-tmp]' })
export class NgLabelTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for customizing multi-select label display
* Access to: items array, clear function
*/
@Directive({ selector: '[ng-multi-label-tmp]' })
export class NgMultiLabelTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Directive for displaying and styling item labels with automatic HTML escaping
* Alternative to using bindLabel property - provides more control over display
*/
@Directive({ selector: '[ngItemLabel]' })
export class NgItemLabelDirective implements OnChanges {
/** The label text to display */
@Input() ngItemLabel: string;
/** Whether to escape HTML in the label (default: true) */
@Input() escape: boolean = true;
constructor(private element: ElementRef<HTMLElement>) {}
ngOnChanges(changes: SimpleChanges): void;
}
/**
* Template directive for customizing option group display
* Access to: item (group), item.label, item.children
*/
@Directive({ selector: '[ng-optgroup-tmp]' })
export class NgOptgroupTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for customizing tag display when addTag is enabled
* Access to: searchTerm, item
*/
@Directive({ selector: '[ng-tag-tmp]' })
export class NgTagTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}Usage Examples:
@Component({
template: `
<!-- Custom option template with icons and descriptions -->
<ng-select [(ngModel)]="selectedUser" [clearable]="false">
<ng-option *ngFor="let user of users" [value]="user">
<ng-container *ngOptionTemplateDirective="let item=item; let index=index">
<div class="user-option">
<img [src]="item.avatar" width="24" height="24" class="avatar">
<div class="user-info">
<div class="name">{{ item.name }}</div>
<div class="email">{{ item.email }}</div>
</div>
<span class="role-badge">{{ item.role }}</span>
</div>
</ng-container>
</ng-option>
<!-- Custom selected label template -->
<ng-label-tmp ng-label-tmp let-item="item" let-clear="clear">
<img [src]="item.avatar" width="18" height="18">
{{ item.name }}
<span class="clear-btn" (click)="clear(item)">×</span>
</ng-label-tmp>
</ng-select>
<!-- Multi-select with custom multi-label -->
<ng-select [(ngModel)]="selectedUsers" [multiple]="true">
<ng-option *ngFor="let user of users" [value]="user">
{{ user.name }}
</ng-option>
<ng-multi-label-tmp ng-multi-label-tmp let-items="items" let-clear="clear">
<div class="multi-label">
<span class="selected-count">{{ items.length }} users selected</span>
<span class="clear-all" (click)="clear()">Clear all</span>
</div>
</ng-multi-label-tmp>
</ng-select>
`
})
export class CustomTemplatesComponent {
selectedUser: any;
selectedUsers: any[] = [];
users = [
{
id: 1,
name: 'Alice Johnson',
email: 'alice@example.com',
avatar: '/avatars/alice.jpg',
role: 'Admin'
},
// ... more users
];
}Template directives for customizing the overall layout and structure of the dropdown.
/**
* Template directive for dropdown header content
* Access to: searchTerm, items
*/
@Directive({ selector: '[ng-header-tmp]' })
export class NgHeaderTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for dropdown footer content
* Access to: searchTerm, items
*/
@Directive({ selector: '[ng-footer-tmp]' })
export class NgFooterTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}Usage Examples:
@Component({
template: `
<ng-select [(ngModel)]="selectedItem" [items]="items" bindLabel="name">
<!-- Custom header with search stats -->
<ng-header-tmp>
<div class="dropdown-header">
<h4>Select an Item</h4>
<small *ngIf="searchTerm">
Showing results for "{{ searchTerm }}"
</small>
</div>
</ng-header-tmp>
<!-- Custom footer with action buttons -->
<ng-footer-tmp>
<div class="dropdown-footer">
<button type="button" (click)="addNewItem()">Add New Item</button>
<button type="button" (click)="selectAll()">Select All</button>
</div>
</ng-footer-tmp>
</ng-select>
`
})
export class HeaderFooterComponent {
selectedItem: any;
searchTerm: string = '';
items = [/* ... */];
addNewItem() {
// Custom logic to add new item
}
selectAll() {
// Custom logic to select all items
}
}Template directives for customizing various component states and UI elements.
/**
* Template directive for placeholder display
* Access to: placeholder text
*/
@Directive({ selector: '[ng-placeholder-tmp]' })
export class NgPlaceholderTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for "not found" message display
* Access to: searchTerm, notFoundText
*/
@Directive({ selector: '[ng-notfound-tmp]' })
export class NgNotFoundTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for "type to search" message display
* Access to: typeToSearchText
*/
@Directive({ selector: '[ng-typetosearch-tmp]' })
export class NgTypeToSearchTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for loading text display
* Access to: loadingText
*/
@Directive({ selector: '[ng-loadingtext-tmp]' })
export class NgLoadingTextTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for loading spinner display
* Access to: loading state
*/
@Directive({ selector: '[ng-loadingspinner-tmp]' })
export class NgLoadingSpinnerTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}
/**
* Template directive for clear button customization
* Access to: clear function
*/
@Directive({ selector: '[ng-clearbutton-tmp]' })
export class NgClearButtonTemplateDirective {
constructor(public template: TemplateRef<any>) {}
}Usage Examples:
@Component({
template: `
<ng-select
[(ngModel)]="selectedItem"
[items]="items"
bindLabel="name"
[loading]="isLoading"
[clearable]="true">
<!-- Custom placeholder with icon -->
<ng-placeholder-tmp>
<div class="custom-placeholder">
<i class="search-icon"></i>
Choose your favorite option...
</div>
</ng-placeholder-tmp>
<!-- Custom not found message -->
<ng-notfound-tmp ng-notfound-tmp let-searchTerm="searchTerm">
<div class="not-found">
<i class="warning-icon"></i>
<p>No results found for "{{ searchTerm }}"</p>
<button type="button" (click)="suggestAlternatives(searchTerm)">
Show suggestions
</button>
</div>
</ng-notfound-tmp>
<!-- Custom loading spinner -->
<ng-loadingspinner-tmp>
<div class="custom-loader">
<div class="spinner"></div>
<span>Loading awesome data...</span>
</div>
</ng-loadingspinner-tmp>
<!-- Custom clear button -->
<ng-clearbutton-tmp ng-clearbutton-tmp let-clear="clear">
<button type="button"
class="custom-clear-btn"
(click)="clear()"
title="Clear selection">
<i class="clear-icon"></i>
</button>
</ng-clearbutton-tmp>
</ng-select>
`
})
export class StateTemplatesComponent {
selectedItem: any;
items: any[] = [];
isLoading: boolean = false;
suggestAlternatives(searchTerm: string) {
// Custom logic for showing alternative suggestions
}
}Each template directive provides access to specific context variables:
// Context variables available in templates
interface NgOptionContext {
$implicit: any; // The item
item: any; // The item (same as $implicit)
index: number; // Item index
searchTerm: string; // Current search term
}
interface NgLabelContext {
$implicit: any; // The selected item
item: any; // The selected item
clear: (item?: any) => void; // Function to clear item
}
interface NgMultiLabelContext {
items: any[]; // Array of selected items
clear: () => void; // Function to clear all items
}
interface NgNotFoundContext {
$implicit: string; // The search term
searchTerm: string; // The search term
notFoundText: string; // The not found text
}
interface NgHeaderFooterContext {
searchTerm: string; // Current search term
items: any[]; // Current filtered items
}// Good: Use OnPush change detection with templates
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<ng-select [items]="items" bindLabel="name">
<ng-option-tmp ng-option-tmp let-item="item">
<div class="option">{{ item.name }}</div>
</ng-option-tmp>
</ng-select>
`
})
export class OptimizedTemplateComponent {}
// Good: Use trackBy for better performance with large lists
@Component({
template: `
<ng-select [items]="items" [trackByFn]="trackByFn">
<!-- templates -->
</ng-select>
`
})
export class TrackByComponent {
trackByFn = (index: number, item: any) => item.id;
}@Component({
template: `
<ng-select
[items]="items"
bindLabel="name"
ariaLabel="Select user"
labelForId="user-select">
<ng-option-tmp ng-option-tmp let-item="item" let-index="index">
<div
role="option"
[attr.aria-label]="item.name + ', ' + item.role"
[attr.aria-describedby]="'user-desc-' + index">
{{ item.name }} - {{ item.role }}
</div>
</ng-option-tmp>
</ng-select>
`
})
export class AccessibleTemplateComponent {}