= load( local!items: { { id: 1, summary: "Item 1", qty: 1, unitPrice: 10 }, { id: 2, summary: "Item 2", qty: 2, unitPrice: 20 }, { id: 3, summary: "Item 3", qty: 3, unitPrice: 30 } }, /* Needed when adding or removing items via a!applyComponents */local!itemsToken, local!newItems, local!deletedItemIds, local!delIndex, a!formLayout( label: "SAIL Example: Inline Editable Grid Tracking Adds and Deletes", firstColumnContents: { a!gridLayout( headerCells: { a!gridLayoutHeaderCell( label: "Summary" ), a!gridLayoutHeaderCell( label: "Qty", align: "RIGHT" ), a!gridLayoutHeaderCell( label: "U/P", align: "RIGHT" ), a!gridLayoutHeaderCell( label: "Amount", align: "RIGHT" ), a!gridLayoutHeaderCell( label: "" )/*For the "Remove" column*/ }, /* Only needed when some columns need to be narrow */columnConfigs: { a!gridLayoutColumnConfig( width: "DISTRIBUTE" ), a!gridLayoutColumnConfig( width: "NARROW" ), a!gridLayoutColumnConfig( width: "NARROW" ), a!gridLayoutColumnConfig( width: "DISTRIBUTE" ), a!gridLayoutColumnConfig( width: "NARROW" ) }, rows: a!applyComponents( function: rule!ucItemRowEach( items: local!items, index: _, itemsToken: local!itemsToken, delIndex: local!delIndex, deletedItemIds: local!deletedItemIds ), array: if( or( isnull( local!items ), count( local!items ) < 1 ), {}, 1 + enumerate( count( local!items ) ) ), arrayVariable: local!itemsToken ) ), a!linkField( label: "Add Link", labelPosition: "COLLAPSED", links: a!dynamicLink( label: "+Add Item", /* * For your use case, set the value to a blank instance of your CDT using * the type constructor, e.g. type!PurchaseRequestItem(). Only specify the field * if you want to give it a default value e.g. due: today()+1. */value: { id: null }, saveInto: { a!save( local!items, append( local!items, save!value ) ), /* * When modifying the size of the array used in a!applyComponents, * make the same change in the "token" array variable */a!save( local!itemsToken, append( local!itemsToken, save!value ) ) } ) ), if( isnull( local!delIndex ), {}, a!richTextDisplayField( value: { a!richTextItem( text: "Are you sure you want to delete this row?" ), a!richTextItem( text: " YES ", link: a!dynamicLink( value: local!delIndex, saveInto: { a!save( local!items, remove( local!items, save!value ) ), a!save( local!itemsToken, remove( local!itemsToken, save!value ) ), a!save( local!delIndex, null ) } ) ), a!richTextItem( text: " NO ", link: a!dynamicLink( value: null, saveInto: local!delIndex ) ) } ) ), a!textField( label: "New Items", value: local!newItems, readOnly: true ), a!textField( label: "Deleted Items", value: local!deletedItemIds, readOnly: true ) }, buttons: a!buttonLayout( /* * Using a!buttonWidget() for the updated value of local!newItems to be displayed * in the UI for testing purposes. Use a!buttonWidgetSubmit() in your form. */primaryButtons: a!buttonWidget( label: "Submit", /* This null should have the same type as your id field */value: tointeger( null ), /* * The tointeger() conversion in wherecontains() is not needed when * you swap the value of local!items with your CDT array */saveInto: a!save( local!newItems, index( local!items, wherecontains( save!value, tointeger( local!items.id ) ), null ) ) ) ) ) )