Change field state dynamically in Acumatica. Or changing field type in Acumatica

Hello friends.

Today I will tell you how we can dynamically change the state of the field in a grid. I want to notice that this way works only for grid and will not work with Form.

In our case we will create DAC Extension for SOLine with 2 fields.

First field will choose the type we want to convert the field into and in the second field will interact with it.

In this example I made fields PXDBString on purpose to show how they are saved to the database.

[PXCacheName(SoLineExtCacheName)]
public class SoLineExt : PXCacheExtension<SOLine>
{
    private const string SoLineExtCacheName = "SoLineExt";
    public static bool IsActive() => true;
 
    #region UsrSlsOrdPrimaryReasonCode
 
    [PXDBString(255)]
    [PXStringList(
        new[] { "1""2""3""4""5" },
        new[] { "DropDown""TextBox""DateTime""CheckBox""Selector" })]
    [PXUIField(DisplayName = "FieldOne")]
    public string UsrFieldOne { getset; }
 
    public abstract class usrFieldOne : BqlString.Field<usrFieldOne>
    {
    }
 
    #endregion
 
    #region UsrSlsOrdSecondaryReasonCode
 
    [PXDBString(255)]
    [PXUIField(DisplayName = "FieldTwo")]
    public string UsrFieldTwo { getset; }
 
    public abstract class usrFieldTwo : BqlString.Field<usrFieldTwo>
    {
    }
 
    #endregion
 
}

 

The next step should be creating the GraphExtension for the graph.

Create a FieldSelecting event for UsrFieldTwo that will dynamically change the state.

We will also check if UsrFieldOne is empty then by default we can create our UsrFieldTwo as a text field.

[PXCacheName(SoOrderEntryExtCacheName)]
public class SOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
    private const string SoOrderEntryExtCacheName = "SoOrderEntryExt";
    public static bool IsActive() => true;
 
    public PXSelect<FixedAsset> FixedAssets; // Here we've a view that we'll show in a selector
 
    protected void _(Events.FieldSelecting<SOLine, SoLineExt.usrFieldTwo> args)
    {
        var fieldOne = args.Row.GetExtension<SoLineExt>()?.UsrFieldOne;
        if (args.Row == null || string.IsNullOrWhiteSpace(fieldOne))
        {
            return;
        }

 

The next step is to define a Switch conditional construct in which we will check the type we should transform UsrFieldTwo into and return to text field.

        switch (fieldOne)
        {
            case "1":
                args.ReturnState = PXStringState.CreateInstance(args.ReturnState, 100, truetypeof(SoLineExt.usrFieldTwo).Name,
                    false, -1, string.Empty, new[] { "val_1""val_2""val_3", }, new[] { "val_1""val_2""val_3", }, falsenull);
                // We can uncomment this line if need to MultiSelect in dropdown.
                //((PXStringState)args.ReturnState).MultiSelect = true;
                break;
            case "2":
                args.ReturnState = PXStringState.CreateInstance(args.ReturnState, 100, null,
                    typeof(SoLineExt.usrFieldTwo).Name, false, -1, nullnullnulltruenull);
                break;
            case "3":
                args.ReturnState = PXDateState.CreateInstance(args.ReturnState, typeof(SoLineExt.usrFieldTwo).Name, false, -1,
                    nullnullnullnull);
                break;
            case "4":
                args.ReturnState = PXFieldState.CreateInstance(args.ReturnState, typeof(bool), falsefalse, -1,
                    nullnullfalsetypeof(SoLineExt.usrFieldTwo).Name, nullnullnull, PXErrorLevel.Undefined, truetrue,
                    null, PXUIVisibility.Visible, nullnullnull); break;
            case "5":
                var state = PXFieldState.CreateInstance(args.ReturnState,
                    typeof(string), falsetrue, 1, nullnullnulltypeof(SoLineExt.usrFieldTwo).Name);
                state.ViewName = nameof(FixedAssets);
                state.DescriptionName = nameof(FixedAsset.description);
                state.FieldList = new[]
                {
                    nameof(FixedAsset.assetID),
                    nameof(FixedAsset.description),
                    nameof(FixedAsset.assetTypeID),
                    nameof(FixedAsset.assetCD)
                };
                var selectorCache = Base.Caches<FixedAsset>();
                state.HeaderList = new[]
                {
                    PXUIFieldAttribute.GetDisplayName<FixedAsset.assetID>(selectorCache),
                    PXUIFieldAttribute.GetDisplayName<FixedAsset.description>(selectorCache),
                    PXUIFieldAttribute.GetDisplayName<FixedAsset.assetTypeID>(selectorCache),
                    PXUIFieldAttribute.GetDisplayName<FixedAsset.assetCD>(selectorCache),
                };
                state.DisplayName = PXUIFieldAttribute.GetDisplayName<SoLineExt.usrFieldTwo>(args.Cache);
                state.Visible = true;
                state.Visibility = PXUIVisibility.Visible;
                state.Enabled = true;
                args.ReturnState = state;
                break;
            default:
                args.ReturnState = PXStringState.CreateInstance(args.ReturnState, 100, null,
                    typeof(SoLineExt.usrFieldTwo).Name, false, -1, nullnullnulltruenull);
                break;
        }
 
    }
}

 After we have prepared our GraphExtension and CacheExtension we need to add our fields to the View, so we can do this through the Customization Editor for clarity.

Very important point! Since we dynamically change the type of our field UsrFieldTwo, you must set MatrixMode="true" for this column:

That's it, now we can make a publish and check it out.

You must remember that all fields that are specified in the list in the database will be stored as a string, so do not forget to convert them to the correct type when you work with them, to avoid problems with the type of ghosting.

If the field is empty then by default it will be a text field.

  • If you select dropdown then we get the value we set in e.ReturnState.

  • The text field is identical to the empty field.

  • If you select CheckBox, our field will have two states True or False.

  • If we select DateTime we can select a date from the DateTimePicker.

 

  • Of course, Selector. This will display the data from our previously defined FixedAsset view.

Let's also see how this data is stored in the database which is demonstrated by sampling.

That's all for now, thank you for your attention, I hope this article will be useful for you

All for successful coding.