SOLVED

Sorting Output in Velocity

Go to solution
Craig_MacNeil
Level 2

Sorting Output in Velocity

Hi all,

Looking for some advice. I'm delving deeper into Velocity as I continue my development learning, and I have a question about sorting. I've spent quite a bit of time on this trying to figure it out myself as I find it the best way to learn, but I'm not having too much luck. Apologies if the answer is obvious.

I've written a script to populate part of an email based on the funds that a user is subscribed to. I've included an example of what this looks like below, while substituting the data for mock data. Basically the script uses #foreach to loop through a list of funds that the user is subscribed to receive information about (the info is stored on our own in-house CMS and pulled from there - $lead.fundcode). It outputs HTML which contains links to a fund page and factsheets. There can be as little as 1 fund output, or as many as 22 for select users. It depends on how many they're subscribed to. $countrylink dictates which instance of our website the user is directed to.

Due to issues with Velocity and the tracking of multiple links I had to use Sandy's brilliant workaround using #evaluate and the script was working fine.

However, I've been asked to find a way of sorting the order in which funds are output. For example, we want Asian funds to appear together, European funds to appear together etc. At the moment this doesn't happen and they're output alphabetically.

How do I go about doing this? I've tried to use the sorter function but the below is clearly incorrect as nothing is pulling through.

 

#set( $allFundLinks = {
   "Fund 1" : {
     "name": "Test Fund 1",
     "link" : "test-fund-1-link",
     "image" : "Fund1%20Imagery.jpg",
     "order" : "1"
},
   "Fund 2" : {
     "name": "Test Fund 2",
     "link" : "test-fund-2-link",
     "image" : "Fund2%20Imagery.jpg",
     "order" : "2"
},
   "Fund 3" : {
     "name": "Test Fund 3",
     "link" : "test-fund-3-link",
     "image" : "Fund3%20Imagery.jpg",
     "order" : "3"
}
}  )

#if  ($lead.countryCode.equals("NL") )
#set ( $countryLink ="netherlands" )
#elseif ($lead.countryCode.equals("BE") )
#set ($countryLink ="belgium" )
#elseif ($lead.countryCode.equals("LU") )
#set ($countryLink = "luxembourg" )
#end

#foreach( $key in $lead.fundcode.split(";") )
  #set( $fundLink = $sorter.sort($allFundLinks,"order")[$key] )
  #evaluate( "${esc.h}set( ${esc.d}fundLink_${foreach.count} = ${esc.d}fundLink )" )
#end


#if( $fundLink_1 )

*/HTML Output*/

#end

#if( $fundLink_2 )

*/HTML Output*/

#end

#if( $fundLink_3 )

*/HTML Output*/

#end

 

1 ACCEPTED SOLUTION

Accepted Solutions
SanfordWhiteman
Level 10 - Community Moderator

Re: Sorting Output in Velocity

There’s nothing to “override” per se. I think you’re misunderstanding something as happening automatically, when it’s actually happening because of deliberate choices you’ve made in your code. You have to rethink those choices, otherwise Velocity is going to continue to do what you told it to.

 

If you want to use the order of the $allFundLinks constants, then loop over those! Don’t loop over the sub-values in the per-person field $lead.fundcode; as long as you loop over $lead.fundcode you’re beholden to the order of the semicolon-delim’d values. That’s what I mean by changing the outer loop.

 

#set( $leadFundCodes = $lead.fundcode.split(";") )
#foreach( $entry in $allFundLinks.entrySet() )
  #set( $fundLinkCode = $entry.getKey() )
  #set( $fundLinkAddl = $entry.getValue() )
  #if( $leadFundCodes.contains($fundLinkCode) )
    #set( $fundLink = $fundLinkAddl.link )
    #evaluate( "${esc.h}set( ${esc.d}fundLink_${foreach.count} = ${esc.d}fundLink )" )
  #end
#end

 

View solution in original post

4 REPLIES 4
SanfordWhiteman
Level 10 - Community Moderator

Re: Sorting Output in Velocity

(1) $allFundLinks is already ordered — it’s a LinkedHashMap, so the items are ordered in order of insertion. If you #foreach over $allFundLinks you’ll see it outputs the objects from top to bottom.

 

(2) When you call $sorter.sort($allFundLinks,"order") you’re asking Velocity to falsify (or, more politely, invent) an iterator for the LinkedHashMap, which doesn’t naturally have one. It will choose to iterate over the values (the objects), not the keys (the simple fund names). So the result of $sorter.sort is an ArrayList of LinkedHashMaps, a completely different shape from the original. The keys are no longer present.

 

(3) You shouldn’t be sorting on a string value if you want numeric order. String sorting will place “100” before “2” for example.

 

(4) You shouldn’t sort on every turn of the loop, that’s redundant.

 

(5) If you want the top-to-bottom order of $allFundLinks to also be the order of the output, then your outer loop should be over $allFundLinks.

Craig_MacNeil
Level 2

Re: Sorting Output in Velocity

Hi Sanford,

Thanks for taking the time to reply. For someone who is still learning this is really useful. It's taking me quite a bit of time to get my head around this so your patience is appreciated.

On your first point, I understand that $allFundLinks is already ordered but with the way our script is set up it doesn't necessarily output in that order. I've included an example of my (currently working) script below.

We have a semi-colon delimited field called $lead.fundcode in which the user's fund preferences are stored (e.g. FUND1; FUND2; FUND3). As I understand it the script below will output the HTML based on the order in which the funds are set within that field, not $allFundLinks. Is there any way of overriding that or are we stuck with the order in which it's set in the field? 

 

 

#set( $allFundLinks = {
   "TEST1" : {
     "name": "Test Fund 1",
     "link" : "test-fund-1-link",
     "image" : "Fund1%20Imagery.jpg"
},
   "TEST3" : {
     "name": "Test Fund 3",
     "link" : "test-fund-3-link",
     "image" : "Fund3%20Imagery.jpg"
},
   "TEST2" : {
     "name": "Test Fund 2",
     "link" : "test-fund-2-link",
     "image" : "Fund2%20Imagery.jpg"
}
}  )


#if  ($lead.countryCode.equals("NL") )
#set ( $countryLink ="netherlands" )
#elseif ($lead.countryCode.equals("BE") )
#set ($countryLink ="belgium" )
#elseif ($lead.countryCode.equals("LU") )
#set ($countryLink = "luxembourg" )
#end

#foreach( $key in $lead.fundcode.split(";") )
  #set( $fundLink = $allFundLinks[$key] )
  #evaluate( "${esc.h}set( ${esc.d}fundLink_${foreach.count} = ${esc.d}fundLink )" )
#end


#if( $fundLink_1 )

*/ HTML Output

#end

#if( $fundLink_2 )

*/ HTML Output

#end

#if( $fundLink_3 )

*/ HTML Output

#end

 

 

 

SanfordWhiteman
Level 10 - Community Moderator

Re: Sorting Output in Velocity

There’s nothing to “override” per se. I think you’re misunderstanding something as happening automatically, when it’s actually happening because of deliberate choices you’ve made in your code. You have to rethink those choices, otherwise Velocity is going to continue to do what you told it to.

 

If you want to use the order of the $allFundLinks constants, then loop over those! Don’t loop over the sub-values in the per-person field $lead.fundcode; as long as you loop over $lead.fundcode you’re beholden to the order of the semicolon-delim’d values. That’s what I mean by changing the outer loop.

 

#set( $leadFundCodes = $lead.fundcode.split(";") )
#foreach( $entry in $allFundLinks.entrySet() )
  #set( $fundLinkCode = $entry.getKey() )
  #set( $fundLinkAddl = $entry.getValue() )
  #if( $leadFundCodes.contains($fundLinkCode) )
    #set( $fundLink = $fundLinkAddl.link )
    #evaluate( "${esc.h}set( ${esc.d}fundLink_${foreach.count} = ${esc.d}fundLink )" )
  #end
#end

 

Craig_MacNeil
Level 2

Re: Sorting Output in Velocity

That's done it. Thanks very much for your help. Learning all the time 😂