1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

#7123: Handle empty_option on API Select

This commit is contained in:
thatmattlove
2021-09-01 17:02:43 -07:00
parent 774dff07ee
commit ddff193786
4 changed files with 34 additions and 25 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -22,13 +22,6 @@ import type { Stringifiable } from 'query-string';
import type { Option } from 'slim-select/dist/data';
import type { Trigger, PathFilter, ApplyMethod, QueryFilter } from './types';
// Empty placeholder option.
const PLACEHOLDER = {
value: '',
text: '',
placeholder: true,
} as Option;
// Attributes which if truthy should render the option disabled.
const DISABLED_ATTRIBUTES = ['occupied'] as string[];
@ -52,6 +45,8 @@ export class APISelect {
*/
public readonly placeholder: string;
public readonly emptyOption: Nullable<Option> = null;
/**
* Event that will initiate the API call to NetBox to load option data. By default, the trigger
* is `'load'`, so data will be fetched when the element renders on the page.
@ -147,7 +142,7 @@ export class APISelect {
/**
* This instance's available options.
*/
private _options: Option[] = [PLACEHOLDER];
private _options: Option[] = [];
/**
* Array of options values which should be considered disabled or static.
@ -168,6 +163,14 @@ export class APISelect {
this.preSorted = true;
}
const emptyOption = base.getAttribute('data-empty-option');
if (isTruthy(emptyOption)) {
this.emptyOption = {
text: emptyOption,
value: '',
};
}
if (hasUrl(base)) {
const url = base.getAttribute('data-url') as string;
this.url = url;
@ -285,17 +288,16 @@ export class APISelect {
// Get the placeholder index (note: if there is no placeholder, the index will be `-1`).
const placeholderIdx = deduplicated.findIndex(o => o.value === '');
if (hasPlaceholder && placeholderIdx < 0) {
if (hasPlaceholder && placeholderIdx < 0 && this.emptyOption !== null) {
// If there is a placeholder but it is not the first element (due to sorting or other merge
// issues), remove it from the options array and place it in front.
deduplicated.splice(placeholderIdx);
deduplicated = [PLACEHOLDER, ...deduplicated];
deduplicated = [this.emptyOption, ...deduplicated];
}
if (!hasPlaceholder) {
if (!hasPlaceholder && this.emptyOption !== null) {
// If there is no placeholder, add one to the front of the array.
deduplicated = [PLACEHOLDER, ...deduplicated];
deduplicated = [this.emptyOption, ...deduplicated];
}
this._options = deduplicated;
this.slim.setData(deduplicated);
}
@ -304,7 +306,11 @@ export class APISelect {
* Remove all options and reset back to the generic placeholder.
*/
private resetOptions(): void {
this.options = [PLACEHOLDER];
if (this.emptyOption !== null) {
this.options = [this.emptyOption];
} else {
this.options = [];
}
}
/**
@ -534,7 +540,7 @@ export class APISelect {
*/
private async getOptions(action: ApplyMethod = 'merge'): Promise<void> {
if (this.queryUrl.includes(`{{`)) {
this.options = [PLACEHOLDER];
this.resetOptions();
return;
}
await this.fetchOptions(this.queryUrl, action);

View File

@ -376,7 +376,7 @@ class DynamicModelChoiceMixin:
widget = widgets.APISelect
def __init__(self, query_params=None, initial_params=None, null_option=None, disabled_indicator=None, fetch_trigger=None,
*args, **kwargs):
empty_label=None, *args, **kwargs):
self.query_params = query_params or {}
self.initial_params = initial_params or {}
self.null_option = null_option
@ -386,11 +386,14 @@ class DynamicModelChoiceMixin:
# to_field_name is set by ModelChoiceField.__init__(), but we need to set it early for reference
# by widget_attrs()
self.to_field_name = kwargs.get('to_field_name')
self.empty_option = empty_label or ""
super().__init__(*args, **kwargs)
def widget_attrs(self, widget):
attrs = {}
attrs = {
'data-empty-option': self.empty_option
}
# Set value-field attribute if the field specifies to_field_name
if self.to_field_name: