return result;
}
+
+ // Given a field on an IDL class, returns the name of the field
+ // on the linked class that acts as the selector for the linked class.
+ // Returns null if no selector is found or the field is not a link.
+ getLinkSelector(fmClass: string, field: string): string {
+ const fieldDef = this.classes[fmClass].field_map[field];
+ if (fieldDef.class) {
+ const classDef = this.classes[fieldDef.class];
+ if (classDef.pkey) {
+ return classDef.field_map[classDef.pkey].selector || null;
+ }
+ }
+ return null;
+ }
}
anonymous?: boolean;
idlist?: boolean;
atomic?: boolean;
+ // If true, link-type fields which link to a class that defines a
+ // selector will be fleshed with the linked value. This affects
+ // retrieve(), retrieveAll(), and search() calls.
+ fleshSelectors?: boolean;
}
// For for documentation purposes.
this.session.disconnect();
}
+ // Adds "flesh" logic to retrieve linked values for all fields
+ // that link to a class which defines a selector field.
+ applySelectorFleshing(fmClass: string, pcrudOps: any) {
+ pcrudOps = pcrudOps || {};
+
+ if (!pcrudOps.flesh) {
+ pcrudOps.flesh = 1;
+ }
+
+ if (!pcrudOps.flesh_fields) {
+ pcrudOps.flesh_fields = {};
+ }
+
+ this.idl.classes[fmClass].fields
+ .filter(f => f.datatype === 'link' && !f.virtual)
+ .forEach(field => {
+ const selector = this.idl.getLinkSelector(fmClass, field.name);
+ if (!selector) { return; }
+
+ if (!pcrudOps.flesh_fields[fmClass]) {
+ pcrudOps.flesh_fields[fmClass] = [];
+ }
+
+ if (pcrudOps.flesh_fields[fmClass].indexOf(field.name) < 0) {
+ pcrudOps.flesh_fields[fmClass].push(field.name);
+ }
+ });
+ }
+
retrieve(fmClass: string, pkey: Number | string,
pcrudOps?: any, reqOps?: PcrudReqOps): Observable<PcrudResponse> {
reqOps = reqOps || {};
this.authoritative = reqOps.authoritative || false;
+ if (reqOps.fleshSelectors) {
+ this.applySelectorFleshing(fmClass, pcrudOps);
+ }
return this.dispatch(
`open-ils.pcrud.retrieve.${fmClass}`,
[this.token(reqOps), pkey, pcrudOps]);
if (reqOps.atomic) { method += '.atomic'; }
+ if (reqOps.fleshSelectors) {
+ this.applySelectorFleshing(fmClass, pcrudOps);
+ }
+
return this.dispatch(method, [this.token(reqOps), search, pcrudOps]);
}
// linked data so we can display the data within the selector
// field. Otherwise, avoid the network lookup and let the
// bare value (usually an ID) be displayed.
- const idField = this.idl.classes[field.class].pkey;
const selector =
- this.idl.classes[field.class].field_map[idField].selector;
+ this.idl.getLinkSelector(this.idlClass, field.name);
if (selector && selector !== field.name) {
promises.push(
// grid data.
@Input() pageOffset: number;
+ // If true and an idlClass is specificed, the grid assumes
+ // datatype=link fields that link to classes which define a selector
+ // are fleshed with the linked object. And, instead of displaying
+ // the raw field value, displays the selector value from the linked
+ // object. The caller is responsible for fleshing the appropriate
+ // fields in the GridDataSource getRows handler.
+ //
+ // This only applies to auto-generated columns.
+ //
+ // For example, idlClass="aou" and field="ou_type", the display
+ // value will be ou_type().name() since "name" is the selector
+ // field on the "aout" class.
+ @Input() showLinkSelectors: boolean;
+
context: GridContext;
// These events are emitted from our grid-body component.
this.context.isMultiSortable = this.multiSortable === true;
this.context.useLocalSort = this.useLocalSort === true;
this.context.disableSelect = this.disableSelect === true;
+ this.context.showLinkSelectors = this.showLinkSelectors === true;
this.context.disableMultiSelect = this.disableMultiSelect === true;
this.context.rowFlairIsEnabled = this.rowFlairIsEnabled === true;
this.context.rowFlairCallback = this.rowFlairCallback;
defaultVisibleFields: string[];
defaultHiddenFields: string[];
overflowCells: boolean;
+ showLinkSelectors: boolean;
// Services injected by our grid component
idl: IdlService;
getRowColumnValue(row: any, col: GridColumn): string {
let val;
- if (col.name in row) {
+
+ if (col.path) {
+ val = this.nestedItemFieldValue(row, col);
+ } else if (col.name in row) {
val = this.getObjectFieldValue(row, col.name);
- } else {
- if (col.path) {
- val = this.nestedItemFieldValue(row, col);
- }
}
return this.format.transform({
for (let i = 0; i < steps.length; i++) {
const step = steps[i];
- if (typeof obj !== 'object') {
+ if (obj === null || obj === undefined || typeof obj !== 'object') {
// We have run out of data to step through before
// reaching the end of the path. Conclude fleshing via
// callback if provided then exit.
col.datatype = field.datatype;
col.isIndex = (field.name === pkeyField);
col.isAuto = true;
+
+ if (this.showLinkSelectors) {
+ const selector = this.idl.getLinkSelector(
+ this.columnSet.idlClass, field.name);
+ if (selector) {
+ col.path = field.name + '.' + selector;
+ }
+ }
+
this.columnSet.add(col);
});
}
<eg-translate #translator></eg-translate>
<eg-grid #grid idlClass="{{idlClass}}" [dataSource]="dataSource"
- [sortable]="true" persistKey="{{persistKey}}">
+ [sortable]="true" persistKey="{{persistKey}}" [showLinkSelectors]="true">
<eg-grid-toolbar-button [disabled]="!canCreate"
label="New {{idlClassDef.label}}" i18n-label [action]="createNew">
</eg-grid-toolbar-button>
const search = {};
search[this.orgField] = orgs;
- return this.pcrud.search(this.idlClass, search, searchOps);
+ return this.pcrud.search(
+ this.idlClass, search, searchOps, {fleshSelectors: true});
}
// No org filter -- fetch all rows
- return this.pcrud.retrieveAll(this.idlClass, searchOps);
+ return this.pcrud.retrieveAll(
+ this.idlClass, searchOps, {fleshSelectors: true});
};
}