Subscribe for automatic updates: RSS icon RSS

Login icon Sign in for full access | Help icon Help
Advanced search

Pages: [1] 2
  Reply  |  Print  
Author Topic: Is there a way to enforce AFTER FIELD validation before executing ACTIONS block?  (Read 27487 times)
Huy H.
Posts: 45


« on: July 16, 2018, 10:49:23 pm »

We are getting ourselves in a bit of a pickle with this issue.  Here's a bit of background.  Traditionally, we've been using BUTTONEDIT for our user to enter and store coded values.  For example, a vehicle type could be stored as "C" in the database to represent a car.  With the recent enhancement to Genero's COMPLETER attribute, we've made changes to our BUTTONEDIT widgets.  Now we display both the code and the translation in the input fields, and user can either enter "C" to in the field, or enter "Car" if they prefer the translation value.  Now our BUTTONEDIT content looks like this: [C - Car]

In the AFTER FIELD block, we parse the code from content of the form field, so the above will result in input_record.vehicle_type = "C".  This is all fine in situations where we are dealing with simple inputs where we either accept or abort inputs -- because ACCEPT INPUT automatically triggers the AFTER FIELD code.

The situation that we are running into is in the example below, where this is part of a bigger input:
Vehicle Type [C - Car]
Vehicle Color [          ] [Search]

Suppose the user just type Car and select "C - Car" from the list of suggestions.  At this point, without leaving the current field, the user clicks "Search" -- Search requires you to input both values.  It detected that the vehicle color has not been entered and forces the user to that input field.  The problem now is that NEXT FIELD does not trigger the AFTER FIELD of the current field in focus (probably for a good reason), but now we are ending up with a situation where even after the user enters the second field -- the program variable that represents the first field is never properly assigned because AFTER FIELD of the first field is never triggered. 

We realize that there are ways to brute-force to get around this issue (e.g. automatically parse the coded value in the ON CHANGE), but that would required a lot of code changes, in addition to the performance implication as well trying to validate on an "ON CHANGE". 

It would be nice if we somehow have an attribute on an action where we can force the interactive block to trigger the AFTER FIELD validation, similar to what we have with the VALIDATE attribute of an action -- but we don't.  So if anyone can think of an elegant way to solve this problem, please let us know.
Sebastien F.
Four Js
Posts: 545


« Reply #1 on: July 17, 2018, 09:49:04 am »

Hello Huy,

Seems you are facing the typical 4GL/BDL input field checking issue, where you need to repeat the code in AFTER FIELD and AFTER INPUT (or in an ON ACTION in your case).

I don't think using ON CHANGE will help: For regular fields, ON CHANGE is like AFTER FIELD, except it's triggered only if the field value has changed.
But maybe I am confused by your explanation, you talk about BUTTONEDIT + COMPLETER ... so it's not very clear to me...
=> Please provide a little sample, it's always better than a long explanation!

I assume the [search] button is to run a query based on the values entered in the vehicle type and color, right?

I would suggest to use UNBUFFERED and move all the code checking field values in a function, that you can then call from different places in your INPUT dialog.

Note: It's easier to write a module dedicated to that input, to have the record definition at the module level, so it can be accessed from any function in the module. Think of a .4gl module like a class instantiated once...

I understand your request to have a way to call user-defined validation code for each field, and define this at a single point:
https://4js.com/support/issue/?id=FGL-02377#startissue

Seb

I am not using COMPLETER in this sample, it's just to illustrate the field input checking pattern:

Code
  1. DEFINE rec RECORD
  2.           v_type VARCHAR(30),
  3.           v_color VARCHAR(30)
  4.       END RECORD
  5.  
  6. MAIN
  7.    OPTIONS INPUT WRAP
  8.    OPEN FORM f1 FROM "form1"
  9.    DISPLAY FORM f1
  10.    INITIALIZE rec.* TO NULL
  11.    CALL input()
  12. END MAIN
  13.  
  14. FUNCTION input()
  15.    INPUT BY NAME rec.*
  16.          ATTRIBUTES(UNBUFFERED, WITHOUT DEFAULTS)
  17.        AFTER FIELD v_type
  18.           IF NOT check_values(DIALOG) THEN
  19.              CONTINUE INPUT
  20.           END IF
  21.        ON ACTION search
  22.           IF NOT check_values(DIALOG) THEN
  23.              CONTINUE INPUT
  24.           END IF
  25.           MESSAGE SFMT("Search with %1 and %2",rec.v_type,rec.v_color)
  26.    END INPUT
  27. END FUNCTION
  28.  
  29. FUNCTION check_values(d ui.Dialog)
  30.    IF rec.v_type NOT MATCHES "[CB]*" THEN
  31.       ERROR "Type must start with C or B"
  32.       CALL d.nextField("v_type")
  33.       RETURN FALSE
  34.    END IF
  35.    IF rec.v_color IS NULL THEN
  36.       ERROR "Must enter color to search"
  37.       CALL d.nextField("v_color")
  38.       RETURN FALSE
  39.    END IF
  40.    RETURN TRUE
  41. END FUNCTION
  42.  


Code
  1. LAYOUT
  2. GRID
  3. {
  4. Type:  [f1                         ]
  5. Color: [f2                         ]
  6.                [b1      ]
  7. }
  8. END
  9. END
  10. ATTRIBUTES
  11. EDIT f1 = FORMONLY.v_type;
  12. EDIT f2 = FORMONLY.v_color;
  13. BUTTON b1 : search, TEXT="Search";
  14. END
  15.  
Huy H.
Posts: 45


« Reply #2 on: July 17, 2018, 06:33:53 pm »

Thanks Sebastien.  I've provide the code below -- hope this will make it clearer of what we are trying to do.  It is import that the COMPLETER be part of this sample program -- as that was primary reason behind our current approach.

Code
  1. TYPE vehicle_def  RECORD
  2.         v_type    CHAR(1),
  3.         v_license STRING,
  4.         v_color   STRING
  5.               END RECORD
  6.  
  7. DEFINE all_types DYNAMIC ARRAY OF STRING
  8. DEFINE veh_rec   vehicle_def
  9.  
  10. MAIN
  11.  
  12.   DEFINE v_type  STRING
  13.  
  14.   OPTIONS INPUT WRAP
  15.  
  16.   LET all_types[1] = "BOAT"
  17.   LET all_types[2] = "CAR"
  18.   LET all_types[3] = "MOTORCYCLE"
  19.   LET all_types[4] = "TRUCK"
  20.  
  21.   OPEN FORM f1 FROM "demo"
  22.   DISPLAY FORM f1
  23.  
  24.   INPUT BY NAME v_type, veh_rec.v_license, veh_rec.v_color
  25.   WITHOUT DEFAULTS ATTRIBUTES(UNBUFFERED)
  26.  
  27.     ON CHANGE v_type
  28.       CALL set_completer(DIALOG, v_type)
  29.  
  30.     AFTER FIELD v_type
  31.       IF valid_vehicle_type(v_type) THEN
  32.         LET veh_rec.v_type = parse_vehicle_type(v_type)
  33.       ELSE
  34.         NEXT FIELD v_type
  35.       END IF
  36.  
  37.     ON ACTION search
  38.       IF LENGTH(veh_rec.v_license) = 0 THEN
  39.         ERROR "license required"
  40.         NEXT FIELD v_license
  41.       END IF
  42.       CALL search_vehicle()
  43.  
  44.     ON ACTION accept
  45.       ACCEPT INPUT
  46.  
  47.     AFTER INPUT
  48.       IF NOT validate_vehicle(DIALOG) THEN
  49.         CONTINUE INPUT
  50.       END IF
  51.       CALL add_vehicle()
  52.   END INPUT
  53.  
  54. END MAIN
  55.  
  56. FUNCTION set_completer(d, p)
  57.  DEFINE d ui.Dialog,
  58.         p STRING,
  59.         items DYNAMIC ARRAY OF STRING,
  60.         i INT
  61.  
  62.  IF p.getLength() > 0 THEN
  63.    LET p = p, "*"
  64.    FOR i = 1 TO all_types.getLength()
  65.      IF all_types[i] MATCHES p THEN
  66.        LET items[items.getLength()+1] = all_types[i]
  67.      END IF
  68.    END FOR
  69.  END IF
  70.  CALL d.setCompleterItems(items)
  71. END FUNCTION
  72.  
  73. FUNCTION parse_vehicle_type(v_type STRING)
  74.  IF LENGTH(v_type) > 0 THEN
  75.    RETURN v_type.getCharAt(1)
  76.  ELSE
  77.    RETURN NULL
  78.  END IF
  79. END FUNCTION
  80.  
  81. FUNCTION valid_vehicle_type(v_type STRING)
  82.  DEFINE t CHAR(1)
  83.  IF LENGTH(v_type) > 0 THEN
  84.    LET t = v_type.getCharAt(1)
  85.    IF t MATCHES "[BCMT]" THEN
  86.      RETURN TRUE
  87.    ELSE
  88.      ERROR "invalid vehicle type"
  89.      RETURN FALSE
  90.    END IF
  91.  ELSE
  92.    RETURN FALSE
  93.  END IF
  94. END FUNCTION
  95.  
  96. FUNCTION validate_vehicle(d ui.Dialog)
  97.  IF LENGTH(veh_rec.v_type) = 0 THEN
  98.    ERROR "vehicle type required"
  99.    CALL d.nextField("v_type")
  100.    RETURN FALSE
  101.  END IF
  102.  IF LENGTH(veh_rec.v_license) = 0 THEN
  103.    ERROR "license required"
  104.    CALL d.nextField("v_license")
  105.    RETURN FALSE
  106.  END IF
  107.  RETURN TRUE
  108. END FUNCTION
  109.  
  110. FUNCTION add_vehicle()
  111.  DISPLAY SFMT("add_vehicle(): %1-%2-%3",
  112.          veh_rec.v_type, veh_rec.v_license, veh_rec.v_color)
  113. END FUNCTION
  114.  
  115. FUNCTION search_vehicle()
  116.  DISPLAY SFMT("search_vehicle(): %1-%2-%3",
  117.          veh_rec.v_type, veh_rec.v_license, veh_rec.v_color)
  118. END FUNCTION
  119.  
  120.  
  121.  


Code
  1. LAYOUT
  2. GRID
  3. {
  4. Type:    [f1         ]
  5. License: [f2         ][b1    ]
  6. Color:   [f3         ]
  7.  
  8.          [b2         ]
  9. }
  10. END
  11. END
  12.  
  13. ATTRIBUTES
  14. EDIT f1 = FORMONLY.v_type,UPSHIFT,COMPLETER;
  15. EDIT f2 = FORMONLY.v_license,UPSHIFT;
  16. EDIT f3 = FORMONLY.v_color,UPSHIFT;
  17. BUTTON b1 : search, TEXT="Search";
  18. BUTTON b2 : accept, TEXT="Add/Update";
  19. END
  20.  

If you run the provided sample program and enter CAR | ABC123 | RED, then click Add/Update, you will see all all three field values in veh_rec, in particular, veh_rec.v_type = "C".

Now if you type "CAR" in the vehicle type field, then click "Search", which will validate the License field and put the cursor on the empty license field, while bypassing the all important AFTER FIELD v_type block.  Because the AFTER FIELD block was bypassed, veh_rec.v_type never gets assigned.  If you continue and type "ABC123" in the license field, "RED" in the next field, then click Add/Update -- NOTE that veh_rec.v_type is NULL.

We know that a way around this is by putting the same block of AFTER FIELD code in the AFTER INPUT, but that is not ideal.  Creating a re-usable validation function is possible, but we will likely have to create a function for every single COMPLETER field -- as it cannot be generic.  We have MANY MANY forms that have MANY MANY completer fields.
Sebastien F.
Four Js
Posts: 545


« Reply #3 on: July 18, 2018, 01:07:21 pm »

Thanks for the sample, it clarifies your case.

First understand that this issue is not related to COMPLETER: You can remove the ON CHANGE v_type block, still the validation code in AFTER FIELD has to be executed when needed.

In fact the issue is related to the [Search] button: When the focus is in the v_type field, Genero cannot guess that the code in AFTER FIELD has to be executed when the user clicks on the button. By default the button action must be fired without changing the focus of v_type field: Any button / action can be related to all fields of your form... and the rule is to leave the focus in the current (v_type) field. Fortunately, we have the UNBUFFERED mode to get input buffer validated and copied into the variable, otherwise you would have to get the input buffer of the current field to check values (DIALOG.getFieldBuffer())

So a general validation callback function to be executed for a field would not help here: Anyway it would not be fired when you click on the [Search] button...

BTW I wonder why you are using COMPLETER everywhere in your forms, when a regular COMBOBOX could do the job and save you from writing additional verification code.
Is there a good reason why you don't use COMBOBOXes in this case?
Did you consider ITEMS=(("C","Car"), ("B","Boat"), ... ) ?

Another option could be to use a BUTTONEDIT instead of an EDIT for the v_license field, and attach the search action to it.
By doing this, if the user clicks on the BUTTONEDIT button, the AFTER FIELD v_type block is executed because the focus needs to go to v_license.
If the search function is related / specific to the v_license field, maybe that makes sense.

Try also to use
Code
  1. ON ACTION search INFIELD v_license
and keep the [Search] button detached from the v_license field:
This will force the focus to be into v_license and force the AFTER FIELD to be executed before moving to v_license ...
Using Genero 3.10, check the difference with qualified and unqualified action view in form definition:
Code
  1. BUTTON b1 : search, TEXT="Search";
and
Code
  1. BUTTON b1 : v_license.search, TEXT="Search";
BTW pay attention with qualified action names on BUTTONEDIT, it has changed in latest 3.10 (FGL-4866):
http://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_Migrate_to_310_buttonedit_action.html

Otherwise, if [Search] is a not related to a particular field, the only option I see is to repeat the validation code in ON ACTION search (and AFTER INPUT)...

Seb
Huy H.
Posts: 45


« Reply #4 on: July 18, 2018, 05:25:33 pm »

One of our developers found a work-around to handle this kind of situation where we need the AFTER FIELD to be executed while still continuing the input.  The way we solve this is by triggering the ACCEPT INPUT so that the AFTER FIELD validation of the current field would kick in.  Then within the AFTER INPUT block we force it back to CONTINUE INPUT.   

Code
  1. ON ACTION search
  2.  LET button_action = "search"
  3.  ACCEPT INPUT
  4.  
  5. AFTER INPUT
  6.  IF button_action = "search" THEN
  7.    LET button_action = NULL
  8.    { move original ON ACTION search block of code here }
  9.    CONTINUE INPUT
  10.  END IF
  11.  
  12.  { the usual AFTER INPUT codes }

 
Reuben B.
Four Js
Posts: 1119


« Reply #5 on: July 23, 2018, 03:14:08 am »

With your workaround, wouldn't you find also that any NOT NULL etc validation for ALL the fields in the dialog would be triggered?

With regards Seb's suggestion of UNBUFFERED, it will result in a reduction and simplification of code, and is what you would most likely use if starting from scratch.  To avoid operating in an environment that is a mix of buffered and unbuffered, and the two different coding styles required, it is something you should consider moving to in-between major versions of your product, and changing all of your dialogs to be unbuffered.  It is normally a case of adding ui.Dialog.setDefaultUnbuffered in an initialisation library call, setting validate="no" on certain actions (cancel, help etc) in the 4ad,  and reviewing code that uses the buffer to take account of the fact that the variable has now been populated.

With regards the population of 4gl variable and triggering of AFTER FIELD blocks on ON ACTION, what we are doing is no different to the Informix-4gl ON KEY behaviour.  Like you I found that frustrating and have in the past pushed for something like ... ON ACTION action-name VALIDATE=(NO|BUFFER|FIELD|ACCEPT|ALL) where ...
NONE is the current default buffered 4gl behaviour
BUFFER is the default unbuffered 4gl behaviour where the current field is populated with the value in the buffer
FIELD is as per buffer but also triggers the ON CHANGE, AFTER FIELD block for the current field to ensure that the value of the current field is valid.
ACCEPT is as per current ACCEPT behaviour where AFTER FIELD of current field is triggered and then the AFTER INPUT. 
ALL would trigger AFTER FIELD for every field in the dialog before the AFTER INPUT

At the moment we don't have equivalent for FIELD and ALL, and have to resort to repeatedly putting the calling of variable assigning from the buffer (if not using unbuffered), and validation functions into the ON ACTION.  I perhaps need to modify the concept to include VALIDATE(FIELD=[field1, field2, ...]) to consider the case where two or more fields are required to be valid before the ON ACTION is executed.  But for now if I had a case where I required multiple fields to be valid before triggering an action I would probably code ...

Code
  1. INPUT ... ATTRIBUTES(UNBUFFERED)
  2.  
  3. AFTER FIELD field1
  4.   CALL valid_field1() RETURNING ok, error_text
  5.   IF NOT ok THEN
  6.      ERROR error_text
  7.      NEXT FIELD field1
  8.   END IF
  9.  
  10. AFTER FIELD field2
  11.   CALL valid_field2() RETURNING ok, error_text
  12.   IF NOT ok THEN
  13.      ERROR error_text
  14.      NEXT FIELD field2
  15.   END IF
  16.  
  17. ON ACTION action-name
  18.  -- Ensure that field1 and field2 are valid before calling the action
  19.  CALL valid_field1() RETURNING ok, error_text
  20.   IF NOT ok THEN
  21.      ERROR error_text
  22.      NEXT FIELD field1
  23.   END IF
  24.  CALL valid_field2() RETURNING ok, error_text
  25.   IF NOT ok THEN
  26.      ERROR error_text
  27.      NEXT FIELD field2
  28.   END IF
  29.   -- do the action

Reuben








Product Consultant (Asia Pacific)
Developer Relations Manager (Worldwide)
Author of https://4js.com/ask-reuben
Contributor to https://github.com/FourjsGenero
Reuben B.
Four Js
Posts: 1119


« Reply #6 on: July 23, 2018, 03:38:16 am »

We are getting ourselves in a bit of a pickle with this issue.  Here's a bit of background.  Traditionally, we've been using BUTTONEDIT for our user to enter and store coded values.  For example, a vehicle type could be stored as "C" in the database to represent a car.  With the recent enhancement to Genero's COMPLETER attribute, we've made changes to our BUTTONEDIT widgets.  Now we display both the code and the translation in the input fields, and user can either enter "C" to in the field, or enter "Car" if they prefer the translation value.  Now our BUTTONEDIT content looks like this: [C - Car]

...

I will post separately to make replying easier, but I want to touch on this.  When COMPLETER attribute was implemented, a case was raised internally of how the COMPLETER copes as a BUTTONEDIT replacement.  That is the BUTTONEDIT is being used to enter a database code e.g. C, and allows the user to select from a list that would have C=Car, and would then display Car in a LABEL field to the right of the BUTTONEDIT e.g.

[C^] Car     (where ^ is the BUTTONEDIT button)


Now using COMPLETER the user rather than selecting from a list of C-Car etc, the user could simply type the code if they know it, or if they did not know it, they could type the description e.g. Car, and the completer would offer the code value C, and put that in the underlying 4gl variable.  That is seen in this example https://github.com/FourjsGenero/ex_autocomplete with the second field using airport codes.  The user can type in a City name e.g. Strasbourg and the 4gl variable is populated with the selected 3 letter airport code e.g. SXB. 

The code is not as clean as it should be, and when this was raised internally with our developers, they responded that that was not the expected usage of COMPLETER!!!! 

I would like the COMPLETER functionality enhanced to handle this case better, (ideally as simply as the COMBOBOX handles it with the one or two arguments for setItem).  So I would encourage anyone who has run into this, to make sure they have raised it here or with their support centre.

Reuben






 




Product Consultant (Asia Pacific)
Developer Relations Manager (Worldwide)
Author of https://4js.com/ask-reuben
Contributor to https://github.com/FourjsGenero
Huy H.
Posts: 45


« Reply #7 on: July 23, 2018, 04:46:15 pm »

For the record, we are using UNBUFFERED dialog in all our codes (just as in the sample provided).  Although, the problem I am describing is much like an unbuffered input -- reason being we have two variables to represent one field: veh_rec.v_type is the database field, and v_type is the variable that's tied to the input widget with completer attributes.  I know that the completer is not the issue here, but it provides a context of why we have two variables to represent the same field.

As for the completer usage, we are exclusively using it in BUTTONEDIT widgets with "zoom/lookup" functionality - (see attached image).  It might be a shock to your developers, but for us, where we came from where we use BUTTONEDITs to represent database codes, this was the most natural approach to extend the BUTTONEDIT functionality to make it more user friendly.  We gained a couple of things by doing this: 1) Both code and the translation is show to the user. 2) User can enter values using translation values, not just by codes.

You are spot on regarding the fact that the code is now a bit more complex with the BUTTONEDIT validations:

Code
  1.      ON CHANGE approved_by
  2.        CALL acu_officer_number_autocompleter(DIALOG, go_record.jurisdiction, 3, TODAY, FALSE)
  3.  
  4.      AFTER FIELD approved_by
  5.        CALL acu_officer_number_autocompleter(DIALOG, go_record.jurisdiction, 3, TODAY, TRUE)
  6.        LET completer.approved_by = acu_strip_code(completer.approved_by)
  7.        IF valid_mj_code("officer_number",completer.approved_by,go_record.jurisdiction) = FALSE THEN
  8.          NEXT FIELD approved_by
  9.        END IF
  10.        LET go_record.approved_by = completer.approved_by
  11.        CALL go_load_completer_translations("approved_by")
  12.  

There's quite a bit of things going on here:
1) We have to build the completer string that contains the code and the translation using go_load_completer_translations("approved_by")
2) Build an autocompleter function to suggest values, and possibly prefill if there's only a single match: acu_officer_number_autocompleter()
3) Parse the completer value to get back the database code: acu_strip_code()
4) Validate the parsed code: valid_mj_code() -- this was the only original function that was there prior to our implementation of the completer in for the BUTONEDIT

As you can see from above, we have to deal with synchronization of two variables: go_record.approved_by, and completer.approved_by.  A "combobox-like" implementation of the autocompleter would have probably saved us from this type of scenario.

As for the question of why not just use a combo box?  We have thought about that -- but in many situations, this is not ideal because it would required to fetch a lot of data from the database -- some of our BUTTONEDIT "zoom" selects from tables that can contain hundreds and thousands rows.



* Capture.PNG (2.23 KB, 288x86 - viewed 2350 times.)
Huy H.
Posts: 45


« Reply #8 on: July 23, 2018, 04:48:47 pm »

wrong attachment -- use this one instead.


* Capture.PNG (11.24 KB, 590x196 - viewed 2481 times.)
Enrico S.
Posts: 40


« Reply #9 on: June 21, 2019, 03:22:22 pm »

Hi All.
I have a similar problem but I was unable to find an elegant solution to this problem.
When the user chooses a value in the completer list the field buffer is not loaded, no trigger is fired and the focus stay on the current field.
A sort of AFTER COMPLETION trigger would be useful to be able to force the exit from the current field.

...
ON CHANGE myfield
    CALL fill_proposals (DIALOG, myfield)
...
AFTER COMPLETION
    case
       when infield (myfield)
          next field next - or some other statement
    ...
    end case
Reuben B.
Four Js
Posts: 1119


« Reply #10 on: June 24, 2019, 02:30:39 am »

Hi All.
I have a similar problem but I was unable to find an elegant solution to this problem.
When the user chooses a value in the completer list the field buffer is not loaded, no trigger is fired and the focus stay on the current field.
A sort of AFTER COMPLETION trigger would be useful to be able to force the exit from the current field.

...
ON CHANGE myfield
    CALL fill_proposals (DIALOG, myfield)
...
AFTER COMPLETION
    case
       when infield (myfield)
          next field next - or some other statement
    ...
    end case


I wonder if there is a potential solution using AUTONEXT http://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_FSFAttributes_AUTONEXT.html.

It looked promising applying the following changes to my test program
- add AUTONEXT as attribute for form field entry
- changed field from STRING to an arbitrarily large CHAR e.g. CHAR(50)
- when filling the proposals, pad out with spaces to so that each entry in the list is the length of the CHAR e.g pad with spaces so length is 50
i.e selecting an entry fills out the EDIT field and thus AUTONEXT occured to move focus to next field

Now question for us is at our end, should we require the last two steps or should this be possible with a STRING. ie if AUTONEXT is used with COMPLETER attribute, should that move focus to the next field when user selects an item?  It would seem sensible too, but is there something I might have overlooked.

Reuben

Reuben





Product Consultant (Asia Pacific)
Developer Relations Manager (Worldwide)
Author of https://4js.com/ask-reuben
Contributor to https://github.com/FourjsGenero
Enrico S.
Posts: 40


« Reply #11 on: June 25, 2019, 04:23:47 pm »

Hi, Reuben.
Thanks, I have applied what you suggest.
Unfortunately it works only using the keyboard to choose a row in selection list; not working in case of click on the selection list (the focus stay on the search item), so it cannot fully work around the problem.

Furthermore filling item with trailing spaces looks like a vintage programming style and can have an impact to the field validation if the input cell in form is not large enougth to contain a so filled value.

In my opinion this case need a specific solution to avoid such workaround. This could improve the completer.

Talking about the question at your side, in my opinion the programmer should be able to set the behavior (stay on the field or jump to next field after completion) and to use both char() and string fields.

Best regards.
Enrico

Reuben B.
Four Js
Posts: 1119


« Reply #12 on: June 26, 2019, 12:57:39 am »

Hi, Reuben.
Thanks, I have applied what you suggest.
Unfortunately it works only using the keyboard to choose a row in selection list; not working in case of click on the selection list (the focus stay on the search item), so it cannot fully work around the problem.
Quote

My example was moving onto next field with mouse-click with GDC, not sure what is different with your example.   However I do note that when I try my example with GBC it doesn't.  Something for me to report

Quote
Furthermore filling item with trailing spaces looks like a vintage programming style and can have an impact to the field validation if the input cell in form is not large enougth to contain a so filled value.

In my opinion this case need a specific solution to avoid such workaround. This could improve the completer.

Talking about the question at your side, in my opinion the programmer should be able to set the behavior (stay on the field or jump to next field after completion) and to use both char() and string fields.
I'm not going to disagree about vintage style comment.  One of the nice things about using STRING over CHAR (and same applies DYNAMIC ARRAY over STATIC ARRAY) is not having to worry about picking an arbitrarily large number as the maximum length. 

This behaviour is more a reflection of what AUTONEXT does, that is when a field is full, move onto the next field ie 10 character account code, user keys in 10 characters and focus moves to next field without requiring TAB.  Similarly when using AUTONEXT with a DATEEDIT field, if the formfield has 10 characters it works because selecting date has filled the 10 characters (assuming dd/mm/yyyy).  If the formfield has 12 character, focus won't move to next field.  Hence the trick of padding with spaces to fill the field so AUTONEXT occurs.

It maybe that rather than re-using AUTONEXT,the better long-term solution is for a new keyword or .4st that can be used by DATEEDIT, COMBOBOX, EDIT+COMPLETER and other widgets where final selection is with press of a mouse to signal a move onto next field.  Unfortunately for you, you have raised this topic right on the cusp of a release.

Reuben

Product Consultant (Asia Pacific)
Developer Relations Manager (Worldwide)
Author of https://4js.com/ask-reuben
Contributor to https://github.com/FourjsGenero
Reuben B.
Four Js
Posts: 1119


« Reply #13 on: June 26, 2019, 02:07:25 am »

I tried to apply my AUTONEXT technique to https://github.com/FourjsGenero/ex_autocomplete but I hit another issue in that using keyboard to scroll down list of entries in completer list would also trigger AUTONEXT .  There maybe a workaround but I'll leave it there for the moment and let developers discuss when they have finished wrapping up 3.20

Product Consultant (Asia Pacific)
Developer Relations Manager (Worldwide)
Author of https://4js.com/ask-reuben
Contributor to https://github.com/FourjsGenero
Leo S.
Four Js
Posts: 129


« Reply #14 on: June 26, 2019, 02:22:10 pm »

Loud thinking: If the clients would send ON CHANGE again when the completion was chosen (in other words, flush the field) the 4GL programmer could easily detect the completed case and invoke a NEXT FIELD.
Also for Huy's case the way to invoke AFTER FIELD with the help of ACCEPT INPUT wouldn't be needed.
Existing code will invoke setCompleterItems again with the one and only item already in the field : the client could suppress showing the list in this case (checked with GDC: its the case).
It will be discussed internally and we will come back to this issue.

For the completer discussions:
Sure it would be desirable to have a "translating" completer, meaning the 'C' code is in the INPUT and not the completed text (CAR).
But as far as I understand Huy's comments *both* the code and the completed text are wanted to be visible , so its not an INPUT from just 1 field (if both are wanted we would need to implement a way to express in which field the code has to be displayed)
In any case if you feel a build-in translating completer option (as Huy wrote: A "combobox-like" implementation of the autocompleter) could save you a lot of code, feel free to send in  a feature request via the support centers and illustrate some code samples how you think it should work.

Regards, Leo
Pages: [1] 2
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines