Tuesday, 3 May 2016

Hiding the tab from the user interface

Hi Everyone

Today I want to discuss with you ways how you can control visibility of tab items in Acumatica User interfaces.
You can do it in one of the following two ways:
  • By setting a VisibleExp property on PXTabItem in ASPX page
  • By enabling/disabling AllowSelect property of the view that serves as a DataMember of the grid that is displayed on that tab
Welcome in this article if you want to see details.

Method 1 – VisibleExp
In this method, you directly write the conditions under which the tab should be visible in the screen's ASPX code.
<px:PXTabItem Text="Tax Agency Settings" BindingContext="tab" 
    VisibleExp="DataControls[&quot;chkTaxAgency&quot;].Value = 1">

Note that the binding context is important as it specifies which element's DataControls you want to access in the VisibleExp.
Also DataControls is collection of values for user interface fields, so you need to specify there IDs of controls (not data access class fields).

However, this method is extremely limited in many ways:

  • The condition checking is restricted to controls available in the UI, so it is not possible to condition visibility upon the internal state of the system.
  • Sometimes this method will require you to include "fake" data controls into ASPX that will only be checked in VisibleExp, but won't actually be ever seen by the user.
  • There seems to be no support for complex conditions including AND/OR.
  • Ugly &quot; entities instead of normal quotes in the expression – not particularly readable.

Most importantly, if you need to disable the tab for a particular document type, there is no way around hard - coding a constant into a VisibleExp. You would be explicitly writing something like: VisibleExp="DataControls[&quot;edDocumentType&quot;].Value != CHK"

Hard-coding is generally considered a very poor development practice. It poses a significant threat to code maintainability: probably the above code is going to break something in the future. For example if you decide to rename the document codes form CHK to CHQ.

In addition to that, this solution is not easily generalized to situations when you suddenly discover the need to hide the tab not only for checks, but also for other document types. This is due to lack of complex conditional expressions mentioned above.

Method 2 – AllowSelect
Idea of this method is - if you hide all controls from the tab item, than Acumatica will automatically hide tab with no visible controls.

Lets do an example: assume that you need to hide a tab named Applications depending on the document type selected in SO303000 (Invoices):

The tab that we're interested in has a grid control with a data member set to Adjustments:
<px:PXTabItem Text="Applications" RepaintOnDemand="false">
        <px:PXGrid ID="detgrid" DataSourceID="ds" SkinID="Details"> 
                <px:PXGridLevel DataMember="Adjustments">

And not that this tab item has only one control - PXGrid.
Also note required property here - RepaintOnDemand="false". This property indicates whether the control refresh tab items content (and select data) after the item becomes visible. Unfortunately, setting it to false incurs certain performance losses. In particular, the Adjustments view' Select will be called much more frequently.

Currently, the Tab is "smart" in the way that it understands that when its child control (PXGridLevel) cannot perform a select on its data member; in this case, the tab hides itself from the UI. This is why you can control the visibility of the tab by setting the AllowSelect property of the cache that corresponds to the Adjustments:
Adjustments.Cache.AllowSelect = 
    doc.DocType != ARDocType.CashSale 
    && doc.DocType != ARDocType.CashReturn;

The above code is written in the ARInvoice_RowSelected handler of the graph, where ARInvoice is the primary DAC and the type of the master records of the page. So, every time ARInvoice is selected, the tab item will become visible or invisible depending on the document type.

This method has its own limitations too:
  • You should always remember that it is not enough to disable AllowSelect, you should also enable it when needed. So you need to evaluate this property every time when event is called. 
  • This method doesn't seem to work without setting the PXTabItem's RepaintOnDemand property to false (see above).
Big thanks to Acumatica development team for this example.
Have a nice development!

No comments: