{"id":776,"date":"2011-06-06T20:20:08","date_gmt":"2011-06-07T01:20:08","guid":{"rendered":"http:\/\/anvil-of-time.com\/wordpress\/?p=776"},"modified":"2021-03-10T20:26:35","modified_gmt":"2021-03-11T01:26:35","slug":"powerbuilder-type-ahead-style-dropdown-datawindow-columns","status":"publish","type":"post","link":"https:\/\/anvil-of-time.com\/powerbuilder\/powerbuilder-type-ahead-style-dropdown-datawindow-columns\/","title":{"rendered":"PowerBuilder &#8211; Type ahead style dropdown datawindow columns"},"content":{"rendered":"<p>This type of functionality is one of those things which fills a gap so completely and perfectly that when you encounter some application (and almost all web pages) which doesn&#8217;t have it you groan to yourself. In the ancient past this was alternatively referred to as &#8216;Quicken style&#8217; dropdowns since that application was one very common example in use. Basically this functionality is used on dropdown datawindows to allow the user to type in a series of characters which cause the control to filter the entries so that finding the desired one is quick and easy. The PFC has a service attached to the datawindow ancestor which does the same thing but here is the same functionality encapsulated into a single NVO.<\/p>\n<p>Sample Application Screen Shots:<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2011\/06\/Sample-1.jpg\"><img loading=\"lazy\" class=\"aligncenter wp-image-777 size-full\" title=\"Sample 1\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/Sample-1.jpg\" alt=\"\" width=\"412\" height=\"230\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/Sample-1.jpg 412w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/Sample-1-300x167.jpg 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/Sample-1-150x83.jpg 150w\" sizes=\"(max-width: 412px) 100vw, 412px\" \/><\/a><\/p>\n<p>Image one shows the standard PB dropdown which is basically useless outside of using the mouse pointer.<\/p>\n<p><a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2011\/06\/Sample-2.jpg\"><img loading=\"lazy\" class=\"aligncenter wp-image-778 size-full\" title=\"Sample 2\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/Sample-2.jpg\" alt=\"\" width=\"412\" height=\"230\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/Sample-2.jpg 412w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/Sample-2-300x167.jpg 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/Sample-2-150x83.jpg 150w\" sizes=\"(max-width: 412px) 100vw, 412px\" \/><\/a><br \/>\nImage two shows the Type Ahead interface where the highlighted row in the dropdown responds to user typing.<\/p>\n<p>On the window containing the datawindow(s) you wish to have this functionality add the following:<\/p>\n<pre name=\"code\" class=\"VB\">\/\/getfocus\n\/\/ Use this method if you have several datawindows on a window which you wish to have this type of functionality.  If not you\n\/\/ could just put this code in the window postopen type event.\ndatawindow ldw\nldw = THIS\nnvo_grid.uf_set_current_dw(ldw)\n\n\n\/\/editchanged\n\/\/ map nvo event to datawindow event\nCHOOSE CASE dwo.name\n\tCASE &#039;pri_pro_int_id&#039;\n\t\tnvo_grid.event ue_editchanged(row, dwo, data)\nEND CHOOSE\n\n\t\t\n\/\/itemfocuschanged\n\/\/ map nvo event to datawindow event\nnvo_grid.event ue_itemfocuschanged(row, dwo)<\/pre>\n<p>The NVO is set to autoinstantiate and contains the following code.<\/p>\n<pre name=\"code\" class=\"VB\">instance variables\n\/\/ dddw search as you type functionality\ndatawindow idw\ndatawindowchild idwc[]\nstring is_datawindow[] \/\/ names of datawindow\/column combinations registered for typeahead functionality\ninteger     ii_currentindex\nboolean\t\tib_performsearch=False\nstring\t\tis_textprev<\/pre>\n<p>Two events.<\/p>\n<pre name=\"code\" class=\"VB\">ue_editchanged(ref long al_row, ref dwobject adwo, ref string as_data);\n\/\/ mapped to editchanged event on datawindow where dddw typeahead is desired\nboolean\t\tlb_matchfound=False\ninteger\t\tli_searchtextlen\nlong\t\tll_findrow\nlong\t\tll_dddw_rowcount\nstring\t\tls_dddw_displaycol\nstring\t\tls_foundtext\nstring\t\tls_findexp\nstring\t\tls_displaydata_value\nstring\t\tls_searchtext\n\n\/\/ Check requirements.\nIf IsNull(adwo) or Not IsValid(adwo) Then Return\n\n\/\/ Confirm that the search capabilities are valid for this column.\nif ib_performsearch=False or ii_currentindex &lt;= 0 THEN return\n\n\/\/ Get information on the column and text.\nls_searchtext = as_data\nli_searchtextlen = Len (ls_searchtext)\n\n\/\/ If the user performed a delete operation, do not perform the search.\n\/\/ If the text entered is the same as the last search, do not perform another search.\nIf (li_searchtextlen &lt; Len(is_textprev)) or &amp;\n\t(Lower (ls_searchtext) = Lower (is_textprev)) Then\n\t\/\/ Store the previous text information.\n\tis_textprev = &#039;&#039;\n\tReturn \nEnd If\n\n\/\/ Store the previous text information.\nis_textprev = ls_searchtext\n\n\/\/ Build the find expression to search the dddw for the text \n\/\/ entered in the parent datawindow column.\nls_dddw_displaycol = adwo.dddw.displaycolumn\nls_findexp = &quot;Lower (Left (&quot; + ls_dddw_displaycol + &quot;, &quot; + &amp;\n\tString (li_searchtextlen) + &quot;)) = &#039;&quot; + Lower (ls_searchtext) + &quot;&#039;&quot;\n\n\/\/ Perform the Search on the dddw.\nll_dddw_rowcount = idwc[ii_currentindex].rowcount()\nll_findrow = idwc[ii_currentindex].Find (ls_findexp, 0, ll_dddw_rowcount + 1)\n\n\/\/ Determine if a match was found on the dddw.\nlb_matchfound = (ll_findrow &gt; 0)\n\n\/\/ Set the found text if found on the dddw.\nif lb_matchfound then\n\t\/\/ Get the text found.\n\tls_foundtext = idwc[ii_currentindex].GetItemString (ll_findrow, ls_dddw_displaycol)\nEnd If\t\t\t\t\t\t\t\t\n\n\/\/ For either dddw or ddlb, check if a match was found.\nIf lb_matchfound Then\n\t\/\/ Set the text.\n\tidw.SetText (ls_foundtext)\n\n\t\/\/ Determine what to highlight or where to move the cursor..\n\tif li_searchtextlen = len(ls_foundtext) THEN\n\t\t\/\/ Move the cursor to the end\n\t\tidw.SelectText (Len (ls_foundtext)+1, 0)\n\telse\n\t\t\/\/ Hightlight the portion the user has not actually typed.\n\t\tidw.SelectText (li_searchtextlen + 1, Len (ls_foundtext))\n\tend if\nend if\n\n\n\nue_itemfocuschanged(long al_row, ref dwobject adwo);\n\/\/ set index if column is in dddw array\n\nint\t\tli_index\nstring \tls_dwcolname\n\nib_performsearch = False\nii_currentindex = 0\nis_textprev = &#039;&#039;\n\nIf IsNull(adwo) or Not IsValid(adwo) Then Return\nIf IsNull(al_row) or al_row &lt;= 0 Then Return\nIf IsNull(idw) or Not IsValid(idw) Then Return\n\/\/ Get column name. (in &#039;datawindow name|column name&#039; format)\nls_dwcolname = idw.classname() + &#039;|&#039; + adwo.Name\n\n\/\/ Check if column is in the search column array.\nli_index = uf_find_registered_dddw_columns(ls_dwcolname)\nIf li_index &lt;= 0 Then Return\n\/\/ can perform search on the column\nib_performsearch = True\n\n\/\/ Store the current index.\nii_currentindex = li_index\n\/\/ Store the previous text information.\nis_textprev = idw.GetText()<\/pre>\n<p>Three functions<\/p>\n<pre name=\"code\" class=\"VB\">public function integer uf_register_dddw_columns (ref datawindow adw, string as_colname);\n\/\/ set up datawindowchild array\ndatawindowchild ldwc\ninteger li_rc\nlong\tll_ac\nstring ls_desc, ls_val\n\nFOR ll_ac = 1 to Upperbound(is_datawindow)\n\tIF is_datawindow[ll_ac] = adw.classname() + &#039;|&#039; + as_colname THEN\n\t\tRETURN 1 \/\/ already registered\n\tEND IF\nNEXT\n\nll_ac = upperbound(is_datawindow) + 1\n\nis_datawindow[ll_ac] = adw.classname() + &#039;|&#039; + as_colname\n\/\/ need allowedit property set for this functionality to work\n\/\/ this must be done prior to the getchild call\nls_desc = as_colname + &#039;.dddw.allowedit&#039;\nls_val = adw.describe(ls_desc)\nIF ls_val &lt;&gt; &#039;yes&#039; THEN\n\tls_desc += &#039;=yes&#039;\n\tls_val = adw.modify(ls_desc)\nEND IF\n\n\/\/ Get a reference to the DropDownDatawindow.\nli_rc = adw.GetChild(as_colname, ldwc)\nIF li_rc&lt;&gt;1 THEN RETURN -1\nidwc[ll_ac] = ldwc\nRETURN 1\n\n\n\npublic function integer uf_find_registered_dddw_columns (string as_dwcolname);\n\/\/ finds array position of given datawindow name\/column name array\ninteger\tli_count\ninteger\tli_i\n\n\/\/ Get the size of the array.\nli_count = upperbound(is_datawindow)\n\n\/\/ Check for an empty array.\nif li_count &lt;= 0 THEN return 0\n\n\/\/ Find column name in array.\nfor li_i=1 TO li_count\n\tif is_datawindow[li_i] = as_dwcolname THEN\n\t\treturn li_i\n\tend if\nnext\n\/\/ Column name not found in array.\nRETURN 0\n\n\n\npublic subroutine uf_set_current_dw (ref datawindow adw);\n\/\/called from getfocus event on datawindow\twith dddw typeahead capability\nidw = adw<\/pre>\n<p>A couple things of note here. Since the dddw column must be set to allow edit, you will need to have appropriate data checking in the itemchanged event to prevent incorrect entries should the user just type something in and leave the field. Also, if you have defined the datawindow to not allow edits, the NVO will modify the datawindow object to allow it. This means any previous getchild references may be broken once the datawindow is modified.<\/p>\n<p>A sample application is <a href=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2011\/06\/typeahead.zip\">attached<\/a> (PB11.5.1) to demonstrate the functionality.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This type of functionality is one of those things which fills a gap so completely and perfectly that when you encounter some application (and almost all web pages) which doesn&#8217;t have it you groan to yourself. In the ancient past this was alternatively referred to as &#8216;Quicken style&#8217; dropdowns since that application was one very&hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[3,10],"tags":[21,33,12,16],"_links":{"self":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/776"}],"collection":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/comments?post=776"}],"version-history":[{"count":7,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/776\/revisions"}],"predecessor-version":[{"id":1954,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/776\/revisions\/1954"}],"wp:attachment":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/media?parent=776"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/categories?post=776"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/tags?post=776"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}