Having multiple saves in braces

Certified Senior Developer

Hello,

Is there any reason that Appian would only execute the first a!save inside a bracket, and not the rest of it? The code goes into the second part of the if statement, and only runs whichever is the first function in the braces. If I switch the order of the 2, it still only runs the first one. 

Attached is my code. Thank you for your help. 

if(
index(
local!existingEvaluationPlanSnapshot,
"evaluation_id_fk",
null
) = local!relevantEvaluation.id_pk,
a!save(
ri!evaluationAction,
local!existingEvaluationPlanSnapshot
),
{
a!save(
ri!evaluationActionToDelete,
local!existingEvaluationPlanSnapshot
),
a!save(
ri!evaluationAction,
'type!{urn:com:appian:types}evaluationActions'(
evaluation_id_fk: local!relevantEvaluation.id_pk,
action_plan_id_fk: ri!actionPlan.id_pk,
created_by: loggedInUser(),
created_on: now()
)
)
}
),

  Discussion posts and replies are publicly visible

Parents
  • I ran into a similar situation recently where a!save's within an if() would only execute the first a!save, and was just able to replicate after a number of different attempts.  There appears to be a bug where in some situations, only the first a!save will fire within an if().  In my situation the CDT I'm using in the if() is a List of CDT with 1 item, vs a single CDT item.  I can replicate this with a List of Dictionary as well (replication code below). 

    We're on 19.4, and I will submit a bug report today.  This bug was around prior on 19.1 as well, I can confirm as we just completed our 19.4 upgrade (been troubleshooting since prior..). 

    I have found that you can work-around this by either adding a nested index() to ensure 1 item returned, or moving the if() calls into the second parameter of each a!save, so all will always fire but save their current value back (no change) if the should not update. I'm guessing here your local!existingEvaluationPlanSnapshot is actually a List type with 1 item.

    You should have 2 options here, first would be to wrap a second index() call to ensure only one result such as:

    if(
    index(
    index(
    local!existingEvaluationPlanSnapshot,
    "evaluation_id_fk",
    null
    ),
    1,
    null) = local!relevantEvaluation.id_pk,

    Second you can try this for your saveInto setup which executes all saves always but the value parameter depends on whether or not you want to change the variable:

    with(
    local!eval: index(
    local!existingEvaluationPlanSnapshot,
    "evaluation_id_fk",
    null
    ) = local!relevantEvaluation.id_pk,
    {
    a!save(
    ri!evaluationAction,
    if(local!eval,local!existingEvaluationPlanSnapshot,ri!evaluationAction)
    ),
    a!save(
    ri!evaluationActionToDelete,
    if(local!eval,ri!evaluationActionToDelete,local!existingEvaluationPlanSnapshot)
    ),
    a!save(
    ri!evaluationAction,
    if(local!eval,ri!evaluationAction,
    'type!{urn:com:appian:types}evaluationActions'(
    evaluation_id_fk: local!relevantEvaluation.id_pk,
    action_plan_id_fk: ri!actionPlan.id_pk,
    created_by: loggedInUser(),
    created_on: now()
    )
    )
    )
    }
    )

    For replicating this issue, try this code in a new interface.  When you click Submit, Test Field 1 is the only a!save to execute.  I have 2 options in there to swap to for correct functionality:

    a!localVariables(
    local!test1: "Initialized",
    local!test2: "Initialized",
    local!test3: "Initialized",
    /* When we have a List of dictionary with 1 item, the bug presents itself */
    local!data: {{version: 3}},
    /* Work-around #1 below */
    /*local!data: index({{version: 3}},1,{}),*/
    a!formLayout(
    label: "Form",
    contents: {
    a!sectionLayout(
    contents: {
    a!columnsLayout(
    columns: {
    a!columnLayout(
    contents: {
    a!textField(readOnly: true, labelPosition: "ADJACENT", label: "Version", value: local!data.version),
    a!textField(readOnly: true, labelPosition: "ADJACENT", label: "Is Version > 2", value: tointeger(local!data.version)>2)
    }
    ),
    a!columnLayout(
    contents: {
    a!textField(readOnly: true, labelPosition: "ADJACENT", label: "Test Field 1", value: local!test1),
    a!textField(readOnly: true, labelPosition: "ADJACENT", label: "Test Field 2", value: local!test2),
    a!textField(readOnly: true, labelPosition: "ADJACENT", label: "Test Field 3", value: local!test3)
    }
    )
    }
    )
    }
    )
    },
    buttons: a!buttonLayout(
    primaryButtons: {
    a!buttonWidget(
    label: "Submit",
    submit: true,
    style: "PRIMARY",
    saveInto: {

    if(
    tointeger(local!data.version)>2,
    {
    a!save(local!test1,"saved1"),
    a!save(local!test2,"saved1"),
    a!save(local!test3,"saved1")
    },
    {
    a!save(local!test1,"saved2"),
    a!save(local!test2,"saved2"),
    a!save(local!test3,"saved2")
    }
    )

    /* UNCOMMENT BELOW FOR WORK-AROUND #3 */

    /*,*/
    /*with(*/
    /*local!save: tointeger(local!data.version)>2,*/
    /*{*/
    /*a!save(local!test1,if(local!save,"saved3",local!test1)),*/
    /*a!save(local!test2,if(local!save,"saved3",local!test2)),*/
    /*a!save(local!test3,if(local!save,"saved3",local!test3))*/
    /*}*/
    /*)*/
    }
    ),
    a!buttonWidget(
    label: "Reset",
    submit: true,
    style: "SECONDARY",
    saveInto: {
    a!save(local!test1,"Initialized"),
    a!save(local!test2,"Initialized"),
    a!save(local!test3,"Initialized")
    }
    )
    }
    )
    )
    )

  • 0
    Certified Lead Developer
    in reply to Chris

    Somewhat reviving a zombie thread here but someone has just asked me about this very same problem and sent me this thread, which they found a bit difficult to understand. Chris's answer is correct, but I thought it might be worth adding some specifics as to what is happening, as well as a simpler example and explanation.

    Ultimately, this issue occurs because the first input to fn!if() is an array, normally of one item. Here's an example of the issue, but returning bits of text rather than a!save() functions:

    if(
      {true},
      {
        "first value if true",
        "second value if true"
      },
      {
        "first value if false",
        "second value if false"
      }
    )

    In this example, I've wrapped the boolean condition in curly braces, and so it's a list of boolean with a length of 1. Because I've passed a list of one boolean as the condition, and lists in the value parameters, only the first item of the relevant value parameter will be returned. Similarly, if the condition is set to {false}, we'll only be returned the first item in the second list of items.

    This behaviour is actually documented here, but here's the text for completeness:

    • When a list is passed to the condition parameter, it is treated as a list of conditions and the value parameters will be treated as lists of values to return.
      • This means that when passed an empty list, if() always returns an empty list.
      • When passed a list containing a single boolean and lists in the value parameters, only the first item of the selected list will be returned.

    Hopefully that makes it clear what is happening - it's certainly an easy one to be caught out by!

Reply
  • 0
    Certified Lead Developer
    in reply to Chris

    Somewhat reviving a zombie thread here but someone has just asked me about this very same problem and sent me this thread, which they found a bit difficult to understand. Chris's answer is correct, but I thought it might be worth adding some specifics as to what is happening, as well as a simpler example and explanation.

    Ultimately, this issue occurs because the first input to fn!if() is an array, normally of one item. Here's an example of the issue, but returning bits of text rather than a!save() functions:

    if(
      {true},
      {
        "first value if true",
        "second value if true"
      },
      {
        "first value if false",
        "second value if false"
      }
    )

    In this example, I've wrapped the boolean condition in curly braces, and so it's a list of boolean with a length of 1. Because I've passed a list of one boolean as the condition, and lists in the value parameters, only the first item of the relevant value parameter will be returned. Similarly, if the condition is set to {false}, we'll only be returned the first item in the second list of items.

    This behaviour is actually documented here, but here's the text for completeness:

    • When a list is passed to the condition parameter, it is treated as a list of conditions and the value parameters will be treated as lists of values to return.
      • This means that when passed an empty list, if() always returns an empty list.
      • When passed a list containing a single boolean and lists in the value parameters, only the first item of the selected list will be returned.

    Hopefully that makes it clear what is happening - it's certainly an easy one to be caught out by!

Children
No Data