Working with Field Values Using a Parameterized Name

When writing reusable code, if your object function needs to perform the same operations on different fields, you can parameterize the field name.

Start by defining a function parameter of type String whose value at runtime will be the name of a field in the current object. Then, when your code needs to access the value of the parameterized field, just call getAttribute(fieldNameParam). To assign a new value to that field, call setAttribute(fieldNameParam,newValue). In either case, if the value of the field name parameter passed in does not match the name of some field in the current object, a NoDefException will be thrown to signal an error.

Consider the following example of an object function named conditionalIncrement() that increments the value of the number field whose name is passed in only if the field’s value is less than a maximum value also passed in:

// Object function: void conditionalIncrement(fieldName String, maxValue Long)
// ---------------
def fieldValue = getAttribute(fieldName)
if (fieldValue < maxValue) {
  setAttribute(fieldName, fieldValue + 1)
} 

The first line defines a fieldValue variable to store the value of the field whose name is passed in. If its value is less than maxValue, then line three assigns the field a new value that is one greater than its current value. Once you define an object function like conditionalIncrement(), then any Groovy scripts on the same object can invoke it, passing in appropriate argument values. For example, in one script suppose you need to increment the value of a field named UsageCount if its value is less than 500:

// Increment the usage count if it is less than 500
conditionalIncrement('UsageCount', 500)

In another script, imagine you need to increment the value of a DocumentVersionNumber field if its value is less than 1000. You can use the same object function: just pass in different values for the field name and maximum value parameters:

// Increment the document version number if it is less than 1000
conditionalIncrement('DocumentVersionNumber', 1000)

Of course the getAttribute() and setAttribute() functions can also accept a literal String value as their first argument, so you could theoretically write conditional logic like:

// Ensure document is not locked before updating request-for-approval date
// NOTE: more verbose get/setAttribute() approach
if (getAttribute('DocumentStatus') != 'LOCKED') {
  setAttribute('RequestForApprovalDate', today())
}

However, in the example above, when the name of the field being evaluated and assigned is not coming from a parameter or local variable, then it is simpler and more readable to write this equivalent code instead:

// Ensure document is not locked before updating request-for-approval date
// NOTE: More terse, elegant direct field name access
if (DocumentStatus != 'LOCKED') {
  RequestForApprovalDate = today()
}

When invoked on their own, the getAttribute() and setAttribute() functions operate on the current object. However, anywhere in your script code where you are working with a business object Row, you can also call these functions on that particular row as shown in the following example of an object function. Notice that it also parameterizes the name of the object passed to the newView() function:

// Object function: String getRowDescription(objectName String, displayFieldName String, id Long)
// ---------------
// Create a new view object to work with the business object whose name is
// passed in the objectName parameter
def view = newView(objectName)
// Find the row in that view whose key is given by the value of the id parameter
def rows = view.findByKey(key(id),1)
// If we found exactly one row, return the value of the display field name on
// that row, whose field name is given by the value in the displayFieldName parameter
return rows.size() == 1 ? return rows[0].getAttribute(displayFieldName) : null

With such a function defined, we can invoke it from any script in the object to access the display field value of different objects we might need to work with:

// Get RecordName of the Task object with key 123456
def taskName = getRowDescription('Task','RecordName',123456)
// Get the Name of the Territory object with key 987654
def optyName = getRowDescription('Territory','Name',987654)

If you use the getAttribute() or setAttribute() to access field values on a related object, remember that the first argument must represent the name of a single field on the object on which you invoke it. For example, the following is not a correct way to use the setAttribute() function to set the Status field of the parent TroubleTicket object for an activity because TroubleTicket?.Status is not the name of a single field on the current Activity object:

// Assume script runs in context of an Activity object (child of TroubleTicket)
// INCORRECT way to set a parent field's value using setAttribute()
setAttribute('TroubleTicket?.Status', 'Open')

Instead, first access the related object and store it in a local variable. Then you can assign a field on the related object as follows:

// Assume script runs in context of an Activity object (child object TroubleTicket)
// First access the parent object
def parentTicket = TroubleTicket
// Then call the setAttribute on that parent object
parentTicket?.setAttribute('Status', 'Open')