Monday, 14 April 2008

Field Captions and the CaptionClass Property

I recently needed to have a field that had a changing field caption based upon some conditions. I knew I had seen this in the standard system for sales orders where the Unit Price field changes between “Unit Price Incl. VAT” and “Unit Price Excl. VAT” depending on how you tick the “Prices Including VAT” field so that is where I started.

If you look on the Unit Price field properties on the Sales Line table you will see that the CaptionClass property is set to GetCaptionClass(FIELDNO("Unit Price")).

That looks like a function call so I take a look in the functions on the table.

GetCaptionClass(FieldNumber : Integer) : Text[80]
IF NOT SalesHeader.GET("Document Type","Document No.") THEN BEGIN
SalesHeader."No." := '';
SalesHeader.INIT;
END;
IF SalesHeader."Prices Including VAT" THEN
SalesPricesIncVar := 1
ELSE
SalesPricesIncVar := 0;
CLEAR(SalesHeader);
EXIT('2,' + FORMAT(SalesPricesIncVar) + ',' + GetFieldCaption(FieldNumber));


Well this seems to be returning either ‘2,1,Unit Price’ or ‘2,0,Unit Price’ depending on whether the Sales Header has the “Prices Including VAT” field set to TRUE or FALSE. How weird is that? Clearly that is not what is displaying on the form.

If you take a look in the C/SIDE Reference Guide (select the option from the Help menu of the application,) there is an interesting line that says “The expression is then interpreted by Trigger 15 in CodeUnit 1.”

Let’s take a look at that codeunit trigger.

CaptionClassTranslate(Language : Integer;CaptionExpr : Text[80]) : Text[80]
CommaPosition := STRPOS(CaptionExpr,',');
IF (CommaPosition > 0) THEN BEGIN
CaptionArea := COPYSTR(CaptionExpr,1,CommaPosition - 1);
CaptionRef := COPYSTR(CaptionExpr,CommaPosition + 1);
CASE CaptionArea OF
'1' : EXIT(DimCaptionClassTranslate(Language,CaptionRef));
'2' : EXIT(VATCaptionClassTranslate(Language,CaptionRef));
'3' : EXIT(CaptionRef);
END;
END;
EXIT('');


This is one of those funny functions that gets called by the system whether you like it or not – you don’t pass the parameters to it but you can guess that what the values contain. I am guessing that in my example the CaptionExpr will contain either ‘2,1,Unit Price’ or ‘2,0,Unit Price’.

On examining the code, I can see that we are pulling out a number from the start of the string into a variable called CaptionArea (which in our case is 2) and using that to either run a new function or return the part of the string that appeared after the number. In our example we are calling VATCaptionClassTranslate(Language,CaptionRef).

So, let’s take a look at what this function does:

VATCaptionClassTranslate(Language : Integer;CaptionExpr : Text[80]) : Text[30]
CommaPosition := STRPOS(CaptionExpr,',');
IF (CommaPosition > 0) THEN BEGIN
VATCaptionType := COPYSTR(CaptionExpr,1,CommaPosition - 1);
VATCaptionRef := COPYSTR(CaptionExpr,CommaPosition + 1);
CASE VATCaptionType OF
'0' : EXIT(COPYSTR(STRSUBSTNO('%1 %2',VATCaptionRef,Text016),1,30));
'1' : EXIT(COPYSTR(STRSUBSTNO('%1 %2',VATCaptionRef,Text017),1,30));
END;
END;
EXIT('');


This function starts by stripping out another parameter into a variable called VATCaptionType and the remainder of the string goes into CaptionRef. Then as you can see the VATCaptionType is evaluated and it returns either ‘Unit Price Excl. VAT’ or ‘Unit Price Incl. VAT’. To know this you have to know that Text016 and Text017 contain ‘Excl VAT’ and ‘Incl. VAT’ respectively.

So that’s it. A good example of how to achieve dynamic field captions using the standard application.

But just to round off, what if I wanted to have my own field with a dynamics caption? Well if you go back to the CaptionClassTranslate function in codeunit 1, you’ll see that option 3 will simply return the value that you passed it back to the caption for the field. This is how you would do it.

Let’s say that we are implementing NAV for a client that wants three addition fields on the Customer Card, the currently have them in their old system called “User Field 1”, “User Field 2” and “User Field 3”. Don’t you just hate that sort of thing? Anyway they say that they want to change the caption to something more meaningful but they can’t decide on what to call them (it’s a lame example I know but it’s late so stick with me.) Being a cunning NAV developer you decide to create three setup fields on the Sales & Receivables Setup table called “Field Caption 1”, “Field Caption 2” and “Field Caption 3”. You can then let the users type the caption they want in these fields and use them for the field captions for the new fields you will add on the customer card.

First of all, you create the fields on the Customer table as “User Field 1”, “User Field 2” and “User Field 3”. Then you create a little function on the Customer table that will take an integer parameter (valued as 1, 2 or 3) and will return a Text value that is the right caption. Let’s call our function “UserFieldCaption”. It might look something like this:

UserFieldCaption(p_FieldNo : Integer) : Text[80]
l_SalesReceivSetup.GET('');
CASE p_FieldNo OF
1: EXIT(l_SalesReceivSetup."Field Caption 1");
2: EXIT(l_SalesReceivSetup."Field Caption 2");
3: EXIT(l_SalesReceivSetup."Field Caption 3");
ELSE
ERROR('UserFieldCaption function on Customer table called with invalid field number of %1',p_FieldNo);
END;


Now on our User Field 1 on the Customer table we would set the CaptionClass property to

'3,'+UserFieldCaption(1)


The other two User Field CaptionClass values will be similar – hopefully you can figure this out yourself.

Once you have compiled everything, set the values of the captions on the Sales & Receivables Setup and Open the Customer table from the object designer. There you should see the caption for your new fields using the value you entered on the setup table.

1 comment:

Anonymous said...

If you have a subform and want to base the captions on fields from the master form, is there a way to do it?