Why can I sort columns in a browser? - openedge

Normally StackOverflow questions are of the form "I don't know how to do something.", but this one is of the form "I know how to do something, but I don't understand why it works.".
More exactly, I'm clicking on the title column of a browser inside a regular window, and then the MOUSE-SELECT-CLICK event is triggered, causing the corresponding column to be sorted, ascending or descending, as you can see in the following source code:
DEFINE BROWSE browser-object
QUERY browser-object DISPLAY
temp_table.Field1 FORMAT ... COLUMN-LABEL "Label1"
temp_table.Field2 FORMAT ... COLUMN-LABEL "Label2"
...
DEFINE VARIABLE L-logical-Field1 AS LOGICAL INITIAL TRUE.
DEFINE VARIABLE L-logical-Field2 AS LOGICAL INITIAL TRUE.
...
ON MOUSE-SELECT-CLICK OF temp_table.Field1 IN BROWSE browser-object
DO:
IF L-logical-Field1
THEN OPEN QUERY browser-object FOR EACH temp_table BY temp_table.Field1.
ELSE OPEN QUERY browser-object FOR EACH temp_table BY temp_table.Field1 DESC.
L-logical-Field1 = NOT L-logical-Field1.
END.
ON MOUSE-SELECT-CLICK OF temp_table.Field2 IN BROWSE browser-object
DO:
IF L-logical-Field2
THEN OPEN QUERY browser-object FOR EACH temp_table BY temp_table.Field2.
ELSE OPEN QUERY browser-object FOR EACH temp_table BY temp_table.Field2 DESC.
L-logical-Field2 = NOT L-logical-Field2.
END.
This is working:
When I click on the title of the column, the column gets sorted. When I click elsewhere in the column, nothing happens.
But WHY does it work? In the source code I have written what to do when I click in the column ANYWHERE, I did not specify that the title column should be clicked, but still it's working.
You can say "Yes, so what? It's working, so what's the big deal?", but I fear that later the customer might ask me to program some behaviour when the column is clicked above a certain tuple and asks me to do something with that particular tuple, and I won't have the smallest idea how to start.
Does anybody have an idea?

To see what is being executed, you can make use of the log-manager with entry type 4glTrace.
ON ALT-CTRL-H ANYWHERE DO:
IF LOG-MANAGER:LOGFILE-NAME = ? THEN DO:
LOG-MANAGER:LOGFILE-NAME = "4gltrace.log".
LOG-MANAGER:LOG-ENTRY-TYPES = "4GLTRACE:2".
MESSAGE "Started logging. Press Ctrl+Alt+H again to stop.":u VIEW-AS ALERT-BOX.
END.
ELSE DO:
LOG-MANAGER:CLOSE-LOG().
OS-COMMAND NO-WAIT VALUE( "4gltrace.log" ).
END.
RETURN NO-APPLY.
END.

Related

How to validate against item master table

I am creating a custom report screen in which I have a fields item number, item type, prod line and status and there is a condition for item number that is I have to validate it against pt_mstr which from what i understand means that the item number that I enter should be present in pt_mstr. And if it's blank then give an error. I've done the validation for blank with this code
If lvc_part = "" then do:
{us/bbi/pxmsg.i &msgnum=40 &errorlevel=3}
Undo mainloop, retry mainloop.
End.
Lvc_part is the variable i declared for item number and mainloop is the loop inside which I'm writing my entire logic. I am getting the general idea for validating item number against pt_mstr but I'm not getting how to put it down as a code. I'm thinking we need to include a find first query to see if the item number is present in pt_mstr or not but I'm not sure. Any leads would be helpful, if you want to know anything regarding the declarations I've used or anything else let me know. Thanks in advance!
You need to add code like this
IF NOT CAN-FIND (FIRST pt_mstr WHERE pt_mstr.<keyfieldname> = lvc_part) THEN
<display error message>
or when it's a index with multiple fields:
IF NOT CAN-FIND (FIRST pt_mstr WHERE pt_mstr.<keyfieldname1> = lvc_part
AND pt_mstr.<keyfieldname2> = <value>) THEN
<display error message>
Most likely you can (and should) leave out the FIRST phrase in the CAN-FIND expression as typically you'd be using a UNIQUE find here.

select date field from SQL datasource in appmaker based on drop down value

I can not post a comment to another question that exists out there, so I am asking my own question. I have a drop down, that consists of "employee name". I want a date box to auto-populate based on the result of the name selected. I.E. John Smith is selected and his DOB is 01/02/1987, I want this second box to return 01/02/1987.
Things I have tried:
Server side script function, calling function -- RESULT: Function not found
Client side script function, Calling function -- RESULT: function found, but can't find references to datasources
On another post, someone recommended doing options in the dropdown to being #datasources.Events.items and then the onChangeEvent being widget.root.descendants.DateBox1.value = newValue.Date;
I have tried this, however, I can not stop the "options" at "items". I am required to proceed through to items.projects.fieldName. Since I am selecting the fieldName on requirement, the newValue isn't returning the date based off that field. It simply says "undefined value"
How should I populate one date box based on the result set of the dropdown box?

If else loop in robot framework

There are 3 set of records which I want to capture from an external excel sheet to follow the data driven approach. Scenario: There are 5 fields in the online screen: Grp No/Blclass/Bnk Code/Brnc Code and Acct No.
Now upon providing the grp and blclass and click on "Create", then the other 3 fields will get enabled for data input and when data input done for all fields, the clicking on submit will successfully complete the transaction input for a particular row from external excel.Then it will pick the second record from excel and do the same and so on... Now the scenario is Suppose for the second record,if the acct no is wrong, then it will show an online error and will not allow user to "Submit". At the same time, the header section(grp and billing class) will not be enabled for inputting the next data until user click the exit button because of that online error.
Now I am new in Robot Framework and tried with "Run Keyword If" but somehow it did not work.
Here are the code that I have used. If all the data in the excel are correct, then it will input the transaction one by one for all rows. But,if any wrong data found, my purpose is to skip that input and proceed for the next record as below.
Objective after clicking Submit Button:
If error found, click Exit button and input the next record - as without exit, the header fields will not be enabled for data input
Else input the next record as per loop
You can try :
Run Keyword If '<condition1>' == '<value1>'
... ELSEIF '<condition2>' == '<value2>'
... ELSE <value3>
This works for me.

AX 2009: Report Range on enums parsing enum value commas?

I think I may have found an interesting bug with AX 2009, and I'm unsure of how I can proceed.
I am attempting to write a new report, and one of the conditions of this report is to be filtered based on the Posting field of the LedgerTrans table. However, it seems that when the report goes to execute, the label of the enum Purchase, receipt is parsed without regard to the quotes. This normally wouldn't be a problem, but the enum label in this case contains a comma. The result is that when run the query dialog box reads: Purchase, consumption, __ILLEGAL_VALUE__. I get this result even if I use the enum value or name. The report must be left interactive, but this field must be locked, so we cannot get the users to adjust the query at run time.
At this point I don't want to change the label itself, but if it is the only way to solve this I will. Has anyone else run into this, or know how we could overcome it?
I've run into this before. Sometimes an acceptable option is hard-coding the conditional values as an OR statement, rather than the comma separated list:
((LedgerTrans.Posting == LedgerPostingType::PurchReceipt) || (LedgerTrans.Posting == LedgerPostingType::PurchConsump))
That can be typed into a range filter box, or can be set as the value of a range via x++ code:
ledgerPostingRange.value("((LedgerTrans.Posting == LedgerPostingType::PurchReceipt) ||
(LedgerTrans.Posting == LedgerPostingType::PurchConsump))");
AX doesn't try to convert these to the labels, so they stay as distinct values, instead of being rendered as labels. Note that parentheses are required for it to be parsed properly.
Since the ILLEGAL_VALUE can appear even when attempting to use a single value that contains a comma in its label, the same can be done for a single :
ledgerPostingRange.value("(LedgerTrans.Posting == LedgerPostingType::PurchReceipt)");
I would definitely change the label! But as a workaround you could use the enum value's number instead.
If the field is often queried, you could put the field in a dialog then change the query:
ledgerPostingRange.value(ledgerPostingType ? int2str(ledgerPostingType) : '');

Populate a form from a select list

I have tried multiple attempts at populating a report from selecting a value in a select list. I have come close but not close enough for the right answer. Does anyone have a solution?
Here is the code
Currently I have a select list that has the option of choosing an employees track and the employees track is populated in the select list based on :app_user.
List of Values
List of values definition:
SELECT track_name AS display_value,
track_id AS return_value
FROM ref_track
ORDER BY 1
Source Value for select list:
SELECT "REF_TRACK"."TRACK_NAME" AS display_value,
"REF_TRACK"."TRACK_ID" AS return_value
FROM "REF_STAFF",
"REF_PLAN",
"WORK_ITEM",
"REF_RELEASE",
"REF_TRACK"
WHERE "REF_RELEASE"."RELEASE_ID" = "REF_PLAN"."RELEASE_ID"
AND "REF_TRACK"."TRACK_ID" = "REF_PLAN"."TRACK_ID"
AND "WORK_ITEM"."WR_ID" = "REF_PLAN"."WORK_ITEM_ID"
AND Nvl("REF_STAFF"."REF_STAFF_TRACK_ID", "REF_PLAN"."TRACK_ID") =
"REF_PLAN"."TRACK_ID"
AND (( "REF_STAFF"."STAFF_USER_ID" = :APP_user ))
I now have a report beneath it that is being populated when the page loads that also generates data based on :App_user.
Report Source Code:
SELECT "REF_PLAN"."PLAN_ID" "PLAN_ID",
"REF_PLAN"."WORK_ITEM_ID" "WORK_ITEM_ID",
"REF_PLAN"."TRACK_ID" "TRACK_ID",
"REF_PLAN"."PLANNED_TOT_HRS" "PLANNED_TOT_HRS",
"REF_PLAN"."PLAN_START_DATE" "PLAN_START_DATE",
"REF_PLAN"."PLAN_END_DATE" "PLAN_END_DATE",
"REF_PLAN"."COMMENTS" "COMMENTS",
"REF_PLAN"."RELEASE_ID" "RELEASE_ID",
"WORK_ITEM"."WR_ID" "WR_ID",
"WORK_ITEM"."WR_NUM" "WR_NUM",
"REF_RELEASE"."RELEASE_ID" "RELEASE_ID2",
"REF_RELEASE"."RELEASE_NUM" "RELEASE_NUM",
"REF_TRACK"."TRACK_ID" "TRACK_ID2",
"REF_TRACK"."TRACK_NAME" "TRACK_NAME",
"REF_STAFF"."REF_STAFF_TRACK_ID" "REF_STAFF_TRACK_ID",
"REF_STAFF"."STAFF_USER_ID" "STAFF_USER_ID"
FROM "REF_STAFF",
"REF_PLAN",
"WORK_ITEM",
"REF_RELEASE",
"REF_TRACK"
WHERE "REF_RELEASE"."RELEASE_ID" = "REF_PLAN"."RELEASE_ID"
AND "REF_TRACK"."TRACK_ID" = "REF_PLAN"."TRACK_ID"
AND "WORK_ITEM"."WR_ID" = "REF_PLAN"."WORK_ITEM_ID"
AND Nvl("REF_STAFF"."REF_STAFF_TRACK_ID", "REF_PLAN"."TRACK_ID") =
"REF_PLAN"."TRACK_ID"
AND (( "REF_STAFF"."STAFF_USER_ID" = :APP_USER ))
AND "REF_PLAN"."TRACK_ID" = :P47_TRACK_LIST
I tried adding this line to pick from the select list.
Is there any way to manipulate this code to be able to select a track from my list and populate data based on the track selection in my report. I would also like to let you know that my select list values are based on a submit page. Please let me know if you can help me. Its frustrating when I look at something for a complete day and cant figure the code out. Also, if there is any other way around it or other options to explore please let me know.
If you want the report to update when you change the selected value of the select list, you can do this in 2 ways. But both come down to the same principle: your selected value has to be submitted to the session state in order for the report to filter on it.
Solution 1: have the select list submit/redirect the page. This will submit the value of your select list to the session, and reloads the page. With the redirect you will fill up the browser history though: select a value a couple of times, and you use 'back' on the browser to navigate back through the choices you made. Or use a submit, this'll reload the page too, but won't fill the history as much. There'll still be one extra history entry though (initial, and first reload, following reloads are not in history).
Find the option by editing your select list, going to the Settings region, and change the page action when value changed.
Solution 2: refresh the report region through a dynamic action. This will not reload the page, it'll 'refresh' just your report. This might be the most userfriendly, it depends if you like a page reload or not :)
You'll need a dynamic option, configured like this:
With these true action details:
And most important, to make sure your selected value is submitted to the session state: add the item to the list of items to be submitted when the report is refreshed.
I set up an example here

Resources