Skip to main content
Solved

Can't use Custom Field within Modern UI Event Handler

  • September 3, 2026
  • 12 replies
  • 103 views

Forum|alt.badge.img+1

I’m trying to follow the examples to change the CSS styling of a row within a grid: I’ve a custom field that gives the quantity allocated on each Sales Order details line and want to change the colour of that line to highlight when it isn’t fully allocated.

So I started with this: UI Events: Changing of the CSS for a Row of a Table • UI Development Guide • Acumatica Beacon

(And added handleEvent, CustomEventType, RowCssHandlerArgs to the import {} from “client-controls” )

	@handleEvent(CustomEventType.GetRowCss, { view: "Transactions" })​
getReceivedRowCss(args: RowCssHandlerArgs<SOLine>): string {​
const split = args?.selector?.row;​

if (split != null && split.UsrQtyAllocated.value < split.UnshippedQty.value) {​
return "bold-row";​
}​
return undefined;​
}​

Where UnshippedQty is a standard field in SOLine. UsrQtyAllocated is defined in (DAC) SOCustomisations.SOLineExt, and in the .ts file as:

export class SOLine_SOCustomisations_generated {
@placeAfterProperty("OrderQty")
UsrQtyAllocated: PXFieldState;
}

 

But I get two compilation errors during publishing:

I think it’s the @handleEvent line that gives the error: 

TS2322: Type 'string' is not assignable to type 'never'

And I also get:

TS2339: Property 'UsrQtyAllocated' does not exist on type 'SOLine'

 

How do I access that custom field?

How do I get around the TS2322 error?

Best answer by MichaelShirk

You tried both snippets?

 

Here’s a direct copy from my code. The only other difference I can spot is that I use single quotes instead of double. I don’t think that should make a difference, but you could try it. 
Also, is “bold-row” and out of the box css class or custom? If custom, try something like ‘red60’. 

	@handleEvent(CustomEventType.GetRowCss, { view: 'Details' })
getDetailsRowCss(args: RowCssHandlerArgs): any {
const row = args?.selector?.row;
if (!row) return undefined;

const priority = row.DeliveryPriority?.value;
if (priority === Priority_10DayRush || priority === Priority_Rebuild) return 'red60';

const confirmed = row.Confirmed?.value;
const remaining = row.DeliveryRemaining?.value;
if ((confirmed == null || confirmed === false) && priority !== Priority_Exception && remaining != null && remaining <= 5)
return 'yellow60';

return undefined;
}

 

12 replies

darylbowman
Captain II
Forum|alt.badge.img+17

I have this pattern saved for getting an extension where EP307000_PMTimeActivity_DXCrewID is the extension class:

@handleEvent(CustomEventType.RowSelected, { view: "Activity" })
onActivityRowSelected(args: RowSelectedHandlerArgs<PXViewCollection<PMTimeActivity>>) {
const model = args.viewModel as PXViewCollection<EP307000_PMTimeActivity_DXCrewID>;
if (model.SplitRecord) {
model.SplitRecord.enabled = !!args.viewModel.activeRow?.id;
}
}

 


Forum|alt.badge.img+1

Thanks ​@darylbowman, that moves me on somewhat. I now have this:

	@handleEvent(CustomEventType.GetRowCss, { view: "Transactions" })​
getReceivedRowCss(args: RowCssHandlerArgs<SOLine_SOCustomisations_generated>): string {​
const split = args?.selector?.row;​
if (split != null && split.OrderQty.value > split.UnshippedQty.value) {​
return "bold-row";​
}​
return undefined;​
}​

But I still get the other error:

 

 TS2322: Type 'string' is not assignable to type 'never'

darylbowman
Captain II
Forum|alt.badge.img+17

Try this:

@handleEvent(CustomEventType.GetRowCss, { view: "Transactions" })
getReceivedRowCss(args: RowCssHandlerArgs<PXViewCollection<SOLine_SOCustomisations_generated>>): string {
const split = args?.selector?.row;
if (split != null && split.OrderQty.value > split.UnshippedQty.value) {
return "bold-row";
}
return undefined;
}

 


Forum|alt.badge.img+1

Thanks again Daryl.

But this line:

@handleEvent(CustomEventType.GetRowCss, { view: "Transactions" })

Is the one that gives the compilation error.

If I comment it, the project will publish without any other errors.


MichaelShirk
Captain II
Forum|alt.badge.img+6
  • Captain II
  • September 4, 2026

@allisterchambers48 try this. 
Using “any” as the return type fixes it.
 

	@handleEvent(CustomEventType.GetRowCss, { view: "Transactions" })​
getReceivedRowCss(args: RowCssHandlerArgs<SOLine_SOCustomisations_generated>): any {​
const split = args?.selector?.row;​
if (split != null && split.OrderQty.value > split.UnshippedQty.value) {​
return "bold-row";​
}​
return undefined;​
}​

Or if you still want to use the custom field. 
 

@handleEvent(CustomEventType.GetRowCss, { view: "Transactions" })
getReceivedRowCss(args: RowCssHandlerArgs): any {
const row = args?.selector?.row;
if (!row) return undefined;

const allocated = row.UsrQtyAllocated?.value;
const unshipped = row.UnshippedQty?.value;
if (allocated != null && unshipped != null && allocated < unshipped) return "bold-row";

return undefined;
}

 


Forum|alt.badge.img+1

Thanks ​@MichaelShirk . But doesn’t fix it.


MichaelShirk
Captain II
Forum|alt.badge.img+6
  • Captain II
  • Answer
  • September 4, 2026

You tried both snippets?

 

Here’s a direct copy from my code. The only other difference I can spot is that I use single quotes instead of double. I don’t think that should make a difference, but you could try it. 
Also, is “bold-row” and out of the box css class or custom? If custom, try something like ‘red60’. 

	@handleEvent(CustomEventType.GetRowCss, { view: 'Details' })
getDetailsRowCss(args: RowCssHandlerArgs): any {
const row = args?.selector?.row;
if (!row) return undefined;

const priority = row.DeliveryPriority?.value;
if (priority === Priority_10DayRush || priority === Priority_Rebuild) return 'red60';

const confirmed = row.Confirmed?.value;
const remaining = row.DeliveryRemaining?.value;
if ((confirmed == null || confirmed === false) && priority !== Priority_Exception && remaining != null && remaining <= 5)
return 'yellow60';

return undefined;
}

 


Forum|alt.badge.img+1

Seems like we’re looking in the wrong place.

This compiles:

	@handleEvent(CustomEventType.GetRowCss, /*{ view: 'Details' }*/)​
getDetailsRowCss(args: RowCssHandlerArgs<SOLine_SOCustomisations_generated>): undefined | string{​
const split = args?.selector?.row;​
if (split != null && split.OrderQty.value > split.UnshippedQty.value) {​
return "bold-row";​
}​
return undefined;​
}​

It looks to be the parameter passed to handleEvent which is the problem.

Commenting out the second parameter gives something that will compile (but presumably won’t get bound to the correct view. 

Neither of these work:

  • {view: “Details”}
  • {view: “Transactions” }

Forum|alt.badge.img+1

The error message, including the source name gives:

customizationScreens\Company\screens\SO\SO301000\extensions\SO301000_SOCustomisations_generated.ts(99,44)      TS2322: Type 'string' is not assignable to type 'never'

And the text appearing on line 99, character 44 is 

{ view: "Transactions" }

Definitely something funky about that parameter.

 


Forum|alt.badge.img+8
  • Captain II
  • September 4, 2026

I think you have added a colon where you don’t want one:

getReceivedRowCss(args: RowCssHandlerArgs<SOLine>): string {​

Based on all the code that I’ve been looking at from my install, that line should be:

getReceivedRowCss(args: RowCssHandlerArgs<SOLine>) {​

Here’s an example from PM301000.ts and it follows the syntax that ​@darylbowman had given:

@handleEvent(CustomEventType.GetRowCss, { view: "BalanceRecords" })
getItemsRowCss(args: RowCssHandlerArgs<PXViewCollection<BalanceRecords>>) {
return args?.selector?.row?.RecordID.value < 0
? PMConstants.BoldRowCssClass
: undefined;
}

Edit: I found in PO302020_Receive.ts and example like yours:

@handleEvent(CustomEventType.GetRowCss, { view: "Received" })
getReceivedRowCss(args: RowCssHandlerArgs<PXViewCollection<ReceiptSplitsForReceive>>): string {
const split = args?.selector?.row;

if (split == null || split.ReceivedQty.value === 0) {
return undefined;
}
else if (this.Document?.WMSSingleOrder?.value === true || split.Qty.value === 0) {
if (split.RestQty.value === 0) {
return "startedLine completedLine";
}
else if (split.ReceivedQty.value > 0) {
return "startedLine";
}
}
else {
if (split.ReceivedQty.value > split.Qty.value) {
return "startedLine excessedLine";
}
else if (split.ReceivedQty.value === split.Qty.value) {
return "startedLine completedLine";
}
else if (split.ReceivedQty.value > 0) {
return "startedLine";
}
}

return undefined;
}

 


Forum|alt.badge.img+1

Thanks ​@Django. But that change affects code after the line that the error is reported against. I still get the error.


Forum|alt.badge.img+1

Here’s my working version:

    @handleEvent(CustomEventType.GetRowCss, { view: 'Transactions' } )​
onGetRowCss(args:RowCssHandlerArgs): undefined | string
{​

const model = args?.selector?.row as SOLine_SOCustomisations_generated;​
if (model != null && model.OrderQty.value > (model.ShippedQty.value + model.UsrQtyAllocated.value ) ) {​
return "bold-row";​
}​

return undefined;​
}​
  • Single- or Double- quotes seem equivalent
  • args: can be RowCssHandlerArgs or RowCssHandlerArgs<PXViewCollection<SOLine>>, but can’t be RowCssHandlerArgs<PXViewCollection<SOLine_SOCustomisations_generated», presumable because Transactions is PXViewCollection<SOLine> and can’t be narrowed to this derived type.
  • {view: “Transactions”} is a selector for a View. That view must match the type  T where args is PXViewCollection<T>. If the name or the type doesn’t match, the selector find a result to which no value (Never) can be assigned.
  • onGetRowCss() needs “: [return type]” otherwise it is a subroutine and not permitted to return a function value
  • The Usr field is not available on args?.selector?.row. This must be cast to the derived type in order to access all base and custom fields.