You can enable users to select individual items in a result matrix dashboard portlet and run an action (trigger an event) on a button click.

In this example, we have a Dashboard with a result matrix portlet listing LPG items. Users can select any of these items and run their recalculation.

Under the hood, there are two logics associated with this Dashboard. One logic (main) builds the Dashboard content. An Option Input allows the user to select one of the Live Price Grids that exist in the partition. When the Dashboard is refreshed, a result matrix displays the LPG Items, one row per item, with SKU and lastUpdateDate.

The user can select one or multiple rows, and click on the “Calc PGI” button. When the user clicks the button, we run a different logic (action), which reads the list of the selected SKUs (i.e. the LPG Items) and triggers the calculation of each of them.

After about one minute, to allow time for the backend processing, if you refresh the dashboard, you’ll see that the lastUpdateDate of the selected rows have changes, proving that the calculation has been done.

The “action” logic can do anything we allow in the Groovy Sandbox. Here we just recalculate the LPG items. But it could as easily create a new Live Price Grid or Price List with the selected SKUs.

Dashboard Logic

The Dashboard logic contains the following elements:

pg_list
api.findPriceGrids(null, null)
input_pg_label
def labels = api.getElement("pg_list")*.label.sort()

api.option("Pick an LPG", labels)
input_activate_click
api.booleanUserEntry("Activate Embedded")
input_activate_select
api.booleanUserEntry("Activate Select")
pg
def label = api.getElement("input_pg_label")

if (label == null || api.syntaxCheck) return

api.getElement("pg_list").find { label.equals(it.label) }
pg_items
def pg = api.getElement("pg")

if (pg == null || api.syntaxCheck) return


def fields = ["sku", "activePrice", "submitDate", "lastUpdateDate"]
def sortField = "sku"
def filter = Filter.equal("priceGridId", pg.id)

api.find("PGI", 0, 200, sortField, /* fields, */ filter)
matrix
def pg = api.getElement("pg")

if (pg == null || api.syntaxCheck) return


def matrix = api.newMatrix([
  "sku", "activePrice", "lastUpdateDate", "download", "action"
])

matrix.setTitle(pg.label)
matrix.setEnableClientFilter(true)
matrix.setColumnFormat("lastUpdateDate", FieldFormatType.DATETIME)
matrix.setPreferenceName("UltimateResultMatrix_uuid42")
matrix.addColumnTranslation("sku", [en: "sku (click leads to Master Data)"])

api.getElement("pg_items").each { pgi ->
  def row = [:]
  row.sku = matrix.linkCell(pgi.sku, AppPages.MD_PRODUCTS_PAGE, pgi.sku)
  row.activePrice = pgi.activePrice
  row.lastUpdateDate = pgi.lastUpdateDate
  row.download = createDownloadLink(matrix, pg, pgi)
  row.action = createCalcPgiAction(matrix, pg, pgi)
  matrix.addRow(row)
}

if (api.getElement("input_activate_click")) {
  addClickEvent(matrix)
}

if (api.getElement("input_activate_select")) {
  addRowSelectionBackEndAction(matrix, pg)
}

return matrix

// helper methods (they make the above code more readable)

def createDownloadLink(def matrix, def pg, def pgi) {
  matrix.downloadButton("Download (whole PG)",
                        "/pricegridmanager.fetchpdf/" + pg.id,
                        null /*payload*/)
}

def createCalcPgiAction(def matrix, def pg, def pgi) {
  matrix.backEndAction("Recalculate (this item)",
                       "/pricegridmanager.update/" + pg.id,
                       api.toJson([data:[typedId: pgi.typedId]]),
                       "success",
                       "failure")
}

def addClickEvent(def matrix) {
  matrix
    .onRowSelection()
      .triggerEvent(api.dashboardWideEvent("myEvent"))
      .withColValueAsEventDataAttr("sku", "sku_attribute")
}

def addRowSelectionBackEndAction(def matrix, def pg) {
  matrix
    .rowSelectionBackEndAction("SKUs")
      .withLogicName("SC_UltimateMatrix_calc")
      .withColumns("sku")
      .addFormulaInput("PG_label", pg.label)
      .addFormulaInput("PG_id", pg.id)
      .withButtonLabel("Calc PGI")
      .withButtonTooltip("(Re)Calculate the selected Price Grid Items (SKUs)")
      .withSuccessMessage("Success")
      .withFailureMessage("Sorry")
}
embedded
if (!api.getElement("input_activate_click")) return

api.dashboard("JJ_embedded_event_chart")

	// Show the dashboard embedded ...
	.showEmbedded()
			
	// ... and reevaluate it on "myEvent"
	// Note: "dashboardWideEvent()" fce makes the event local
	// to the containing dashboard instance
	.andRecalculateOn(api.dashboardWideEvent("myEvent"))
			

	// Pull the "customerId" attribute out of the event payload and expose it
	// as the "Customer Id" input to the embedded dashboard
	.withEventDataAttr("sku_attribute").asParam("SKU")
	//.withEventDataAttr("bandBy").asParam("CustomerClass")

Action Logic

The action logic contains the following elements:

input_pgid
def pg_id = api.decimalUserEntry('PG_id')

// test value
if (pg_id == null) {
  pg_id = 5 // "Fourth Live Price Grid"
}

pg_id as Long
input_skus
def matrix = api.inputMatrix("SKUs", "sku")

// Front End payload validation
if (!api.syntaxCheck) {
  validate(matrix) // throws exception if invalid - this validation is totally optional, feel free to drop or tailor to your own needs
}

// test value
if (matrix == null) {
  matrix = [[sku: "MB-0007"]]
}

matrix*.sku



def validate(def matrix) {
  if (matrix == null) {
    exception(matrix, "is missing or null")
  }
  if (matrix.size() == 0) {
    exception(matrix, "should not be empty")
  }
  if (! (matrix instanceof List) || ! (matrix[0] instanceof Map)) {
    exception(matrix, "should be an Array of Maps")
  }
  if (matrix[0].keySet() == ["sku"] as Set) {
    // that's expected for backend action
  }
  else if (matrix[0].keySet() == ["sku", "selected"] as Set) {
    // that's expected for UI InputMatrix
  }
  else {
    exception(matrix, "should have only 'sku' values")
  }
  if (matrix*.sku.find {!it instanceof String}) {
     exception(matrix, "should have'sku' values of type String")
  }
}

def exception(def matrix, def msg) {
  api.throwException("'SKUs' InputMatrix " + msg + " - " + api.toJson(matrix))
}
calculate
def pg_id = api.getElement("input_pgid")
def sku_list = api.getElement("input_skus")

api.triggerPriceGridCalculation(pg_id, [skusToRecalc: sku_list])

return null