TIP: How to create and use Stateless form to edit an existing record

TIP: How to create and use Stateless form to edit an existing record

In case helpful, since it took me awhile :-)

The use case is to have an alternate form, open it from a report's Edit menu for a record, pre-populated with that record's values, and edit/submit the Update. Below shows the bigger picture and assumes some experience.

Summary:
* Create stateless form from existing form, choosing the desired fields.
* Create a custom function that opens the form and passes the record ID, and on the report, add a Custom Action that creates the link that triggers the form to open for that record.
* Adjust the stateless form to learn, pre-populate, and Update your existing record.

Create stateless form from template, following the dox
* (a big time-saver, since has the field names and form attributes)
* New / Form
* From template. Give desired Name. Select the form you are duplicating. DE-select "stored in Creator" (makes it Stateless).
* On resulting dialog, select the fields to include (to copy to the new form).
* I think the other settings (Validate, Mail Notify, Next URL) can all be set later via the form's Workflow scripts.
* Don't use the form yet!

Create a custom function that opens the form and passes the record ID:
* Workflow / Functions / New.
* Choose your namespace, functionname, what form/table you are using, and invent a name to use within the function that is the collection var holding that record's info.
* Add the OpenURL statement, supplying the name of the form you created, and invent a fieldname to use to pass the record ID - a fieldname you will soon create in your stateless form.
* the entire custom function is below:  in this example namespace is "TSCG", function name being defined is "update_lead_clientreport_only", the DB form/table is "Lead", and the collection variable being defined is "this_lead".
* The openURL will open the stateless form we'd named "Lead_CSR_fields", and send it via parameter named "ParamID", this leads ID.  You could send other vars from this record but no need, the form can grab them later.
  1. void TSCG.update_lead_clientreport_only(Lead this_lead)
  2. {
  3.     openUrl("#Form:Lead_CSR_fields" + "?ParamID=" + this_lead.ID, "Popup window", "height=550,width=900");
  4. }

On the report, add a Custom Action that creates the link that triggers the form to open for that record.
* From the desired report:  Custom Action / New. 
* Give it a name, a short name to use on the left Edit menu, and choose "Display in edit record menu" so that it is available for each record under Edit.
* Select the app, namespace, function name (that you defined above), which form object.

ADJUST THE FORM
* Add a numeric field to the stateless form to "store" the record ID passed by the URL.  (We won't be attempting to update it in the database.)  This is key to the form being able to learn your record's ID:  a field must *exist* on the form in order to grab it from the URL parameter, and then use it.  I doubt you can use the existing system "ID" so just create another.
* (Make sure that this fieldname is the same here and on your custom function's OpenURL parameter that passes the record's ID.  In my example, both are "ParamID".)

NOTE: In the form's Submit / "On Click" section will be a list of the fields it copied to the form. We mustn't use as-is (because the create-from-template routine assumes you want a form to INSERT NEW records), but you will want to copy the fieldnames on this list for when you adjust "OnLoad" and "Submit" below.

In the form's OnLoad:
* Use the ID that was passed in the URL (and "stored" in your special field) to query the DB and get that record's values, storing in a collection variable (commonly named "r" but you can name it what you want).  In the below our form/table is named "Lead".  So we're fetching, from table "Lead", the record who's ID is same as in our form's field "ParamID".
  1. r  =  Lead  [ID == input.ParamID];
* Now, populate your form's fields with the record's values known by "r":
  1. input.Lead_Name = r.Lead_Name;
  2. input.Contact = r.Contact;
  3. //... etc.
* Do any other onLoad actions (hide/show, diaable, etc.), and any neeed field-level OnUser Input actions. (they are not copied over from the original form).
* NOTE that this is reason to be careful that you snyc any script changes in the main form with the stateless form.
* You'll probably want to hide the special ID field, in this case "ParamID".

CHANGE THE ACTION under the "submit" button.
(You'll see that the initial stateless form was designed for *adding* a record.  Get rid of the INSERT wrapper, but hang on to the field names.)  

Fetch the record again (is not remembered from OnLoad), placing values into a collection var.
  1.     r2  =  Lead  [ID == input.ParamID];

* Re-use the existing list of fieldnames, but change the syntax for each to the below, so to update field values.
* (and Adjust the set of fields to match the set on the form, in case you changed any.)
  1. r2.Lead_Name = input.Lead_Name;
  2. r2.Contact = input.Contact;
  3. //others...
* Optionally, make the form go away after submit.
(Since the behavior for a stateless form seems to be to stay on-screen after a submit, and since various "window.close" techniques seem to have issues, I found that ending with OpenUrl --to the same report the user came from, works well in this case since we're only opening this form from 1 report.)
As last line:
  1. openUrl("#View:Client_Status_Report", "same window");

As always, backup your app or form and test carefully on test records.

Hope this helps...