Ask Reuben
Sort, Keep At Top
When sorting in a TABLE, how can I keep rows at the top?
The ui.Dialog.setGroupBy method was introduced in FGL=4.01.03. This provides a way to define a grouping column that the rows in your Table will be grouped by. Rows with the same group value will be kept together.
Any sorting of the table will still keep these rows together and the users sort will be a secondary sort. It is the SQL equivalent of ORDER BY grouping-column [,sort-column]
.
Typically the values in the grouping column will not be unique, and will share a lot of common values. For example city/state/country, or as in my example later a binary value to indicate if selected or not selected.
By selecting an appropriate column, it is possible to ensure that certain rows are always kept at the top of the Table. In the screenshot below, the user has sorted by a Quantity field but the rows that are “Selected” are kept at the top of the table. When a different sort is selected, the “Selected”rows are kept at the top of the table.
The implementation is very simple, simply at the beginning of the dialog add a call to ui.Dialog.setGroupBy with the desired grouping column as the parameter.
The example code for the screenshots is at the end of the article.
Like anything released mid-release, it has not had an Early Access Program to fine tune the concept. One thing that has been pointed out is that the sort order is equivalent of ORDER BY grouping-column [,sort-column]
where sort-column is the table-column chosen by the end-user to sort rows. How do you implement equivalent of ORDER BY grouping-column DESC [,sort-column]
?, that is have the grouping column sorted descending. The answer is to populate the grouping-column appropriately, so in my case it was 0=selected, 1=unselected, as opposed to the more intuitive 0=unselected, 1=selected. Another approach you could have used is to add a column comparison function that reverses the sort collation …
CALL DIALOG.setColumnComparisonFunction(grouping-column, FUNCTION reverse_sort)
FUNCTION reverse_sort(s1 STRING, s2 STRING) RETURNS INT RETURN util.Strings.collate(s1, s2) * -1 END FUNCTION
… but that is a little more tricky with a PHANTOM column as in my example.
So if you have FGL=4.01.03 experiment with this new ui.Dialog.setGroupBy method, and report any improvements for future releases.
#! example 185.4gIMPORT util CONSTANT IMAGE_SELECTED = "fa-check-circle" CONSTANT IMAGE_UNSELECTED = "fa-circle-o" MAIN DEFINE arr DYNAMIC ARRAY OF RECORD available BOOLEAN, selected_img STRING, id INTEGER, desc STRING, qty1 DECIMAL(11, 2), qty2 DECIMAL(11, 2), qty3 DECIMAL(11, 2), qty4 DECIMAL(11, 2) END RECORD DEFINE i INTEGER DEFINE last_row INTEGER WHENEVER ANY ERROR STOP DEFER INTERRUPT DEFER QUIT OPTIONS FIELD ORDER FORM OPTIONS INPUT WRAP CALL ui.Interface.loadStyles("askreuben185.4st") CLOSE WINDOW SCREEN FOR i = 1 TO 26 LET arr[i].id = i LET arr[i].desc = ASCII (64 + i), ASCII (96 + i), ASCII (96 + i) LET arr[i].qty1 = util.Math.rand(100000) / 100 LET arr[i].qty2 = util.Math.rand(100000) / 100 LET arr[i].qty3 = util.Math.rand(100000) / 100 LET arr[i].qty4 = util.Math.rand(100000) / 100 LET arr[i].available = 1 -- all rows unselected to stary LET arr[i].selected_img = IMAGE_UNSELECTED END FOR OPEN WINDOW w WITH FORM "askreuben185" ATTRIBUTES(TEXT = "Ask Reuben 185") WHILE TRUE DISPLAY ARRAY arr TO scr.* ATTRIBUTES(UNBUFFERED) BEFORE DISPLAY CALL DIALOG.setGroupBy("scr.available") --group arrays on the value of this column IF last_row > 0 AND last_row <= arr.getLength() THEN CALL DIALOG.setCurrentRow("scr", last_row) -- put cursor back on previously selected row END IF ON ACTION toggle -- User clicks on this image to change between available/unselected and unavailable/selected LET arr[arr_curr()].available = NOT arr[arr_curr()].available LET arr[arr_curr()].selected_img = IIF(arr[arr_curr()].available==1, IMAGE_UNSELECTED, IMAGE_SELECTED) LET last_row = DIALOG.getCurrentRow("scr") EXIT DISPLAY -- exit array to resort END DISPLAY END WHILE END MAIN
#! example185.per LAYOUT TABLE { [f00 ][f01][f02 ][f03 ][f04 ][f05 ][f06 ] } END END ATTRIBUTES PHANTOM formonly.available; IMAGE f00 = formonly.selected_img, TITLE="Selected", ACTION=toggle; EDIT f01 = formonly.id, TITLE="Id"; EDIT f02 = formonly.desc, TITLE="Description", STRETCH=X; EDIT f03 = formonly.qty1, TITLE="Quantity 1"; EDIT f04 = formonly.qty2, TITLE="Quantity 2"; EDIT f05 = formonly.qty3, TITLE="Quantity 3"; EDIT f06 = formonly.qty4, TITLE="Quantity 4"; INSTRUCTIONS SCREEN RECORD scr(available, selected_img, id, desc, qty1, qty2, qty3, qty4)
<!-- example185.4st --> <?xml version="1.0" encoding="ANSI_X3.4-1968"?> <StyleList> <Style name="Window"> <StyleAttribute name="windowType" value="normal" /> </Style> <Style name="Table"> <StyleAttribute name="headerAlignment" value="auto" /> <StyleAttribute name="alternateRows" value="yes" /> </Style> </StyleList>