}
// Return the selector field for the class. If no selector is
- // defined, use 'name' if it exists as a field on the class. As
- // a last ditch fallback, if there's no selector but the primary
- // key is a text field, use that.
+ // defined, use 'name' if it exists as a field on the class.
getClassSelector(idlClass: string): string {
if (idlClass) {
// No selector defined in the IDL, try 'name'.
if ('name' in classDef.field_map) { return 'name'; }
-
- // last ditch - if the primary key is a text field,
- // treat it as the selector
- if (classDef.field_map[classDef.pkey].datatype === 'text') {
- return classDef.pkey;
- }
-
}
}
};
}
- if (fieldOptions.customTemplate) {
- field.template = fieldOptions.customTemplate.template;
- field.context = fieldOptions.customTemplate.context;
- } else if (fieldOptions.customValues) {
+ if (fieldOptions.customValues) {
field.linkedValues = fieldOptions.customValues;
} else if (field.datatype === 'link') {
- if (fieldOptions.linkedSearchConditions) {
- field.idlBaseQuery = fieldOptions.linkedSearchConditions;
- }
- field.selector = fieldOptions.linkedSearchField ||
- this.idl.getClassSelector(field.class);
+ promise = this.wireUpCombobox(field);
} else if (field.datatype === 'timestamp') {
field.datetime = this.datetimeFieldsList.includes(field.name);
this.orgDefaultAllowedList.includes(field.name);
}
+ if (fieldOptions.customTemplate) {
+ field.template = fieldOptions.customTemplate.template;
+ field.context = fieldOptions.customTemplate.context;
+ }
+
if (fieldOptions.helpText) {
field.helpText = fieldOptions.helpText;
field.helpText.current().then(help => field.helpTextValue = help);
return promise || Promise.resolve();
}
+ wireUpCombobox(field: any): Promise<any> {
+
+ const fieldOptions = this.fieldOptions[field.name] || {};
+
+ // globally preloading unless a field-specific value is set.
+ if (this.preloadLinkedValues) {
+ if (!('preloadLinkedValues' in fieldOptions)) {
+ fieldOptions.preloadLinkedValues = true;
+ }
+ }
+
+ const selector = fieldOptions.linkedSearchField ||
+ this.idl.getClassSelector(field.class);
+
+ if (!selector && !fieldOptions.preloadLinkedValues) {
+ // User probably expects an async data source, but we can't
+ // provide one without a selector. Warn the user.
+ console.warn(`Class ${field.class} has no selector.
+ Pre-fetching all rows for combobox`);
+ }
+
+ if (fieldOptions.preloadLinkedValues || !selector) {
+ return this.pcrud.retrieveAll(field.class, {}, {atomic : true})
+ .toPromise().then(list => {
+ field.linkedValues =
+ this.flattenLinkedValues(field, list);
+ });
+ }
+
+ // If we have a selector, wire up for async data retrieval
+ field.linkedValuesSource =
+ (term: string): Observable<ComboboxEntry> => {
+
+ const search = {};
+ const orderBy = {order_by: {}};
+ const idField = this.idl.classes[field.class].pkey || 'id';
+
+ search[selector] = {'ilike': `%${term}%`};
+ orderBy.order_by[field.class] = selector;
+
+ return this.pcrud.search(field.class, search, orderBy)
+ .pipe(map(idlThing =>
+ // Map each object into a ComboboxEntry upon arrival
+ this.flattenLinkedValues(field, [idlThing])[0]
+ ));
+ };
+
+ // Using an async data source, but a value is already set
+ // on the field. Fetch the linked object and add it to the
+ // combobox entry list so it will be avilable for display
+ // at dialog load time.
+ const linkVal = this.record[field.name]();
+ if (linkVal !== null && linkVal !== undefined) {
+ return this.pcrud.retrieve(field.class, linkVal).toPromise()
+ .then(idlThing => {
+ field.linkedValues =
+ this.flattenLinkedValues(field, Array(idlThing));
+ });
+ }
+
+ // No linked value applied, nothing to pre-fetch.
+ return Promise.resolve();
+ }
+
// Returns a context object to be inserted into a custom
// field template.
customTemplateFieldContext(fieldDef: any): CustomFieldContext {
return field.datatype;
}
- if (field.datatype === 'link') {
- return 'link';
- }
-
- if (field.linkedValues) {
+ if (field.datatype === 'link' || field.linkedValues) {
return 'list';
}