From 17998c9e3d6231ad938a7b0f4eebd6d870c03035 Mon Sep 17 00:00:00 2001 From: Reza Date: Tue, 3 Jan 2023 18:51:05 +0100 Subject: [PATCH] Support Lookup field for binding and bug fixing --- DynamicDropdown/ControlManifest.Input.xml | 8 ++- DynamicDropdown/index.ts | 50 +++++++++++++++---- .../strings/DynamicDropdown.1033.resx | 2 +- solutions/src/Other/Solution.xml | 6 +-- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/DynamicDropdown/ControlManifest.Input.xml b/DynamicDropdown/ControlManifest.Input.xml index db88c86..fa5b43e 100644 --- a/DynamicDropdown/ControlManifest.Input.xml +++ b/DynamicDropdown/ControlManifest.Input.xml @@ -1,6 +1,6 @@ - + - + @@ -39,6 +39,10 @@ --> + + SingleLine.Text + Lookup.Simple + SingleLine.Text Lookup.Simple diff --git a/DynamicDropdown/index.ts b/DynamicDropdown/index.ts index 692bf75..1e3bf08 100644 --- a/DynamicDropdown/index.ts +++ b/DynamicDropdown/index.ts @@ -6,7 +6,7 @@ import { DynamicComboBox } from './DynamicComboBox'; export class DynamicDropdown implements ComponentFramework.StandardControl { private notifyOutputChanged: () => void; rootContainer: HTMLDivElement; - selectedValue: string | number; + selectedValue: string | number | ComponentFramework.LookupValue[] | null; context: ComponentFramework.Context; /** @@ -54,35 +54,46 @@ export class DynamicDropdown implements ComponentFramework.StandardControl { - const queryValue = queryValues['queryValue' + index as possibleQueryValueNames]; + const queryValue = queryValues['queryValue' + index as possibleQueryValueNames]; if (queryValue.type == 'Lookup.Simple') { const value = (queryValue as ComponentFramework.PropertyTypes.LookupProperty).raw - return value ? value[0].id : null; + return value && value.length > 0 ? value[0].id : '00000000-0000-0000-0000-000000000000'; } return queryValue.raw; } if (value && value.attributes && query && entityType.raw && query.raw) { const q = queryValues ? query.raw.replace(/\${(\d+)}/gm, getQueryValue) : query.raw; - let p = context.webAPI.retrieveMultipleRecords(entityType.raw, q).then( - (value) => { options = value.entities; }, + const p = context.webAPI.retrieveMultipleRecords(entityType.raw, q).then( + (val) => { + options = val.entities; + // const valueToMatch = this.tryGetLookupId(value) ?? value.raw; + // const isValueFound = valueToMatch == null || valueField !== null && valueField.raw !== null && val.entities.some((entity) => entity[valueField.raw ?? ''] == valueToMatch); + // if (!isValueFound) { + // this.selectedValue = null; + // this.notifyOutputChanged(); + // } + }, (error) => { errorMessage = error.message; } ); + const getAttributeValue = (entity: ComponentFramework.WebApi.Entity, attribute: string): string => entity[attribute]; + const getAttributeValueRegEx = (entity: ComponentFramework.WebApi.Entity, attribute: string): string => attribute.replace(/\${([\w_]+)}/gm, (_,m)=> entity[m]); + p.then(() => { ReactDOM.render( React.createElement(DynamicComboBox, { - //label: value.attributes.DisplayName, label : '', - value: value.raw, - /* fetch list from webApi / fetchXml, then map and return it. */ + value: this.tryGetLookupId(value) ?? value.raw, options: options, optionKeyField: valueField.raw, optionTextField: textField.raw, disabled: disabled, masked: masked, errorMessage: errorMessage, - onChange: this.onChange, + onChange: value.type == 'Lookup.Simple' ? this.onChangeLookup : this.onChange, + getKeyValue: valueField.raw && valueField.raw.indexOf('$') > -1 ? getAttributeValueRegEx : getAttributeValue, + getTextValue: textField.raw && textField.raw.indexOf('$') > -1 ? getAttributeValueRegEx : getAttributeValue }), this.rootContainer, ); @@ -90,9 +101,14 @@ export class DynamicDropdown implements ComponentFramework.StandardControl { + if (value == null || value.type !== 'Lookup.Simple' || value.raw == null) { return null; } + const lookupValue = value as ComponentFramework.PropertyTypes.LookupProperty; + return (lookupValue.raw.length == 0) ? null : lookupValue.raw[0].id; + } + retrieveOption = async (entityType: string, query: string, webAPI: ComponentFramework.WebApi): Promise => { if (!entityType || !query) { return; } - try { const t = await webAPI.retrieveMultipleRecords(entityType, query); return { options: t.entities } @@ -101,11 +117,23 @@ export class DynamicDropdown implements ComponentFramework.StandardControl { + onChange = (newValue: string | number | null, newText: string | null): void => { this.selectedValue = newValue; this.notifyOutputChanged(); }; + onChangeLookup = (newValue: string | number | null, newText: string | null): void => { + this.selectedValue = (newValue == null) ? [{} as ComponentFramework.LookupValue] : + [ + { + id: newValue, + name: newText, + entityType: (this.context.parameters.value as ComponentFramework.PropertyTypes.LookupProperty).getTargetEntityType() + } as ComponentFramework.LookupValue + ]; + this.notifyOutputChanged(); + } + /** * It is called by the framework prior to a control receiving new data. * @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as “bound” or “output” diff --git a/DynamicDropdown/strings/DynamicDropdown.1033.resx b/DynamicDropdown/strings/DynamicDropdown.1033.resx index 9a7684e..9de4cc7 100644 --- a/DynamicDropdown/strings/DynamicDropdown.1033.resx +++ b/DynamicDropdown/strings/DynamicDropdown.1033.resx @@ -121,7 +121,7 @@ Dynamic Dropdown - + Displays a drop-down control with a list that can be filled based on a query that can depend on the value of other fields. diff --git a/solutions/src/Other/Solution.xml b/solutions/src/Other/Solution.xml index ae179e3..45ce4cc 100644 --- a/solutions/src/Other/Solution.xml +++ b/solutions/src/Other/Solution.xml @@ -5,15 +5,15 @@ DynamicDropDown - + - 1.0 + 1.1.24 2 - Reza Niroomand + RezaNiroomand