Here's a quick and (hopefully) easy question.
In various forms, when I need the user to select a record from another table through a lookup, I do the following if there is no particular processing (no need to call a function on the LookUp form, the LookUp form is a regular tabular form with the usual OK/Cancel buttons, etc.)
// Assuming we have a MyRecord : Record ("My Record") variable
IF FORM.RUNMODAL(FORM::"My Lookup Form", MyRecord) = ACTION::LookupOK THEN BEGIN
// Do stuff with the selected record
END;
I found our partner usually did the same thing in another way, for the same case (no particular processing).
// Assuming we have a MyRecord : Record ("My Record") variable and a MyLookupForm : Form ("My Lookup Form") variable.
MyLookupForm.SETTABLEVIEW(MyRecord);
MyLookupForm.EDITABLE(FALSE); // Optional - only needed if the LookupForm is also used in another context to modify data
MyLookupForm.LOOKUPMODE := TRUE;
IF MyLookupForm.RUNMODAL = ACTION::LookupOK THEN BEGIN
MyLookupForm.GETRECORD(MyRecord);
// Do stuff with the selected record
END;
If all I need a lookup button to do is getting a record without any unusual processing, it seems to me that declaring a Form variable, initializing it, etc. is overkill. Under this hypothesis (i.e. I do not otherwise need the Form variable), are the two above code snippets equivalent?
I looked on mibuso and elsewhere on the web, but couldn't find a definitive answer to my question. In fact, everybody seems to be recommending the second method as the general solution to "lookup a record in another table", but I find it unnecessarily "complex" for the simple case, so I'm wondering if there might be a subtle difference I couldn't find about.
Thanks!
Answers
The code is not exact equivalent. The difference is here: If you do not have to make sure that your lookup form is aways in lookup mode and readonly then it doesn't matter in fact. (MyLookupForm.LOOKUPMODE := TRUE; is enough BTW);
My personal preference is to use relation (no code at all, only default lookup form provided by NAV), then, if I need to code something extra, use FORM.RUNNODAL(0,rec), then use FORM.RUNNODAL(form::"somespecificformhere",rec), and at last define variable and run MyFormVariable.RUNMODAL construction.
The main reason for using FORM.RUNNODAL(0,rec) construction is that it works with temporary records passed as rec variable, and uses default lookup form as defined for a table. And it is shorter to write.
I use MyFormVariable.RUNMODAL constrution only if I need to pass some extra parameters/settings which cannot be passed as a filters, or call form function to prepare lookup, or when it doesn't make sense to create extra fields just to pass some variables.
Hope this helps.
Regards,
Slawek
Dynamics NAV, MS SQL Server, Wherescape RED;
PRINCE2 Practitioner - License GR657010572SG
GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03
1) FORM.RUNMODAL
and
2) MyFormVar.RUNMODAL
In 1) the form is initialized ON EACH RUN (this means that the OnInit-trigger of the form will be run each time).
In 2) the form is initialized ONLY the first time it is run in a certain object. The second time you run it, the OnInit-trigger of the form will NOT run. Of course you can put a CLEAR(MyFormVar) before or after the run. In this case the OnInit-trigger of the form will be run each time. In reality, I consider doing a CLEAR(MyFormVar) after the RUN a good practice.
No PM,please use the forum. || May the <SOLVED>-attribute be in your title!
As far as I know MyFormVar.RUNMODAL will NOT run second time, if you don't clear it after first run.
Slawek
Dynamics NAV, MS SQL Server, Wherescape RED;
PRINCE2 Practitioner - License GR657010572SG
GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03
No PM,please use the forum. || May the <SOLVED>-attribute be in your title!
I didn't know about the FORM.RUNMODAL(0, MyRecVar) construction. \:D/ So, if I understood Slawek, I could (or is that should?):
1) use FORM.RUNMODAL(0, MyRecVar) for a simple LookUp.
2) use FORM.RUNMODAL(FormNo, MyRecVar) for a LookUp using another form than the default form defined for that table.
3) use MyFormVar.RUNMODAL(MyRecVar) for more elaborate processing, for instance using a non-default LookUp form, call a function of that form, etc.
I'm pretty certain that is right. If I remember correctly, using MyFormVar.RUNMODAL twice without using CLEAR(MyFormVar) in between causes NAV to throw a run-time error. (So whatever method is used, the OnInit-trigger of the form should always be executed.) However, you can use RUN twice in a row because the variable is automatically cleared when RUN is used (source: C/SIDE Reference Guide).
For the last little bit I've been grappling with the issue of getting my temporary table to display properly in LOOKUP, and after reading this post, I think I have an understanding of the difference in behavior between FORM.RUNMODAL and MyForm.RUNMODAL:
For showing temporary records, my observation is that:
- FORM.RUNMODAL will allow a temporary record to show up correctly, but
- MyForm.RUNMODAL will only show the main table even if SETTABLEVIEW is issued with the temporary rec as the variable.
Example:
TERMINOLOGY USED BELOW:
{
RECORDS
MyTable - not temporary
MyTEMPTable - temporary version of MyTable
FORM
MyForm - default form for MyTable in Object Designer
MyFormVar - local/global variable for MyForm
}
CASE I. When I issue: FORM.RUNMODAL(FORM::MyForm, MyTEMPTable), it works well... it shows me the temporary table, but,
CASE II. When I issue the following commands:
CLEAR(MyFormVar);
MyFormVar.SETTABLEVIEW(MyTEMPTable);
MyFormVar.RUNMODAL;
what I see is MyTable, not MyTEMPTable! This had me completely confused for the longest time... I kept thinking that my TRANSFERFIELDS function that I was using to move some lines from MyTable to MyTEMPTable was messed up, but, it was actually a RUNMODAL issue.
So... fellow developers, BEWARE!
So in order to use a Lookup Form with a temporary table, FORM.RUN(FormID, MyRec) or FORM.RUNMODAL(FormID, MyRec) must be used, but this raises another issue to watch for: if the form identified by FormID is a tabular form with the LOOKUPMODE property set to FALSE and EDITABLE to Yes (look at F100 Accounting Periods, for instance, compare with F89 Job List), then you would need to either change the Form properties LOOKUPMODE to Yes and EDITABLE to No (bad idea! this is an invitation to problems due to unforeseen side-effects), or better yet, create a copy of the form in which the properties are set as appropriate for a Lookup Form and use that form instead.
Given the Accounting Periods example, one would create an Accounting Period List form as a copy of Accounting Periods, set its LOOKUPMODE property to Yes and EDITABLE property to No, then use FORM.RUNMODAL(FORM::"Accounting Period List", MyTEMPTable) to successfully use a Lookup on the temporary table to choose an Accounting Period.