How to return a local variable in an expression?

So I have a local variable in an expression rule. Is there  a way to set that value as the return value of the expression rule?

  Discussion posts and replies are publicly visible

Parents
  • +1
    Certified Lead Developer

    Yes - just call the local variable again.

    a!localVariables(
      local!test: "Hello World!",
      
      "Here is our local variable value: " & local!test
    )

  • What if I have a much longer multi-line expression instead of what you have in line 4?

  • 0
    Certified Lead Developer
    in reply to swolfe5555

    You still just invoke previously-declared local variables by name in whatever positions you need them.  If you're having trouble, i would suggest you post your code or a representative example (please use "Insert -> Code" for readability), and I can help troubleshoot (otherwise i'm just guessing blindly).

  • /*
    Define the local variables for the function
    */
    
    a!localVariables(
      /*Will hold the table from the query that will be looped through*/
      local!offices: a!queryEntity(
        entity: cons!Geo_locationDBE,
        query: a!query(
          logicalexpression: a!queryLogicalExpression(
            operator: "AND",
            filters: {
              a!queryFilter(
                field: "Location_ID",
                operator: "not includes",
                value: "DUMMY"
              )
    
            }
          ),
          selection: a!querySelection(columns: {
            a!queryColumn(field: "Location_ID"),
            a!queryColumn(field: "Area_Name"),
            a!queryColumn(field: "Longitude"),
            a!queryColumn(field: "Latitude"),
            a!queryColumn(field: "Zipcode"),
          }),
        
          pagingInfo: a!pagingInfo(
            startIndex: 1,
            batchSize: -1    
          )
        )
          
        ),
        
      
      
      local!outLocation: "Out of Office",
      
      local!currentClosest: infinity(),
      
      local!currentDistance: infinity(),
      
    /*the script using the local variables*/
      {
    
    
    /*
    Now we need to loop through this data subset to see if the 
    location that is input from the employee's phone is closer than the 
    threshold to any of the locations in the query
    */
    
    a!forEach(
      items: local!offices,
      expression: (
        /*compute the distance*/
        {
        a!save(local!currentDistance, 
        rule!Geo_computeDistanceBetween(ri!Longitude, ri!Latitude, 
        fv!item.Longitude, fv!item.Latitude)
        ),
        
        if({
          and(local!currentDistance < local!currentClosest ,
            local!currentDistance < ri!RadiusThreshold
          )},
          /*update the output location and current closest*/
          {a!save(local!currentClosest, local!currentDistance),
          a!save(local!outLocation, fv!item.Location_ID)},
          
          /*do nothing*/
          {a!save(local!currentClosest, local!currentClosest)}
          
      ) 
      }
    )
    ),
    
    /*
    Output the location found
    */
    local!outLocation
    
    }
    
    )

  • 0
    Certified Lead Developer
    in reply to swolfe5555

    Well, I see your issue - a!save() only works within the saveInto parameter of an interactive component upon input from a user, and does not work in an expression rule to dynamically set the value of a previously declared variable.  What you should be doing instead is setting the value of local!outLocation to the logic needed to determine its value.  That or just get rid of the local!outLocation variable and directly return the value of your a!forEach at the end.  So basically you'll need to reformat the entire last block of your expression.

  • What is the purpose of a local variable if I can't use it in this situation?

  • 0
    Certified Lead Developer
    in reply to swolfe5555

    Likewise, you will need to revise how you're setting local!currentDistance.  One of the most straightforward ways to do it is to set it up-front just after your local!offices are declared:

    local!officeDistances: a!forEach(
      items: local!offices,
      expression: rule!Geo_computeDistanceBetween(
        ri!Longitude, 
        ri!Latitude, 
        fv!item.Longitude,
        fv!item.Latitude
      )
    )

    This will create an array of distances with one item in each array for each item in the local!offices array.

  • Then I guess I could just call some built in minimum function on that array

  • 0
    Certified Lead Developer
    in reply to swolfe5555
    What is the purpose of a local variable if I can't use it in this situation?

    I don't believe it's accurate to say you can't use them - the issue isn't that you want to use them, but rather that you're trying to use them in a way that they aren't made for.  They work differently than in traditional programming languages, so it's a good idea to get used to how they do (and don't) in order to accomplish advanced functionality.

    The concept you're missing here is - instead of creating a local variable initialized with a temporary value, and trying to back-save a new value later (outside of a user-interactive component), you should set each local variable to hold its desired value initially.  Then you can use that local variable either as you set subsequent local variables, or in your output.

Reply Children
  • 0
    Certified Lead Developer
    in reply to swolfe5555

    No prob - here's a streamlined version I created that demonstrates how this would probably work best for you (though you'll need to figure out a way to re-add the calculation for radiusThreshold at some point, but just for example:

    /*
    Define the local variables for the function
    */
    
    a!localVariables(
      /*Will hold the table from the query that will be looped through*/
      local!offices: a!queryEntity(
        entity: cons!Geo_locationDBE,
        query: a!query(
          logicalexpression: a!queryLogicalExpression(
            operator: "AND",
            filters: {
              a!queryFilter(
                field: "Location_ID",
                operator: "not includes",
                value: "DUMMY"
              )
    
            }
          ),
          selection: a!querySelection(columns: {
            a!queryColumn(field: "Location_ID"),
            a!queryColumn(field: "Area_Name"),
            a!queryColumn(field: "Longitude"),
            a!queryColumn(field: "Latitude"),
            a!queryColumn(field: "Zipcode"),
          }),
    
          pagingInfo: a!pagingInfo(
            startIndex: 1,
            batchSize: -1    
          )
        )
    
      ),
    
      local!officeDistances: a!forEach(
        items: local!offices,
        expression: rule!Geo_computeDistanceBetween(
          ri!Longitude, 
          ri!Latitude, 
          fv!item.Longitude,
          fv!item.Latitude
        )
      ),
      
      local!closestDistance: min(local!officeDistances),
      
      /* find closest office (assumes no duplicate distances) */
      local!closestOffice: index(
        local!offices.data, /* edited */
        where(local!officeDistances = local!closestDistance)
      ),
    
      local!closestOffice
    
    )

  • Do you know of a simple way to index a datasubset?

  • 0
    Certified Lead Developer
    in reply to swolfe5555

    yes - just add ".data" after the local variable name, i.e. "local!offices.data" might be necessary in my example above since it looks like your query returns a dataSubset instead of a data array.