Skip to main content
Solved

How to refresh the UI when field is updated.

  • 6 August 2024
  • 7 replies
  • 116 views

I have customized purchase orders screen, add an extension to POLine DAC and add two fields.

  public class POLineExt : PXCacheExtension<PX.Objects.PO.POLine>
{
#region UsrInventoryItemClassID

[PXInt]
[PXUIField(DisplayName="ItemClass")]
[PXDBScalar(typeof(
Search<InventoryItem.itemClassID,
Where<InventoryItem.inventoryID, Equal<POLine.inventoryID>>>))]
public virtual int? UsrInventoryItemClassID { get; set; }
public abstract class usrInventoryItemClassID : PX.Data.BQL.BqlInt.Field<usrInventoryItemClassID> { }
#endregion

#region UsrInventoryItemClassCD

[PXString(32)]
[PXUIField(DisplayName="Item Class Description")]
[PXDBScalar(typeof(
Search2<INItemClass.itemClassCD,
InnerJoin<InventoryItem, On<InventoryItem.itemClassID, Equal<INItemClass.itemClassID>>>,
Where<InventoryItem.inventoryID, Equal<POLine.inventoryID>>>))]
public virtual string UsrInventoryItemClassCD { get; set; }
public abstract class usrInventoryItemClassCD : PX.Data.BQL.BqlString.Field<usrInventoryItemClassCD> { }
#endregion
}

 

Dispaly these two in the grid,

When I select the Inventory ID, I need to load the item class and item class description according to  PXDBScalar] query. So, I wrote an event as below. but it is not work properly. to update the UI I has to reload the whole website. How to fix that issue?

        protected void POLine_InventoryID_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{

//Base.Transactions.Cache.Clear();
//Base.Transactions.Cache.ClearQueryCache();
//Base.Transactions.View.RequestRefresh();


//cache.SetValueExt<POLineExt.usrInventoryItemClassID>(e.Row, 4);
//cache.SetValueExt<POLineExt.usrInventoryItemClassCD>(e.Row, "JAM");

if (e.Row == null) return;
var row = (POLine)e.Row;
var tranView = row.GetExtension<POLineExt>();
cache.SetValueExt<POLineExt.usrInventoryItemClassID>(row, tranView.UsrInventoryItemClassID);
cache.Update(row);

}

 

I didn’t test this, but this would (in theory) call the FieldSelecting event for your custom field and force it to calculate again.

protected virtual void _(Events.FieldUpdated<POLine.inventoryID> e)
{
POLine row = e.Row;
if (row is null) return;

string f = null;
e.Cache.RaiseFieldSelecting<POLineExt.usrInventoryItemClassID>(row, ref f, false);
}

If that doesn’t work, I would suggest you pivot to using FieldDefaulting on your custom fields to set the values. Then call e.Cache.SetDefaultExt<>() in the code above instead to force it to recalculate the default value.


Hi, @darylbowman, I tried with following two methods, I made few changes of your code because it gives compiler errors. But still, I unable to achieve the requirement.

        protected virtual void _(Events.FieldUpdated<POLine.inventoryID> e)
{
POLine row = (POLine)e.Row;
if (row is null) return;

object f = null;
e.Cache.RaiseFieldSelecting<POLineExt.usrInventoryItemClassID>(row, ref f, false);
e.Cache.RaiseFieldSelecting<POLineExt.usrInventoryItemClassCD>(row, ref f, false);
//e.Cache.Update(row);
}

protected virtual void _(Events.FieldDefaulting<POLineExt.usrInventoryItemClassID> e)
{
POLine row = (POLine)e.Row;
if (row is null) return;

// Acuminator disable once PX1047 RowChangesInEventHandlersForbiddenForArgs [Justification]
e.Cache.SetDefaultExt<POLineExt.usrInventoryItemClassCD>(row);
// Acuminator disable once PX1047 RowChangesInEventHandlersForbiddenForArgs [Justification]
e.Cache.SetDefaultExt<POLineExt.usrInventoryItemClassID>(row);

}

 


Hi @PDharmasena10 

Defaulting only happens when you insert a new entity record.

In your case, you’re updating an existing one.

PXDBScalar tends to be memory-heavy and in my experience, just sets the values you need using an event (FieldUpdated, RowSelected, depending on your case).

As your fields are unbound, it might be better to do that in RowSelected with an additional check if they are already set up (to avoid redundant calls for that logic), because otherwise when you open your Purchase Order without changing InventoryID those 2 fields will be empty.


@PDharmasena10 - You need to call SetDefaultExt in the same place you're now calling RaiseFieldSelecting. You won't need those anymore.

Add PXUnboundDefault] to both DAC fields and comment out the PXDBScalar.

Then, in the FieldDefaulting handlers, write the logic to set e.ReturnValue to the correct value based upon the current POLine's InventoryID.

When InventoryID is updated, it will re-default your fields.


Hi @darylbowman, @andriitkachenko , I tried to implement according to the above comments but was unable to achieve the desired output. Could you please, provide some code samples related to this solution for me to study?


Hi @PDharmasena10 

Here’s the event:

        protected virtual void _(Events.RowSelected<POLine> e)
{
if (!(e.Row is POLine row) || row.InventoryID == null) return;
var ext = row.GetExtension<POLineExt>();
if (ext == null || (ext.UsrInventoryItemClassID != null && ext.UsrInventoryItemClassCD != null)) return;

var inventoryClass = PXSelectJoin<INItemClass,
InnerJoin<InventoryItem,
On<InventoryItem.itemClassID, Equal<INItemClass.itemClassID>>>,
Where<InventoryItem.inventoryID, Equal<Current<POLine.inventoryID>>>>
.Select(Base)
.FirstTableItems
.FirstOrDefault();

if(inventoryClass == null) return;

ext.UsrInventoryItemClassID = inventoryClass.ItemClassID;
ext.UsrInventoryItemClassCD = inventoryClass.ItemClassCD;
}

And that’s the result:

If you want it to be propagated only when new InventoryID is set - you can change that example into FieldUpdated. But note that in that case your 2 new fields will be empty when you open new record or even refresh the page.


@andriitkachenko Thanks you for the support. I change the code according to my requirement as bellow.
 

        protected virtual void _(Events.FieldUpdated<POLine.inventoryID> e)
{

if (!(e.Row is POLine row) || row.InventoryID == null) return;
var ext = row.GetExtension<POLineExt>();
if (ext == null) return;

var inventoryClass = PXSelectJoin<INItemClass,
InnerJoin<InventoryItem,
On<InventoryItem.itemClassID, Equal<INItemClass.itemClassID>>>,
Where<InventoryItem.inventoryID, Equal<Current<POLine.inventoryID>>>>
.Select(Base)
.FirstTableItems
.FirstOrDefault();

if (inventoryClass == null) return;

ext.UsrInventoryItemClassID = inventoryClass.ItemClassID;
ext.UsrInventoryItemClassCD = inventoryClass.ItemClassCD;
}

 


Reply