Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically changing PXSelector in Acumatica

Tags:

c#

acumatica

I have the following use case:

Acumatica combo box / dropdown, which can have 8 or so values, the selection of which determines the table / DAC used to present in a PXSelector.

e.g.:

-If user select option a, I need to show in PXSelector values from Table A

-If user select option b, I need to show in PXSelector values from Table B

-If user select option c, I need to show in PXSelector value from Table C

I understand that I'd have to use a Custom Selector Attribute, but the details of how to do this are not clear.

like image 226
pmfith Avatar asked May 05 '16 15:05

pmfith


1 Answers

As you said, you need to implement an attribute that inherits from the PXCustomSelectorAttribute class.

1- Create a class PromptType that will have an ID and Description that will hold the types of each table.

public class PromptType
{
    public Type Id { get; set;}
    public Type Description { get; set; }
}

2- Implement the customSelectorAttribute, like this:

public class MyCustomSelector : PXCustomSelectorAttribute
{
    //Class used to display the data into the selector
    [Serializable]
    public class TableDummy : IBqlTable
    {
        #region Id

        [PXInt(IsKey = true)]
        [PXUIField(DisplayName = "Id")]
        public int? Id { get; set; }

        public class id : IBqlField { }

        #endregion


        #region Description

        [PXString(60, IsUnicode = true, InputMask = "")]
        [PXUIField(DisplayName = "Description", Visibility = PXUIVisibility.SelectorVisible)]
        public string Description { get; set; }

        public class description : IBqlField { }

        #endregion
    }

    //Selected table
    private Type _TableSelection;

    //Tables Ids. You can add as much field ID as you want
    private Type _TableFieldA;
    private Type _TableFieldB;
    private Type _TableFieldC;

    //Tables description fields
    private Type _TableAFieldDesc;
    private Type _TableBFieldDesc;
    private Type _TableCFieldDesc;


    public MyCustomSelector(Type tableSelection, Type tableFieldA, Type tableAFieldDesc, Type tableFieldB, Type tableBFieldDesc, Type tableFieldC, Type tableCFieldDesc) : base(typeof(TableDummy.id))
    {
        _TableSelection = tableSelection;
        _TableFieldA = tableFieldA;
        _TableFieldB = tableFieldB;
        _TableFieldC = tableFieldC;
        _TableAFieldDesc = tableAFieldDesc;
        _TableBFieldDesc = tableBFieldDesc;
        _TableCFieldDesc = tableCFieldDesc;
    }

    //Get the name of the selected table by using the private field _TableSelection.
    private string GetSelection()
    {
        var cache = _Graph.Caches[_BqlTable];
        return cache.GetValue(cache.Current, _TableSelection.Name)?.ToString();
    }

    //Return a pompt instance based on the selected table in the dropdown.
    private PromptType GetSelectedTableField(string selectedTable)
    {
        switch (selectedTable)
        {
            case "A":
                return new PromptType() { Id = _TableFieldA, Description = _TableAFieldDesc };
            case "B":
                return new PromptType() { Id = _TableFieldB, Description = _TableBFieldDesc };
            case "C":
                return new PromptType() { Id = _TableFieldC, Description = _TableCFieldDesc };
            default:
                return new PromptType() { Id = _TableFieldA, Description = _TableAFieldDesc };
        }
    }

    //Return the records
    public IEnumerable GetRecords()
    {
        var selectedField = GetSelectedTableField(GetSelection());
        var selectedTable = BqlCommand.GetItemType(selectedField.Id);

        var select = BqlCommand.Compose(
                        typeof(Select<>),
                            selectedTable
                        );

        var cmd = BqlCommand.CreateInstance(select);
        PXView view = new PXView(_Graph, true, cmd);

        foreach (var row in view.SelectMulti())
        {
            var id = (int?)view.Cache.GetValue(row, selectedField.Id.Name);
            var description = view.Cache.GetValue(row, selectedField.Description.Name)?.ToString();
            yield return new TableDummy { Id = id, Description = description };
        }
    }
}

You can change the constructor of the custom attribute, by passing the desired number of tables.


3- Once you have implemented your custom attribute, you can use it in your field like this:

#region DropDown to select a table
[PXDBString(1)]
[PXUIField(DisplayName = "Table Selection")]
[PXStringList(
    new string[]
    {
        "A",
        "B",
        "C"
    },
    new string[]
    {
            "Table A",
            "Table B",
            "Table C"
    })]
public virtual string UsrTableSelection { get; set; }
public abstract class usrTableSelection : IBqlField
{
}
#endregion

#region Selector
[PXDBInt]
[PXUIField(DisplayName = "Table Selector")]
[MyCustomSelector(
    typeof(APRegisterExt.usrTableSelection), 
    typeof(TableA.id),typeof(TableA.description),
    typeof(TableB.id), typeof(TableB.description),
    typeof(PX.Objects.AR.Customer.bAccountID), 
    typeof(PX.Objects.AR.Customer.acctName))]
public virtual int? UsrTableSelector { get; set; }

public abstract class usrTableSelector : IBqlField
{
}
#endregion

4- Also, you should not forget to set the visibility on your tables fields. I'm referring to the tables (DACs) that you want to display in the selector. Let say that you want to display TableA, TableB or TableC depending on your drop down, you need to set the visibility on the fields that you are going to use in the selector.

Here's the implementation of one of the tables that I used during my tests:

[Serializable]
public class TableA : IBqlTable
{
    #region Id

    [PXDBInt(IsKey = true)]
    [PXUIField(DisplayName = "Id")]
    public int? Id { get; set; }

    public class id : IBqlField { }

    #endregion


    #region Description

    [PXDBString(60, IsUnicode = true, InputMask = "")]
    [PXUIField(DisplayName = "Description", Visibility = PXUIVisibility.SelectorVisible)]
    public string Description { get; set; }

    public class description : IBqlField { }

    #endregion


    #region InfoA

    [PXDBString(60, IsUnicode = true, InputMask = "")]
    [PXUIField(DisplayName = "Info A", Visibility = PXUIVisibility.SelectorVisible)]
    public string InfoA { get; set; }

    public class infoA : IBqlField { }

    #endregion
}

By setting the visibility to SelectorVisible, the field will be displayed automatically in the PXSelector.


5- Finally, you need to set CommitChanges to True on your dropdown and set AutoRefresh to True on your form field. Here's an example:

<px:PXDropDown runat="server" ID="CstPXDropDown1" DataField="UsrTableSelection" CommitChanges="True" />
<px:PXSelector runat="server" ID="CstPXSelector2" DataField="UsrTableSelector" AutoRefresh="True" />
like image 91
billybob Avatar answered Oct 05 '22 22:10

billybob