Core package of ngx-formly - a dynamic (JSON powered) form library for Angular that brings unmatched maintainability to your application's forms
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Utilities for handling select field options with observable support, enabling dynamic option loading and transformation for select, radio, and checkbox fields.
Angular pipe for transforming and processing select options with support for observables, groups, and dynamic loading.
/**
* Pipe for processing select field options
*/
@Pipe({
name: 'formlySelectOptions',
pure: false
})
export class FormlySelectOptionsPipe implements PipeTransform {
/**
* Transform options for select fields with observable support
* @param options - Array of options, observable, or function returning options
* @param field - Optional field configuration for context
* @returns Observable of processed select options
*/
transform(options: any, field?: FormlyFieldConfig): Observable<FormlySelectOption[]>;
}Usage Examples:
// In a custom select field component
@Component({
selector: 'formly-field-select',
template: `
<select [formControl]="formControl" [formlyAttributes]="field">
<option value="">{{ props.placeholder || 'Select an option' }}</option>
<ng-container *ngFor="let option of props.options | formlySelectOptions:field | async">
<optgroup *ngIf="option.group" [label]="option.group">
<option
*ngFor="let item of option.children"
[value]="item.value"
[disabled]="item.disabled">
{{ item.label }}
</option>
</optgroup>
<option
*ngIf="!option.group"
[value]="option.value"
[disabled]="option.disabled">
{{ option.label }}
</option>
</ng-container>
</select>
`
})
export class FormlyFieldSelect extends FieldType<FieldTypeConfig<FormlyFieldSelectProps>> {}const fieldConfig: FormlyFieldConfig = {
key: 'country',
type: 'select',
props: {
label: 'Country',
placeholder: 'Select a country',
required: true,
options: [
{ label: 'United States', value: 'US' },
{ label: 'Canada', value: 'CA' },
{ label: 'United Kingdom', value: 'GB', disabled: false },
{ label: 'France', value: 'FR' },
{ label: 'Germany', value: 'DE' }
]
}
};import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({...})
export class DynamicSelectFormComponent {
constructor(private http: HttpClient) {}
getCountries(): Observable<FormlySelectOption[]> {
return this.http.get<any[]>('/api/countries').pipe(
map(countries => countries.map(country => ({
label: country.name,
value: country.code,
disabled: !country.active
})))
);
}
fields: FormlyFieldConfig[] = [
{
key: 'country',
type: 'select',
props: {
label: 'Country',
placeholder: 'Select a country',
required: true,
options: this.getCountries()
}
}
];
}const fieldWithGroups: FormlyFieldConfig = {
key: 'vehicle',
type: 'select',
props: {
label: 'Vehicle Type',
options: [
{
label: 'Cars',
group: true,
children: [
{ label: 'Toyota Camry', value: 'camry' },
{ label: 'Honda Accord', value: 'accord' },
{ label: 'BMW X5', value: 'bmw-x5' }
]
},
{
label: 'Motorcycles',
group: true,
children: [
{ label: 'Harley Davidson', value: 'harley' },
{ label: 'Yamaha', value: 'yamaha' }
]
}
]
}
};/**
* Legacy version of FormlySelectOptionsPipe for backward compatibility
* @deprecated Use FormlySelectOptionsPipe instead
*/
@Pipe({
name: 'formlySelectOptions',
pure: false
})
export class LegacyFormlySelectOptionsPipe extends FormlySelectOptionsPipe {}interface FormlySelectOption {
/** Display text for the option */
label: string;
/** Value to be stored in the form model */
value: any;
/** Whether this option is disabled */
disabled?: boolean;
/** Group name for grouped options */
group?: string;
/** Child options for grouped selections */
children?: FormlySelectOption[];
}
interface FormlySelectOptionGroup {
/** Group label */
label: string;
/** Indicates this is a group container */
group: true;
/** Options within this group */
children: FormlySelectOption[];
}
type FormlySelectOptions = (FormlySelectOption | FormlySelectOptionGroup)[];interface FormlyFieldSelectProps extends FormlyFieldProps {
/** Options for the select field */
options?:
| FormlySelectOptions
| Observable<FormlySelectOptions>
| ((field: FormlyFieldConfig) => FormlySelectOptions)
| ((field: FormlyFieldConfig) => Observable<FormlySelectOptions>);
/** Whether to allow multiple selections */
multiple?: boolean;
/** Placeholder text when no option is selected */
placeholder?: string;
/** Compare function for option values */
compareWith?: (o1: any, o2: any) => boolean;
/** Whether to select the first option by default */
selectAllOption?: string;
/** Custom option value property name */
valueProp?: string;
/** Custom option label property name */
labelProp?: string;
/** Custom option disabled property name */
disabledProp?: string;
/** Custom option group property name */
groupProp?: string;
}/**
* Function type for processing options
*/
type OptionProcessor = (
options: any,
field: FormlyFieldConfig
) => Observable<FormlySelectOption[]>;
/**
* Configuration for option transformation
*/
interface OptionTransformConfig {
/** Property name to use for option values */
valueProp?: string;
/** Property name to use for option labels */
labelProp?: string;
/** Property name to use for disabled state */
disabledProp?: string;
/** Property name to use for grouping */
groupProp?: string;
/** Custom transform function */
transform?: (item: any, index: number, array: any[]) => FormlySelectOption;
}import {
FormlySelectOptionsPipe,
FormlySelectOption,
FormlyFieldSelectProps
} from '@ngx-formly/core/select';The select functionality is included in the core module:
import { FormlyModule } from '@ngx-formly/core';
@NgModule({
imports: [
FormlyModule.forRoot()
]
})
export class AppModule {}@Component({...})
export class DependentSelectComponent {
form = new FormGroup({});
model = { country: '', state: '', city: '' };
fields: FormlyFieldConfig[] = [
{
key: 'country',
type: 'select',
props: {
label: 'Country',
placeholder: 'Select a country',
required: true,
options: [
{ label: 'United States', value: 'US' },
{ label: 'Canada', value: 'CA' }
]
}
},
{
key: 'state',
type: 'select',
props: {
label: 'State/Province',
placeholder: 'Select a state',
required: true,
options: []
},
expressions: {
'props.options': (field: FormlyFieldConfig) => {
const country = field.model?.country;
if (country === 'US') {
return [
{ label: 'California', value: 'CA' },
{ label: 'New York', value: 'NY' },
{ label: 'Texas', value: 'TX' }
];
} else if (country === 'CA') {
return [
{ label: 'Ontario', value: 'ON' },
{ label: 'Quebec', value: 'QC' },
{ label: 'British Columbia', value: 'BC' }
];
}
return [];
}
}
}
];
}@Injectable()
export class OptionService {
constructor(private http: HttpClient) {}
loadUsers(): Observable<FormlySelectOption[]> {
return this.http.get<any[]>('/api/users').pipe(
map(users => users.map(user => ({
label: `${user.firstName} ${user.lastName} (${user.email})`,
value: user.id,
disabled: !user.active
})))
);
}
searchUsers(query: string): Observable<FormlySelectOption[]> {
return this.http.get<any[]>(`/api/users/search?q=${query}`).pipe(
map(users => users.map(user => ({
label: `${user.firstName} ${user.lastName}`,
value: user.id
})))
);
}
}
// Usage in field configuration
const fieldConfig: FormlyFieldConfig = {
key: 'assignedUser',
type: 'select',
props: {
label: 'Assigned User',
placeholder: 'Select a user',
options: this.optionService.loadUsers()
}
};