Subscribe for automatic updates: RSS icon RSS

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

Pages: [1]
  Reply  |  Print  
Author Topic: Exiting a display array by switching folder pages.  (Read 74691 times)
Ben R.
Posts: 28


« on: January 16, 2014, 09:58:24 pm »

I've got a set of 5 folder pages, each with a table and display array within. I've tied an action to each page to enter the display array. What I'd like to have happen is for switching to another tab to exit the current display array and then enter the array on the next tab. I'm only able to get haflway there, however, and that's by calling on ON ACTION exit display for each tab in the before display section of each array. Once the tab is touched the display array exits, then hitting the tab again triggers the display array for the tab that's hit.

Here is the code so you can see what I'm talking about:

The layout+action assignment:

Quote
FOLDER nm_bottom_folder
PAGE p0(Text="Invoices", action=viewinvoices)
TABLE
{
 Invoice  S  Class       Doc Date   Due Date   Amount      Tax      Freight  Balance    Age   Cmts
[C0     ][C1|C2        ][C3       ][C4       ][C5        ][C6     ][C7     ][C8        ][C9  ][CA ]
}
END -- TABLE
END -- PAGE

The function calls from the action:

Quote
ON ACTION viewinvoices CALL view_invoices()
ON ACTION viewoverterms CALL view_over_terms()
ON ACTION viewassociated CALL view_associated()
ON ACTION viewopenorders CALL view_open_orders()
ON ACTION viewhistory CALL view_history();

One of the functions:

Quote
  function view_invoices()
  display array p_invoices to s_invoices.*
    before display
      ON ACTION viewinvoices exit display
      ON ACTION viewoverterms exit display
      ON ACTION viewassociated exit display
      ON ACTION viewopenorders exit display
      ON ACTION viewhistory exit display
  end display
end function

As you can see, with five tabs and five functions, I'm having to have 30 lines (the before display section) of repetition. While this is doable, it's not ideal to have to repeat that much code. Is there another approach that would work better for this? Having to call exit display from within the display array block seems to lock me into the way I'm doing it now, but I can't figure out a way to attach an action to the generic behavior of clicking on any folder tab. That's what my first thought was--assign an action to the folder, which could hopefully be triggered whenever a folder page was touched.

Any thoughts?
Reuben B.
Four Js
Posts: 1049


« Reply #1 on: January 16, 2014, 10:30:28 pm »

Ben,

Are you aware of the multi-dialog funcitonality that was introduced in Genero 2.10 many years ago? https://4js.com/online_documentation/fjs-fgl-manual-html/#c_fgl_multiple_dialogs_001.html

You would have something like

Code
  1. DIALOG
  2.   DISPLAY ARRAY p_invoices TO s_invoices.*
  3.   END DISPLAY
  4.   DISPLAY ARRAY p_overterms TO s_overterms.*
  5.   END DISPLAY
  6.   DISPLAY ARRAY p_associated TO s_associated.*
  7.   END DISPLAY
  8.   DISPLAY ARRAY p_openorders TO s_openorders.*
  9.   END DISPLAY
  10.   DISPLAY ARRAY p_history TO s_history.*
  11.   END DISPLAY
  12.   ON ACTION close
  13.      EXIT DIALOG
  14. END DIALOG

That could produce quite long code blocks and was improved even further in the more recent Genero 2.5 release with the SUBDIALOG clause https://4js.com/online_documentation/fjs-fgl-manual-html/#c_fgl_multiple_dialogs_SUBDIALOG.html

which enables you to put each of those sub-dialogs in a separate block of code so something like ...

Code
  1. DIALOG
  2.   SUBDIALOG invoices
  3.   SUBDIALOG overterms
  4.   SUBDIALOG associated
  5.   SUBDIALOG openorders
  6.   SUBDIALOG history
  7.   ON ACTION close
  8.      EXIST DIALOG
  9. END DIALOG
  10.  
  11. DIALOG invoices()
  12.   DISPLAY ARRAY p_invoices TO s_invoices.*
  13. END DIALOG
  14.  
  15. and so on

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


« Reply #2 on: January 17, 2014, 08:40:03 am »

hi Ben,
even for me, a dialog with more display array could help, with last version of BDL also use subdialog cause

a function like this:
....
define w ui.Window
define f ui.Form

let w = ui.Window.getCurrent()
let f = w.getForm()

call f.ensureElementVisible("name_of_the_page")

...

could be useful !

by !
Ben R.
Posts: 28


« Reply #3 on: January 17, 2014, 06:33:36 pm »

Reuben,

That looks like it'll work, thanks. It does introduce a new problem in that the tabs trigger the dialog action, so no matter which tab is clicked the program switches to the first tab and the display array in it. I imagine I can check the tab value before enter the dialog, then have the dialog call the return to that tab as a workaround.
Ben R.
Posts: 28


« Reply #4 on: January 23, 2014, 09:40:36 pm »

Connected to the same issue, but slightly different, so I can create a new topic if necessary:

One issue with the folder pages and display array is that for some reason the non-default tab doesn't populate more than 1 row of data when first opened. I open the application, pull up the record, and when I go to the Over Terms tab, there's one line. I re-find that customer record and on the 2nd display it shows the additional 4 lines of data. Basically until I've clicked on the tab, the screen array isn't filling with more than one row.

Here are a couple of screen shots to illustrate the issue:




Absolutely nothing changes between the two shots except in the 2nd one I've opened the Over Terms history before pulling up the customer record. If I go back to the Invoices tab and then pull up another customer, the Over Terms tab is properly populated; for whatever reason it just needs to be accessed once to begin populating data correctly.

Any ideas on what's going on here? Here is the code that feeds the screen arrays:

Quote
    let n = p_invoices.getlength()
    for i = 1 to n step 1
      display p_invoices.* to s_invoices.*
    end for

    let n = p_over_terms.getlength()
    for i = 1 to n step 1
      display p_over_terms.* to s_overterms.*
    end for

Additionally, I did ctrl-right click prior to the data reload and verified that there is no data in the table beyond the first row. I also tried "call ui.Interface.refresh()" after displaying to s_overterms and that did not have any effect.

Any ideas on this?
Bryce S.
Posts: 52


« Reply #5 on: January 23, 2014, 10:33:11 pm »

I think I've seen something like this before, some time back now however I can't recall the specifics...

Are you using:
  dialog attributes (unbuffered)
What happens if you do?

I think just loading the array should be enough to populate them on the screen, won't need to do the for loop with display variable to screen_array

Regards,
  Bryce Stenberg.
Ben R.
Posts: 28


« Reply #6 on: January 23, 2014, 10:38:01 pm »

Bryce,

The looping code I showed above was part of the initial load of the header/table data for the particular customer I've got pulled up. I'm not doing dialog or display array because I don't want the program to actually enter the table until they specifically decide to; once they hit a detail button a dialog is launched which then does the display array p_invoices to s_invoices and p_over_terms to s_overterms. That part actually works fine--when the button is pressed and the display array command is triggered, all of the data correctly populates at that time as well. It's only on the initial load that there is an issue.

If there's a way to do a display array on the initial load without it forcing the user into the table, I'm not aware of it. The for loop was a workaround to get the data into the table without actually using display array.
Sebastien F.
Four Js
Posts: 509


« Reply #7 on: January 24, 2014, 09:51:50 am »

Ben,

The only way to handle your case properly is to use multiple dialogs, as suggested by Reuben:

Your form has a tab with a TABLE that can be accessed by the users. The users will want to resize the window, scroll in the list of records. To do so, you need to implement a dialog (DISPLAY ARRAY) that will act as a controller for this view and feed the TABLE with rows. Any other solution will make your code complex, for a result that will not satisfy end users.

Seb
Ben R.
Posts: 28


« Reply #8 on: January 24, 2014, 04:26:35 pm »

Sebastien,

I'm using multiple dialogs as Reuben suggested to actually navigate within the tables on each tab. The issue here is in loading the data in the tables initially for simple viewing at a quick glance without making the customer enter the tables. For example, this program lets me look up a customer, shows that customer's information in the header section, and then provides a set of tabs with tables for related information like invoices, open orders, and the like. It's pretty common to have the program bring back info for multiple customers, however. If I pull up a set of ten customers then try to switch between them with next/previous, if I'm using a dialog with display arrays to load the data for the initialization to the tables, I'm stuck automatically entering a display array immediately upon the customer loading. If I want to cycle through a set of customers I have to exit the array, hit next, exit the array, hit next, etc..

The workaround I came up with is the above approach; I load the data using a for loop and display to for each array, then provide the user with a button to trigger the dialog with the set of display arrays if they actually want to browse within the tables on each tab.

Just to reassure you that I'm using dialog, though not until the user hits a button to trigger it, here is what the dialog looks like:

Quote
    DIALOG
      display array p_invoices to s_invoices.*
        before row
          if p_invoices.getlength() != 0 then
            call get_comments(p_invoices[arr_curr()].c_invoice, p_invoices[arr_curr()].c_invoice_seq)
          end if
        ON ACTION browse display array p_notes to s_notes.*
        end display
      end display
      display array p_over_terms to s_overterms.*
        before row
          if p_over_terms.getlength() != 0 then
            call get_comments(p_over_terms[arr_curr()].f_invoice, p_over_terms[arr_curr()].f_invoice_seq)
          end if
          ON ACTION browse display array p_notes to s_notes.*
        end display
      end display
    on action close
      exit dialog
    end dialog

The program works perfectly except for the initial load and tab. When the program is first started, it doesn't load more than a single line of data to any of the tables in the non-default tabs (image 1 above.) After I go to any tab and then pull up the same customer, the tabs begin populating correctly. The data is clearly loading into the p_arrays above correctly, it's just that the screen arrays on non-visited tabs are not populating until those tabs have been visited. It doesn't matter how I do it; once I've clicked on any tab and then pull up another record, the issue is resolved until the next time I close and reopen the application. If I pull up a set of 20 customers, click on the Open Orders tab, I'll get one row of data even for a customer with 3 open orders; I hit next to get to the next customer and it populates correctly with 7 orders. If I hit back to go to the previous customer, the issue is now resolved and they have 3 orders listed correctly.

To reiterate: The specific issue I'm having here is that table data not loading into non-default tabs until I've visited the tab. Once I've done that and pull up another record, it works fine. So there's something about the way the screen arrays are being treated that limits them to one row apiece until an alternate tab has been visited; it doesn't matter which tab, any tab fixes the problem for all of them. Even if I have a grid on a tab instead of a table section, if I visit that grid tab the issue is resolved until I restart the application.

Any ideas what would cause this?
Bryce S.
Posts: 52


« Reply #9 on: January 26, 2014, 09:07:09 pm »

Hi Ben,

I had something similar with input arrays back in 2009, I had to use a 'before insert' rather than a 'before row' to fix it.
Maybe a 'before display' will initialise better than a 'before row' in your case?

Regards, Bryce Stenberg.
Reuben B.
Four Js
Posts: 1049


« Reply #10 on: January 27, 2014, 09:40:35 am »

Ben,

I was on holiday last week, but I was wondering if you had seen this forum entry from a few years ago

https://4js.com/fjs_forum/index.php?topic=291.0

I suspect that explains why one row was visible.

The other thing was you originally said ...

Code
  1. It does introduce a new problem in that the tabs trigger the dialog action, so no matter which tab is clicked the program switches to the first tab and the display array in it.

With folder tabs, the tab that currently has the field that has focus will be visible.  If you want a different page to appear, have a look at ui.Form.ensureFieldVisible or ui.Form.ensureElementVisible https://4js.com/online_documentation/fjs-fgl-manual-html/?path=fjs-fgl-manual#c_fgl_ClassForm_ensureFieldVisible.html

Hope that helps,

Reuben

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


« Reply #11 on: February 03, 2014, 10:18:35 pm »

Reuben,

It does help, thank you. Knowing that I wasn't doing something incorrectly and that this is just a built-in limitation allowed me to figure out a workaround. I ended up creating a new function for each tab, then assigning that action to the page elements like this:

Quote
PAGE p1(Text="Open Orders", action=fill_orders)

Then the function:

Quote
  function fill_orders()
    let current_tab = "s_openorders.ord_ordno"
    display array p_open_orders to s_openorders.*
      before row
        exit display
    end display
  end function

This forces the application to display the array to the tab correctly whenever a tab is clicked. Depending on the amount of data there can be a hesitation as the data populates, but the delay is pretty minimal.

Regarding the page visibility, we're on 2.11 and so that functionality is not available. I ended up getting around it by using the current_tab variable as shown above, then in the dialog I'm doing this:

Quote
    DIALOG
      display array p_invoices to s_invoices.*
        before row
          if current_tab != "s_invoices.c_invoice" then
            call dialog.nextfield(current_tab)
          end if

Also in earlier code I initialize current_tab to the above value (s_invoices.c_invoice) to account for somebody entering the dialog without first clicking a tab. This approach seems to work pretty well. There may be a better approach for those limited to an older version of the Genero, but within these limitations I can't think of anything better to do.
Jeff M.
Posts: 38


« Reply #12 on: February 05, 2014, 12:30:09 pm »

Hi Ben,

I might be missing the point but I don't understand why you are exiting the dialog to get the next customer. If you fully embrace the multiple dialogs this should replace any menu you are currently using for navigation.

If you are using dynamic array's for the tables and DIALOG ATTRIBUTE (UNBUFFERED) then these will automatically take care of resizing/redisplaying within the dialog block when you reload them within the DIALOG block - one of the best things about it.

If I understand your requirements correctly something like this should work:
Code
  1. DIALOG ATTRIBUTE (UNBUFFERED)
  2.    DISPLAY ARRAY p_invoices TO s_invoices.*
  3.    END DISPLAY
  4.    DISPLAY ARRAY p_overterms TO s_overterms.*
  5.    END DISPLAY
  6.    DISPLAY ARRAY p_associated TO s_associated.*
  7.    END DISPLAY
  8.    DISPLAY ARRAY p_openorders TO s_openorders.*
  9.    END DISPLAY
  10.    DISPLAY ARRAY p_history TO s_history.*
  11.    END DISPLAY
  12.  
  13.    -- Or on 2.50 use SUBDIALOG for each display array
  14.   -- SUBDIALOG invoices
  15.  
  16.  BEFORE DIALOG
  17.      -- Assuming you have loaded a first customer
  18.      -- call a function to display the header details
  19.      CALL display_customer_header(p_customer.*)
  20.  
  21.  ON ACTION next_customer
  22.       -- Call whatever you use to fetch your customer
  23.       -- You won't need to pass the arrays unless their scope if local to the function
  24.       -- Dynamic arrays will automatically be refreshed
  25.       CALL fetch_next_customer(p_invoices, p_overterms, p_associated, p_openorders, p_history)
  26.           RETURNING p_customer.*    -- Dynamic arrays are passed by reference so do not need returning
  27.      CALL display_customer_header(p_customer.*)
  28.  
  29.   ON ACTION previous_customer
  30.       -- Same principal as above
  31.  
  32.  ON ACTION close
  33.     EXIT DIALOG
  34.  
  35.   ON ACTION yourotheractions
  36.  
  37. END DIALOG
  38.  
  39.  

This allows the DIALOG block to do most of the work for you and perfectly replaces a menu block. The user won't be trapped inside of a table display as they are free to move between customers, or swap screens. The advantages are that the tables are active and can be scrolled, resorted etc as well as dynamically reloaded as you navigate between customers.

If I have misunderstood why you couldn't remain in the dialog block then my apologies.
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines