LOCATE BUTTON FOR SETS

by Cal Locklin   (CALocklin@aol.com)

Cal shows us a way to create a 'locate text' button for forms containing child browse tables which will
  1. search the first record automatically, and
  2. show each parent record only one time.

PROBLEM: The A5 'Locate' command can create confusion for users in certain circumstances.   First, it will not check the current record.   So, even though my original "Locate" button changed to the first record before starting the 'Locate' command, the first record was not searched.  Second, when multiple child records (in sets) are involved, it will appear to keep 'locating' the same parent record.  This happens because the search looks for the next record and each child record represents a new record - including all the data in the parent record.  Since most users (vs. developers) don't know what's happening, they think something is wrong.

SOLUTION: A Locate button containing the Xbasic script below solves the problem by checking the first record then making sure each subsequent 'Locate' operation starts from the last child record of the current parent.  As added bonuses, it:
- allows the user to select which fields to search.
  (Change the field names to match your own.)
- provides the user a more intuitive way to continue a search.

When the user first clicks the Locate button, he is prompted to type the search text:

Search1

Next is a prompt for which field(s) to search.   Of course, your script will need to be modified to include your own field names.   (This option can be left out and the choice of which field(s) to search would be up to the programmer but I left it in as an example for those who want to use it.)

Search2

When the user selects which field to search, the search is completed and the user is left in the 'located' record.
Note:  On the line with "All" I added reference to the various tables in my set.  This is used to remind the user that all fields in all tables will be searched - not just the ones shown on the screen. Elsewhere in my application, I have included a Help file with more description of how the Locate button works.  


When the user has already run a 'Locate' operation during the current session, the first prompt will be different.  The first prompt will be for a 'search type'.  This allows a choice between a "New" search and "Locate Next".  The search text from the last search is included in the "Locate Next" line as a reminder.


Search3

If "Locate Next" is chosen, the locate operation runs immediately. If "New" is chosen, the program goes through the "TEXT TO SEARCH FOR" and "FIELDS TO SEARCH" prompts shown above.


To continue a previous search, the user can simply press the Enter button twice - once to active the Locate button and again to activate the search.   (This assumes, of course, that the user has not moved the cursor from the Locate button and that the programmer leaves "Locate Next" as the default selection for "SEARCH TYPE".)



If the search is run and no more records are found, the user is notified:

Search4

(Did you catch the title in that last pop up?   In the script for my own application, I actually print the name of the current index to avoid confusion about which records were searched.   That adds a bit more complexity and I didn't want to make this presentation any more difficult to explain.  Anyone who wants a copy of the script which includes this feature, e-mail me at CALocklin@aol.com.)

The comments in the script provide additional information about what the program does and how it works.

AND NOW THE SCRIPT:

DIM GLOBAL global_search_text as c
DIM GLOBAL global_search_field as c

'---------------------------------------------------------------------------------
' MAKE SURE THE USER ISN'T STILL ENTERING/MODIFYING THE CURRENT RECORD.
'---------------------------------------------------------------------------------
stbl=table.current()
IF stbl.mode_get() > 0
  ui_msg_box( "ERROR", "In data entry mode.   Please save record before running\
the LOCATE operation.", 48)
  END
END IF

'---------------------------------------------------------------------------------
' IF DESIRED, THIS SECTION CAN BE USED TO INFORM THE USER HOW THE BUTTON WORKS.
'---------------------------------------------------------------------------------
'response=ui_msg_box( "INFORMATION", \
'"This command will find the FIRST occurrence of the text you enter." +chr(013)+ \
'"- To find additional occurrences, simply press the ENTER key twice." +chr(013)+ \
'"- Repeat this sequence until you see the message box 'No more occurrences found'.", \
'UI_INFORMATION_SYMBOL+UI_OK_CANCEL )
'IF response=ui_cancel_selected
'   END
'END IF

'---------------------------------------------------------------------------------
' IF NO global_search_text EXISTS, THIS ROUTINE HAS NOT BEEN RUN BEFORE IN
' THIS SESSION SO IT MUST BE A NEW SEARCH.
' OTHERWISE, FIND OUT WHETHER TO REPEAT THE PREVIOUS SEARCH OR START A NEW ONE.
'---------------------------------------------------------------------------------
IF global_search_text=""
  search_type="New"
ELSE
  search_type=ui_get_list( "SEARCH TYPE", 1, "Locate Next '" + global_search_text + "'", "New" )
     IF search_type=""
        END
     END IF
END IF

'---------------------------------------------------------------------------------
' IF IT IS A NEW SEARCH, FIND OUT WHAT TEXT TO SEARCH FOR AND WHICH FIELD(S)
' TO SEARCH. THEN, SEARCH THE FIRST RECORD.
' *NOTE*:   GOING TO THE FIRST RECORD AND DOING A .fetch_loc_next WILL NOT
'          SEARCH THE FIRST RECORD.
'---------------------------------------------------------------------------------
IF search_type="New"
  global_search_text=ui_get_text( "TEXT TO SEARCH FOR", "Enter search text - caps not\
important.", global_search_text )
  IF global_search_text=""
     END
  END IF
  global_search_field=ui_get_list( "FIELD TO SEARCH", 1, "Status", "Description",\
"All - Task, Project, Actions" )
  IF global_search_field=""
     END
  ELSE
     IF global_search_field="All - Task, Project, Actions"
        global_search_field=""
     END IF
     '---------------------------------------------------------------------------
     ' THIS AREA CAN BE MODIFIED TO ALLOW YOU TO ASK FOR A GENERIC
     ' FIELD NAME THAT THE USER UNDERSTANDS AND THEN CONVERT TO
     ' THE REAL FIELD NAME.
     ' ex: IF global_search_field="Status"
     '            global_search_field="Stat_1"
     '       END IF
     ' THIS COULD EVEN BE EXPANDED TO WORK WITH MULTIPLE FORMS BY
     ' CHECKING THE FORM NAME. CONTACT CALocklin@aol.com FOR MORE INFO.
     '---------------------------------------------------------------------------
  END IF
  '------------------------------------------------------------------------------
  ' CHECK THE FIRST RECORD BY GOING TO THE SECOND RECORD THEN SEARCHING BACKWARD.
  '------------------------------------------------------------------------------
  stbl.fetch_first()
  stbl.fetch_next()
  found=stbl.fetch_loc_prev( global_search_text, global_search_field )
  IF found
     parentform.resynch()
     END
  ELSE
     '---------------------------------------------------------------------------
     ' IF "fetch_loc_prev" DOESN'T FIND IT, THE POINTER STAYS IN THE SECOND
     ' RECORD. THIS LINE TAKES YOU BACK TO THE FIRST RECORD SO THE SEARCH CAN
     ' CONTINUE LATER.
     '---------------------------------------------------------------------------
     stbl.fetch_first()
  END IF

ELSE '--- search_type *NOT* "New"
  current_rec=table.current().recno()
  '------------------------------------------------------------------------------
  ' FIND NEXT *PARENT* RECORD (next RECORD could be just a new child record.)
  ' USING A "1" IN THE .fetch_next() FETCHES ONLY THE PARENT TABLE.
  '------------------------------------------------------------------------------
  table.current().fetch_next(1)
  '------------------------------------------------------------------------------
  ' IF THE 'NEXT' PARENT RECORD IS THE SAME AS THE CURRENT RECORD, THEN WE WERE
  ' ALREADY IN THE LAST RECORD. OBVIOUSLY NOTHING ELSE TO SEARCH.
  ' OTHERWISE, BACK UP ONE RECORD TO THE LAST CHILD RECORD OF THE 'CURRENT'
  ' RECORD. BY STARTING THE NEXT SEARCH AT THE LAST CHILD RECORD OF THE CURRENT
  ' PARENT RECORD, WE WILL NOT BE CHECKING THE CURRENT RECORD AGAIN.
  '------------------------------------------------------------------------------
  next_rec=table.current().recno()
  IF current_rec=next_rec
     ui_msg_box( "DONE", "No more occurrences found.")
     END
  ELSE
     table.current().fetch_prev()
  END IF

END IF

'---------------------------------------------------------------------------------
' THIS IS THE NORMAL 'LOCATE' ROUTINE USED TO SEARCH EVERYTHING BUT THE FIRST
' RECORD. ALSO, IT IS NOT USED IF THE TEXT WAS ALREADY FOUND IN THE *LAST* RECORD.
'---------------------------------------------------------------------------------
found=stbl.fetch_loc_next( global_search_text, global_search_field )

'---------------------------------------------------------------------------------
' WARN THE USER IF NOTHING WAS FOUND.
'---------------------------------------------------------------------------------
IF .not.found
  ui_msg_box( "DONE", "No more occurrences found.")
ELSE
  parentform.resynch()
END IF

END

12/4/99

Don't forget, we need your feedback to make this site better!

Return to home