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: Creatng a screen on the fly?  (Read 16240 times)
Joel S.
Posts: 3


« on: February 05, 2015, 02:46:32 am »

Maybe I'm wrong about this, but I seem to recall at some point, maybe in an online class or presentation, hearing that the screen could be modified on-the-fly by directly modifying the DOM tree.

Can a custom screen be created without a .42f file behind it?  And all of the things like whether it's a combo box, char, integer, etc. be set up at runtime?

We may have a need for input of a customized questionnaire.  So, depending on a configuration table, we'd specify what type of data for each question.  Maybe it's a fill in the box.  Maybe it's a date and we want to create a dateedit field.  Maybe it's a list of values to choose from and we use a combobox.  Or checkboxes.

So I'd like to create appropriate input form.

If this can be done, I would think I could only input x-number of fields at a time.  Because even if I can create the form on the fly, the INPUT statement would be hard-coded and I can only list a specific number of variables to input.  Or is there a way around this too?

Ren?n Q.
Posts: 1


« Reply #1 on: February 05, 2015, 04:55:19 am »

What I would try is to have a 42f compiled file without any field inside, then when needed create a copy of that file and add on-the-fly all the items needed according with the configuration of the tables.
Sebastien F.
Four Js
Posts: 545


« Reply #2 on: February 05, 2015, 06:31:40 am »

If you are using a recent version that supports PHANTOM fields, you can try following:
(I did not test yet with INPUT, but works with DISPLAY ARRAY to implement dynamic selection forms)

1) DEFINE a RECORD that holds all possible input fields/types of your dynamic form, you may want to double the fields with the same type if you need to input 2 dates for ex:

DEFINE input_record RECORD
         field_int_1 INTEGER,
         field_int_2 INTEGER,
         field_varchar_1 VARCHAR(50),
         field_varchar_2 VARCHAR(50),
         field_date_1 DATE,
         field_date_2 DATE,
         ...
     END RECORD
       
2) Do OPEN WINDOW with ROWS/COLUMNS instead of a form

3) Get the window object (ui.Window) with:
     LET winobj = ui.Window.getCurrent()

4) Create the form object (ui.Form) with:
     LET frmobj = winobj.getForm()
get the window root om.DomNode with:
     LET wn = winobj.getNode()
get the form om.DomNode with:
     LET fn = frmobj.getNode()
These will be used to set attributes and create subnodes of the form definition.

5) Implement functions to add field definitions of you form in a structured dynamic array, with info such as field name, label, data type, length...

6) Build you form dynamically, using the array defining fields:
- Define the window node name and dimensions (width / height)
- Define the form node name and dimensions (width / height). Consider using different form names for front-end stored settings (window sizes), and remember forms have a "version" attribute that can be incremented to indicate to the front-end that stored setting must not be applied because it's a new version of the form with potential new layout/fields.
- Add a Grid node, etc
- Create FormFields nodes for input fields and PhantomFormFields for other fields of the RECORD, which are not used for input. Set a fieldId attribut for each of them, create view nodes below (Edit, ComboBox, DateEdit, etc.)
- Create a RecordView node, to map form fields to RECORD members: This is the trick, you must list the elements in the RecordView in the same order as the RECORD elements, with input and phantom fields. The RECORD structure and RecordView must match, but each RecordView child node can bind to an input FormField and PhantomFormField with the fieldIdRef attribute, so in the layout it can be in a different order.
To help on the form creation, write a .per and compile it to see the resulting .42f structure of nodes.

7) In the code, use OPTIONS FIELD ORDER FORM to force the dialogs to use form field tab indexes.

8) Implement an INPUT BY NAME rec.* ... you can use BEFORE FIELD / AFTER FIELD / ON CHANGE ...
To be honnest, here I have a little doubt: For now it's possible to define field triggers for phatom fields, and it's better in our dynamic form case, but I am not 100% sure this is intended, maybe a side effect. We need to clarify this.

Code
  1. layout
  2. grid
  3. {
  4. [f2        ]
  5. [f1        ]
  6. }
  7. end
  8. end
  9. attributes
  10. f1 = formonly.field1;
  11. f2 = formonly.field2;
  12. phantom formonly.field3;
  13. end
  14.  

Code
  1. main
  2.    define rec record
  3.               field1 integer,
  4.               field2 varchar(50),
  5.               field3 varchar(50)
  6.           end record
  7.    open form f1 from "f1"
  8.    display form f1
  9.    options input wrap, field order form
  10.    input by name rec.* without defaults
  11.        before field field1 display "bf field1"
  12.        on change field2 display "oc field2"
  13.        after field field3 display "af field3"
  14.    end input
  15. end main
  16.  

Seb
Joel S.
Posts: 3


« Reply #3 on: February 05, 2015, 04:57:20 pm »

Thank you both.  This info is very helpful.  Unfortunately, I am not ready to code yet.  I'm exploring the feasibility at this point.  And it looks like it's feasible.  Hopefully this will be the approach we will take.

The other thing is, since the data will be of a generic nature, I will probably input into varchars.  Date, integer, or whatever, can be converted and stored as a varchar and converted back when necessary.  Since it's generic, I don't know which fields would be dates, characters, whatever and the input variables can't be dynamic.  And the variable nature of varchar allows me to use less space for shorter fields and more for longer ones.
Sebastien F.
Four Js
Posts: 545


« Reply #4 on: February 06, 2015, 09:39:42 am »

By using VARCHAR for all real data type input you will lose the automatic data checking done by Genero.
You should rather use the appropriate type (use DATE for date input, INTEGER for integer input)
The idea of using PHANTOM fields was to keep using the right type in the BDL variable for the input.
Seb
Joel S.
Posts: 3


« Reply #5 on: February 06, 2015, 11:43:45 pm »

I thought that if I had a field in the form set up as type date, it would do date checking, regardless of the variable type it is returning it to in the input statement.

If I have to code specific input statements for the data types, this kind of blows this whole idea apart.

The intent is to to be able to create "questionnaires" for our clients quickly and easily.  This is for data they want to keep, not necessarily something we want to code screens into our product for.  So I want to create a generic system for the user to give us their list of questions, we populate a configuration table and now they can start inputting their data in a matter of hours.  Much easier than coding screens, Genero code, table changes, etc.

To do this, I wanted to create a dynamic form.  From question to question, we don't know what data type it will be.  Might be date, might be integer, whatever it is configured to be.  So that's why I need to set up the form on-the-fly.  And I would like the advantages of the data checking.

But if I can only do this by matching the input variables to the same type a the form, then it's a major problem.

Imagine I have 5 questions on the screen.  And let's say we code for 4 different types: integer, date, char, and decimal.  Just with those 4 types, I'd have to code 1024 different input statements.  One for int, int, int, int, int - One for int, int, int, int, date - One for int, int, int, date, int - One for ..., and so on.

And if I'm doing all of that work, I might as well have custom forms for each permutation as well.  But that's unfeasible.

I thought the type of field on the form controlled all the checking, not what variable type I'm using in the INPUT.  And a varchar should be able to hold and receive a date, integer, decimal, etc.  And the table to hold the answers would be varchar as well.

But if that's not doable, then this whole idea isn't.
Sebastien F.
Four Js
Posts: 545


« Reply #6 on: February 07, 2015, 12:23:53 pm »

Ok I see what you want to achieve.
In fact types in form fields (per/42f) are only used by CONSTRUCT dialogs. With INPUT / INPUT ARRAY it's the type of the program variables that is used.
Again, I believe that mixing regular fields and PHANTOM fields in a form generated dynamically, with static RECORD / INPUT should do the job.
I will work on a sample and post it here if it works.
Reuben B.
Four Js
Posts: 1119


« Reply #7 on: February 09, 2015, 03:42:48 am »

Typical, interesting topic appears when I've got a long weekend at the beach.

Quote
Maybe I'm wrong about this, but I seem to recall at some point, maybe in an online class or presentation, hearing that the screen could be modified on-the-fly by directly modifying the DOM tree.

Can a custom screen be created without a .42f file behind it?  And all of the things like whether it's a combo box, char, integer, etc. be set up at runtime?

We may have a need for input of a customized questionnaire.  So, depending on a configuration table, we'd specify what type of data for each question.  Maybe it's a fill in the box.  Maybe it's a date and we want to create a dateedit field.  Maybe it's a list of values to choose from and we use a combobox.  Or checkboxes.

So I'd like to create appropriate input form.

If this can be done, I would think I could only input x-number of fields at a time.  Because even if I can create the form on the fly, the INPUT statement would be hard-coded and I can only list a specific number of variables to input.  Or is there a way around this too?


As you've discovered, yes you can create the form, but you can't create the INPUT/DISPLAY ARRAY statement to match.  The INPUT/DISPLAY ARRAY statement has to cater for the maximum case and then you can either hide unused fields/columns, or use phantom columns to narrow the visible form to what you want.

This whole concept of "manipulating the DOM tree" will be more familiar to Genero developers who were around 2003,2004,2005.  Early versions of Genero did not have methods such as ui.Dialog.setFieldActive(), ui.Form.setFieldHidden() and so those developers (I was one at the time) created their own library functions doing DOM tree manipulation to show/hide fields, enable/disable fields.   These techniques could also be used to add fields to a form. Those same techniques still work today and can be used to do things for which there is no Genero method available. 

You can see these techniques in two programs I put up on sourcefourjs, there is AUITree https://code.google.com/p/sourcefourjs/wiki/auitree and a Generic Zoom Window https://code.google.com/p/sourcefourjs/wiki/fgl_zoom although beware they are getting a little dated and there are somethings in there I'd do differently today.

It was also the subject of a presentation I did at IIUG in 2013 which would also explain the useful things you'd need to know like what happens if you start GDC with -D command line option and then Control-Right Click inside your form.

What I would point out also is that you don't need to use these techniques of manipulating the DOM.  I would also consider the fact that
1) a 42f is a readable XML document and/or 2) fglform does not need a compile time license to run.

So your 4gl program could create the .42f it required, either by generating a .42f file using the XML classes, or by generating a .per and using fglform to create the .42f.  If you didn't need to make any changes whilst form is running, that technique may work better for you, particularly if you haven't been exposed to any DOM Tree manipulation previously.



Quote
Imagine I have 5 questions on the screen.  And let's say we code for 4 different types: integer, date, char, and decimal.  Just with those 4 types, I'd have to code 1024 different input statements.  One for int, int, int, int, int - One for int, int, int, int, date - One for int, int, int, date, int - One for ..., and so on.

No you wouldn't.  Using OPTIONS FIELD ORDER FORM https://4js.com/online_documentation/fjs-fgl-manual-html/index.html#c_fgl_programs_012.html you would just have to code one INPUT statement that catered for the maximum number of each datatype.  So you'd likely have ...

Code
  1.  
  2. OPTIONS FIELD ORDER FORM
  3.  
  4. # code to create form
  5. # or code to hide unused fields
  6.  
  7. INPUT BY NAME int1, int2, int3, ...,intn,
  8.    date1, date2, date3, ..., daten,
  9.    char1, char2, char3, ..., charn,
  10.    dec1, dec2, dec3,...,decn

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
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines