Custom picker for dummies

I've been trying to figure out step by step how to create my own address picker.

Most of the questions I've run into here are too specific and don't cover basics. Also, I didn't find an example or tutorial in the online Appian course for this topic.

So, please help! Slight smile

This is my case:

Simple address table example (table has some more columns but I believe they are irrelevant for this story):

ID : 1
ADDRESS_TEXT_ID: "3RD AVENUE-15-NEW YORK-55555"

ID : 2
ADDRESS_TEXT_ID: "5TH AVENUE-10A-LOS ANGELES-12345"

ID : 3
ADDRESS_TEXT_ID: "UPPER STREET-14-AUSTIN-52154"

What I need is a picker that starts searching my address database table with rows like those above after I type at least 3 characters. It allows only 1 selection that needs to be represented with address text (label) and stored as its numerical ID in rule input (rule input is CDT, so the input field should be ri!employee.addressId). 

This is the rule I've created for search:

a!queryEntity(
  entity: cons!EEDM_ADDRESS_DATA_STORE_ENTITY,
  query: a!query(
    logicalExpression: a!queryLogicalExpression(
      operator: "AND",
      filters: {
        a!queryFilter(
          field: "addressTextId",
          operator: "includes",
          value: upper(ri!searchText)
        )
      },
      ignoreFiltersWithEmptyValues: true
    ),
    pagingInfo: a!pagingInfo(
      startIndex: 1,
      batchSize: 50
    )
  ),
  fetchTotalCount: false
).data

This is my custom picker code now:

a!pickerFieldCustom(
  label: "Pick address",
  labelPosition: "ABOVE",
  instructions: "",
  helptooltip: "Start typing address text ID and address containing input string will be shown",
  placeholder: "---Type address text ID ---",
  maxselections: 1,
  suggestfunction: rule!EEDM_SearchAddressByString(_),
  value: ri!employee.addressId,
  saveInto: ri!employee.addressId,
  validations: {}
)

I know I'm missing some key properties but I don't get how to define them.

Could anyone give me step by step example how to finish this picker?

  Discussion posts and replies are publicly visible

Parents
  • 0
    Certified Senior Developer

    Hi

    Fetch all the address from the table
     save in the local variable : local!allAddress
    
    Create a suggest function :  rule!EEDM_ArrayPickerFilter
      - this funtion return all the search results by key
      
      =with(
            if(
    		    len(ri!filter) > 3,
    			  with(
    			    {
    				  local!matches: where(
    					a!forEach(
    					  items: ri!labels, 
    					  expression: search( ri!filter, fv!item)
    					)
    				  ),
    				  a!dataSubset(
    					data: index( ri!labels, local!matches), 
    					identifiers: index( ri!identifiers, local!matches)
    				  )
    				},
    			),
                todatasubset({})			
    		)    
    	)
    	
    In the main rule
    a!pickerFieldCustom(
      label: "Pick address",
      labelPosition: "ABOVE",
      instructions: "",
      helptooltip: "Start typing address text ID and address containing input string will be shown",
      placeholder: "---Type address text ID ---",
      maxselections: 1,
      suggestFunction: rule!EEDM_ArrayPickerFilter(
    					  filter:_ , 
    					  labels: index(local!allAddress,"ADDRESS_TEXT_ID",null), 
    					  identifiers: index(local!allAddress,"ID",null)
    					),
      selectedLabels: a!forEach(
    					  items: ri!employee.addressId,
    					  expression: index(index(local!allAddress,"ADDRESS_TEXT_ID",null),, wherecontains(fv!item, index(local!allAddress,"ID",null)))
    					),
     
      value: ri!employee.addressId,
      saveInto: ri!employee.addressId,
      validations: {}
    )

    Reference : https://docs.appian.com/suite/help/20.1/recipe-configure-an-array-picker.html

  • 0
    A Score Level 1
    in reply to vinayr273

    OK, I've loaded all the addreses into local variable at the beginning of my form layout as you suggested:

    a!localVariables(
      local!activeStep: 1,
      local!steps: {
        "Select employee",
        "Personal Data",
        "Address Data",
        "Review"
      with(
        local!supervisors: rule!EEDM_GetAllSupervisors(),
        local!employees: rule!EEDM_GetAllEmployees(),
        local!allAddress: rule!EEDM_GetAllAddresses(),
        ...

    This is the rule for loading it:

    a!queryEntity(
      entity: cons!EEDM_ADDRESS_DATA_STORE_ENTITY,
      query: a!query(
        pagingInfo: a!pagingInfo(
          startIndex: 1,
          batchSize: 50
        )
      ),
      fetchTotalCount: false
    ).data

    Then I've created suggest function rule but can't test it. What am I doing wrong? Rule inputs are of wrong type or something like that (in my database table ID is number, ADDRESSTEXTID is text)?

    Also when I define my custom picker with this code you've posted above, I get this error:

    a!pickerFieldCustom(
      label: "Pick address",
      labelPosition: "ABOVE",
      instructions: "",
      helptooltip: "Start typing address text ID and address containing input string will be shown",
      placeholder: "---Type address text ID ---",
      maxselections: 1,
      suggestFunction: rule!EEDM_ArrayPickerFilter(
    					  filter:_ , 
    					  labels: index(local!allAddress,"ADDRESS_TEXT_ID",null), 
    					  identifiers: index(local!allAddress,"ID",null)
    					),
      selectedLabels: a!forEach(
    					  items: ri!employee.addressId,
    					  expression: index(index(local!allAddress,"ADDRESS_TEXT_ID",null),, wherecontains(fv!item, index(local!allAddress,"ID",null)))
    					),
     
      value: ri!employee.addressId,
      saveInto: ri!employee.addressId,
      validations: {}
    )

  • +1
    Certified Senior Developer
    in reply to ivanm0004

    Hi,

    please find the updated code

    with(
      
        local!matches: where(
          a!forEach(
            items: ri!labels, 
            expression: search( ri!filter, fv!item)
          )
        ),
        
      if(
        len(ri!filter) >= 3,
            a!dataSubset(
              data: index( ri!labels, local!matches), 
              identifiers: index( ri!identifiers, local!matches)
            ),
            todatasubset({})
       )
      
    )
    
    
    
    a!pickerFieldCustom(
      label: "Pick address",
      labelPosition: "ABOVE",
      instructions: "",
      helptooltip: "Start typing address text ID and address containing input string will be shown",
      placeholder: "---Type address text ID ---",
      maxselections: 1,
      suggestFunction: rule!EEDM_ArrayPickerFilter(
    					  filter:_ , 
    					  labels: index(local!allAddress,"ADDRESS_TEXT_ID",null), 
    					  identifiers: index(local!allAddress,"ID",null)
    					),
      selectedLabels: a!forEach(
    					  items: ri!employee.addressId,
    					  expression: index(index(local!allAddress,"ADDRESS_TEXT_ID",null), wherecontains(tointeger(fv!item), tointeger(index(local!allAddress,"ID",null))))
    					),
     
      value: ri!employee.addressId,
      saveInto: ri!employee.addressId,
      validations: {}
    )

  • 0
    A Score Level 1
    in reply to vinayr273

    Thank you very much! Now I understand these custom picker stuff much better. I've modified this code a bit to add some more functionalities and it works like a charm.

    Although, I have one more question.

    Because I have to load whole address table it may become tricky from the performance viewpoint.

    My table here is some demo table and has only few rows. What if I have to use the whole codebook table? In my country it would be around 53 000 streets or more than 2 million house numbers. 

    Does this picker always require loading into local variables? Is this the best or only practice?

    I know I can redesign this address issue to have multiple dropdowns for street, house number, city, post office etc. instead of one picker. But let's say that I must use some pretty big table for my picker.

    Are there any best practices to manage performance issues?

  • My approach here would be to allow the search be run directly against the database and to be narrowed down to something that would reduce the result set as quickly as possible e.g. a post-code. So your picker could still display the entire address but the search is just using the input postcode to return what should be a very small subset of the overall data.If you ensure that the address is stored in its component parts then postcode would be in its own column, and could have a clustered index on it so that all of the adjacent addresses are retrieved in as few psychical fetches from the disk as possible.

Reply
  • My approach here would be to allow the search be run directly against the database and to be narrowed down to something that would reduce the result set as quickly as possible e.g. a post-code. So your picker could still display the entire address but the search is just using the input postcode to return what should be a very small subset of the overall data.If you ensure that the address is stored in its component parts then postcode would be in its own column, and could have a clustered index on it so that all of the adjacent addresses are retrieved in as few psychical fetches from the disk as possible.

Children
No Data