Skip to content Skip to sidebar Skip to footer

In This Subsystem, a User Can Create Data Entry Forms.

Gå til hovedinnhold

Contextual data entry for lookups

In data entry scenarios, it is common for a user to attempt to place an entity in terms of some more descriptive or tongue attribute if that entity is formally identified past a synthetic key, such as a number sequence. The contextual data entry feature allows users to type in either the synthetic key or a more descriptive attribute straight into a lookup field. This page explains how contextual information entry works and as well provides implementation details and tips for developers who desire their lookups to have this behavior.

Introduction

In data entry scenarios, information technology is common for a user to try to identify an entity in terms of some more descriptive or natural language aspect if that entity is formally identified by a synthetic fundamental, such as a number sequence. A user will typically attempt to enter an Account Name instead of an Business relationship ID for the Customer Business relationship when creating a Sales Order. This is considering nearly interaction with a customer is done using their actual proper noun instead of some constructed identifier. Unfortunately, any user'due south attempt to enter an Account Name will fail because the Client account control's underlying foreign central relates to a field that is a constructed cardinal—a number sequence—and Dynamics AX 2022 (and older) will ever attempt to validate the entered value straight. Therefore, if the Account ID was unknown to the user, the user would exist forced to perform some type of searching stride, such as opening the Customer account control's lookup and filtering on the Business relationship Name column to identify the correct Account ID (see the image below).

Example of filtering on Account name to identify correct Account ID.

This user experience is not optimal and is being addressed by information entry efficiency and productivity. The platform adds initial support for contextual data entry, where the system automatically attempts to understand whether the user'due south entered information is in the context of the key field or some other more than descriptive or well-understood field, and handle it appropriately. For the remainder of this certificate, nosotros'll generically refer to these types of fields as ID (synthetic) and NAME (descriptive) fields, respectively.

Contextual lookup forms

Just similar keyboard data entry, all system-generated lookup forms are likewise now contextual, pregnant that filtering and sorting occur in the context of the information the user has entered. Using the create a Sales Order scenario equally an case, the user will encounter the lookup shown below if an ID is entered.

Customer account lookup form opened in the context of ID.

If a Proper noun is entered, and so the user will run across the following lookup. Detect how the NAME column is moved first in the Grid, and how the lookup is sorted and filtered upon when the user's information is in the context of Proper name.

Customer account lookup form opened in the context of NAME.

Contextual information entry implementation details

Behavior

In the context of the Sales order create scenario mentioned to a higher place, the contextual information entry feature volition allow the user to exist able to freely type in either the ID or NAME without performing whatever laborious search process. In detail, the following behaviors volition occur:

  1. If the user enters a consummate ID reference, the value will be taken direct.
  2. If the user enters a complete and unique Proper name reference, the value volition be automatically translated into an ID and and then candy.
  3. If the user enters a non-complete ID or NAME reference (such as Micro instead of Microsoft), but it still uniquely matches either ID or Name via a BEGINS WITH predicate, and so the value will exist translated into its complete ID and then processed.
  4. If the user enters a not-complete ID or a not-unique Proper noun and at that place are multiple matches, then a disambiguation lookup will be presented to the user to select which value was actually intended.

See Appendix A for more detailed sample scenarios of contextual data entry.

Prerequisites

To maintain functional correctness and reasonable performance, the post-obit constraints were added to the application of the behaviors described in the previous department:

  1. Title Field two is the Proper name field**.
  2. The NAME field must either be covered by an index OR belong to a Table whose Enshroud Lookup belongings is ready to EntireTable. All contextual lookup behavior will be disabled if this requirement is non met for performance reasons. Annotation: An alphabetize should only be added for Not TRANSACTIONAL tables because of index maintenance costs. Also note that you volition likely want to mark this index as non-unique (Let Duplicates = Yes).
  3. If a control is using a custom lookup class (such every bit SysTableLookup; FormHelp on an EDT) then the disambiguation behavior described previously will not exist turned on by default. This is because these custom lookup forms (and fifty-fifty surrounding modified and lookup method overrides) can and will do avant-garde things such equally presenting a dialog, which are not desirable in the context of contextual lookups.

Handling custom lookup forms requires additional knowledge and will be covered in its own section.

Programming model additions

The behaviors and rules expressed in Listings 1 and 2 are contained primarily by a new X++ class called FormControlAmbiguousReferenceResolver. FormControlAmbiguousReferenceResolver uptake in application code will be necessary in more than avant-garde scenarios. Its apply volition be described later in the document. In improver to the FormControlAmbiguousReferenceResolver class, a new control override chosen resolveAmbiguousReference has been added. ResolveAmbiguousReference acts as a hook signal in the system for translating what the user typed into a value that the arrangement is expecting. The bones flow is as follows:

  1. The user enters a value into a command and removes focus.
  2. An interaction is sent from the client to the server, indicating that a new value has been entered. The appropriate command is executed on the server.
  3. Earlier the command attempts to process the value entered by the user, it makes a call to resolveAmbiguousReference to requite the system a gamble to translate the value into the expected domain.
  4. The super implementation of resolveAmbiguousReference creates an instance of FormControlAmbiguousReferenceResolver which executes the rules described above.

The value returned from resolveAmbiguousReference is used for the balance of the command's execution. Validate() and modified() operate confronting the returned value.

Standard lookup uptake

Add together an alphabetize that covers TitleField2

TitleField2 defines the default definition of NAME. In gild to enable ID and NAME contextual data entry, TitleField2 must be either indexed OR belong to a tabular array with CacheLookup set to EntireTable. If the tabular array containing TitleField2 does not however define an index covering TitleField2 and, importantly, the table does non have a high volume of CUD (Creates/Updates/Deletes*), so add together a non-unique alphabetize (Allow Duplicates = Yes) roofing TitleField2. This volition crusade the system to start executing the contextual data entry behavior, except for the custom lookup limitation described in the Prerequisites section. *Adding an index on high-volume transactional tables may incur a noticeable performance penalization due to index maintenance costs.

Enable disambiguation behavior for custom lookup scenarios

Custom lookup implementations can provide advanced or not-typical behaviors, such as presenting dialogs. Therefore, the system disables the default disambiguation behavior when a custom lookup scenario is detected. To opt into the default disambiguation behavior, override the resolveAmbiguousReference method (as shown beneath) on the control hosting the lookup. Note that the 2d parameter to the resolveAmbiguousReferenceForControl call is what overrides the default behavior of not performing disambiguation for custom lookup scenarios.

              public str resolveAmbiguousReference() {     FormControlAmbiguousReferenceResolver::resolveAmbiguousReferenceForControl (this, true); }                          

Make custom lookup forms contextual

As mentioned earlier, all organization-generated lookup forms automatically consider the context of the data entered into their host control. This includes most lookup forms generated via SysTableLookup. Modeled custom lookup forms, by their nature, cannot exist fully-handled by the arrangement and must be modified to match the behavior and visuals of contextual lookups forms.

  1. If the data contained by the host control is in the context of ID, then:

    1. Make the ID column first in the Filigree.
    2. Sort and filter by ID.
  2. If the information independent by the host control is in the context of NAME, then:

    1. Brand the NAME column first in the Grid,
    2. Sort and filter by NAME,

The following scenarios illustrate some custom lookups, forth with the recommendation for how to enable contextual data entry in these cases.

Scenario 1: Custom lookup defined via the FormHelp property on an EDT

Custom lookups defined via FormHelp (even though modeled) withal go through normal kernel-based lookup generation routines. Therefore, the kernel withal has hooks to make some changes to the lookup form. Specifically, the lookup system has enough information to utilise the right filters and sorts; nonetheless, it is NOT known which controls should be moved in the lookup's grid. (While an educated guess could be made based on bindings, that guess may be incorrect in more advanced lookup form designs.) If your custom lookup form is leveraging the SysTableLookup::filterLookupPreRun and SysTableLookup::filterLookupPostRun methods, then uptake the (new) optional parameters on filterLookupPostRun to take the NAME control moved automatically, as shown.

              public class MyCustomLookupForm extends FormRun {     public void run()     {         FormStringControl lookupHostControl = SysTableLookup::getCallerStringControl(this.args());         boolean isFiltered = SysTableLookup::filterLookupPreRun(lookupHostControl, ID_Control, FormDataSourceToFilter);          super();          SysTableLookup::filterLookupPostRun(isFiltered, lookupHostControl.text(), ID_Control, FormDataSourceToFilter,              new FormControlAmbiguousReferenceResolver(callingControl), NAME_Control);     } }                          

If your lookup form isn't using the SysTableLookup::filterLookup* methods, and you lot don't desire to uptake those methods, then you can simply add a control motility as shown below.

              public class MyCustomLookupForm extends FormRun {     public void init()     {         super();         this.applyControlOrdering();     }      private void applyControlOrdering()     {         FormControl callerControl = SysTableLookup::getCallerControl(this.args());         if (FormControlAmbiguousReferenceResolver::isControlValueMappedToAlternativeField(callerControl))         {             Grid.moveControl(ID_Control.id(), NAME_control.id());         }         else         {             Filigree.moveControl(NAME_Control.id(), ID_Control.id());         }     } }                          

Scenario 2: Override of lookup method manually launching a form

Unlike Scenario i, lookup forms launched by completely manual mechanisms, such as the class factory, take no kernel hooks. Therefore, it is the responsibility of the lookup class to adhere to the contextual data entry behaviors. The easiest manner to do this is to leverage the SysTableLookup::filterLookup* methods (similar to Scenario 1) except include one additional parameter to point that sorting should likewise be maintained. An example is shown beneath.

              public form MyCustomLookupForm extends FormRun {     public void run()     {         FormStringControl lookupHostControl = SysTableLookup::getCallerStringControl(this.args());         boolean isFiltered = SysTableLookup::filterLookupPreRun(lookupHostControl, ID_Control, FormDataSourceToFilter);          super();          SysTableLookup::filterLookupPostRun(isFiltered, lookupHostControl.text(), ID_Control, FormDataSourceToFilter,              new FormControlAmbiguousReferenceResolver(callingControl), NAME_Control, true);     } }                          

Advanced lookup uptake

Scenario 1: Overriding ID and NAME bindings

If you desire to use a gear up of fields other than what is chosen past default, y'all must manually construct an instance of FormControlAmbiguousReferenceResolver and provide the optional parameters representing the custom bindings. This specialized example must exist used in an override of resolveAmbiguousReference and in a custom lookup course (including SysTableLookup, which too accepts an instance of FormControlAmbiguousReferenceResolver). A custom binding cannot currently be specified in kernel-generated lookups. Methods currently accepting custom ID and Proper noun bindings:

  1. FormControlAmbiguousReferenceResolver
    • Constructor
    • resolveAmbiguousReferenceForControl
    • surrogateFKHelperForAlternativeFieldMapping
    • isControlValueMappedToAlternativeField

Hither'southward an end-to-end example of how to provide custom bindings.

              [Control Hosting Lookup] public str resolveAmbiguousReference() {     render FormControlAmbiguousReferenceResolver::resolveAmbiguousReferenceForControl(         this, true, AbsoluteFieldBinding::construct(IDField, Table),          AbsoluteFieldBinding::construct(SomeOtherNAMEField, Tabular array)); }  [Custom Lookup Class] public class MyCustomLookupForm extends FormRun {     public void run()     {         FormStringControl lookupHostControl = SysTableLookup::getCallerStringControl(this.args());         boolean isFiltered = SysTableLookup::filterLookupPreRun(lookupHostControl, ID_Control, FormDataSourceToFilter);          super();          SysTableLookup::filterLookupPostRun(isFiltered, lookupHostControl.text(), ID_Control, FormDataSourceToFilter,              new FormControlAmbiguousReferenceResolver(callingControl, AbsoluteFieldBinding::construct(IDField, Table),             AbsoluteFieldBinding::construct(SomeOtherNAMEField, Table)), NAME_Control, true);     } }                          

Scenario ii: Custom resolution logic

It'south possible to utilise custom resolution logic by overriding resolveAmbiguousReference and leveraging something other than FormControlAmbiguousReferenceResolver. Note that this logic needs to exist common to the hosted lookup course so that keyboard and lookup-based entry stay in sync.

              public str resolveAmbiguousReference() {     // In this sample, permit "looser" data entry past simply picking the kickoff record that matches, if whatsoever.     CLI_Job _job;     str mappedValue = this.text();     if (strLen(mappedValue) > 0)     {         select firstonly _job order by _job.Title where _job.Title similar mappedValue + "*";     }      if (_job.RecId)     {         mappedValue = _job.Title;     }      return mappedValue; }                          

Appendix Detailed usage scenarios for contextual data entry

For the scenarios, presume there is a table called "TableA" with PK field "ID" and alphabetize field "Name", with the FK we're trying to enter that is related to the ID (the user ultimately needs to pick an ID). Annotation that any algorithms that depend on like/begins with are assuming string fields. Nosotros won't exist able to provide high fidelity resolution behavior on, for instance, integral types.

Scenario one: User enters a valid ID of "1234" The super() implementation of resolveReference first queries against TableA.ID with the appropriate predicate. The query finds a single record, and returns the user's entered value to be further processed past validate and modified. Validation passes and the user sees "1234" in the UI.

Scenario 2: User enters an invalid ID of "4321" The super() implementation of resolveReference kickoff queries confronting TableA.ID. The query does not find whatsoever records, then a second query is performed confronting the Name field (SELECT Pinnacle two FROM TableA WHERE TableA.Proper noun Like "4321%"). Withal, no record is found, so "4321" is passed through to validation, which fails. The user sees "4321" in the browser every bit well as a validation mistake.

Scenario three: User enters a valid Name of "Meridian" The super() implementation of resolveReference starting time queries against TableA.ID. The query does not observe any records, so a second query is performed against the Name field (SELECT Peak ii FROM TableA WHERE TableA.Name LIKE "ACME%"). This query does find a unmarried record (unique reference), so the lookup automatically returns the corresponding TableA.ID. Validate and modified proceed executing in the context of that value. Validation passes, and ultimately the user sees the ID value for ACME in the browser (for example, ACME would switch to 1234 in the browser).

Scenario 4: User enters an invalid Name of "ACNE" The super() implementation of resolveReference first queries confronting TableA.ID. The query does not notice any records, so a second query is performed against the Name field (SELECT TOP 2 FROM TableA WHERE TableA.Proper noun Like "ACNE%"). This query does not find whatsoever records, and so the lookup passes ACNE through to validation, which fails. The user sees "ACNE" in the browser equally well as a validation error.

Scenario v: User enters an cryptic Name of "Elevation" In this instance, assume there are ii records in the database: 1 with Proper noun "ACME W" and some other with "Superlative E". The super() implementation of resolveReference outset queries confronting TableA.ID. The query does not find any records, so a second query is performed against the Proper noun field (SELECT TOP 2 FROM TableA WHERE TableA.Name LIKE "ACME%"). This query finds two records, then it cannot make whatever further assumptions. A disambiguation lookup is presented to the user showing "ACME West" and "Acme E" as choices. The user picks "Top E". resolveReference then takes the records selected by the user and redirects it to the ID of "ACME E". Validate and modified continue execution in the context of the ID of "Tiptop E". The browser ultimately displays the ID of "ACME E" (for example, 1234).

Scenario 6: User enters an ambiguous Name of "Tiptop" and doesn't make a choice in the disambiguation lookup In this case, assume there are two records in the database: one with Name "Summit Westward" and another with "Superlative E". The super() implementation of resolveReference commencement queries confronting TableA.ID. The query does not find any records, so a second query is performed confronting the Name field (SELECT TOP 2 FROM TableA WHERE TableA.Name LIKE "Pinnacle%"). This query finds two records, so it cannot make whatsoever further assumptions. A disambiguation lookup is presented to the user showing "ACME W" and "ACME E" every bit choices. The user doesn't brand a selection from the lookup. Therefore "Top" is passed through to validate and modified. Validation fails and the user is presented with a validation failure bulletin. The browser withal displays a value of "Peak".

Scenario seven: User enters a "valid" ID of "12" and presents the lookup form Prior to presenting the lookup, the system queries against TableA.ID (SELECT TOP 1 FROM TableA WHERE TableA.ID LIKE '12%'). The query finds a record and therefore assumes the user must be operating in the context of ID. It presents the lookup, filtering and sorting by ID.

Scenario 8: User enters an invalid ID of "4321" and presents the lookup grade Prior to presenting the lookup, the arrangement queries against TableA.ID (SELECT TOP 1 FROM TableA WHERE TableA.ID LIKE '4321%'). The query does not find a matching record and therefore assumes the user is entering a Name. The lookup is presented every bit filtered and sorted past Name (no records shown in this case).

Scenario 9: User enters a "valid" Proper noun of "Ac" and presents the lookup class Prior to presenting the lookup, the system queries against TableA.ID (SELECT TOP one FROM TableA WHERE TableA.ID LIKE 'AC%'). The query does not notice a matching tape and therefore assumes the user is entering a Proper noun. The lookup is presented every bit filtered (those records matching "begins with Ac") and sorted by Proper noun in alphabetical order.

Scenario 10: User enters an invalid Proper noun of "EM" and presents the lookup grade Prior to presenting the lookup, the system queries against TableA.ID (SELECT TOP ane FROM TableA WHERE TableA.ID LIKE 'EM%'). The query does not find a matching record and therefore assumes the user is entering a Name. The lookup is presented as filtered and sorted by Proper name. No records are found and therefore the user is presented with an empty lookup.

cannonvaccom.blogspot.com

Source: https://docs.microsoft.com/nb-no/dynamics365/fin-ops-core/dev-itpro/user-interface/contextual-data-entry-lookups

Post a Comment for "In This Subsystem, a User Can Create Data Entry Forms."