Auto Slot from sys_DropDownMultiple

I have been trying to get an auto slot to populate from the contents of a sys_DropDownMultiple control. I know this would be far easier to just use a manual slot and only allow a certain content type in the slot, however I have a situation where many items would need to be added to the slot and for speed it would be better to select them from a list rather than searching for each one.

My first idea was to create a dynamic WHERE clause and pass it to the sql query in the auto slot but this does not seem to work since the parameters of the auto slot must be in URL query format, so passing something like “rx:sys_contentid=1847 OR rx:sys_contentid=1858 OR rx:sys_contentid=1869” is not possible.

I can get the process to work by looping over the value contained by the sys_DropDownMultiple control (content id of selected content type) and creating multiple slots but this has disadvantages such as not being able to sort or group the items.

#foreach($myChild in $myChildren)
#set($degreeIds = $myChild.String)
#slot(“erauDegreeList” “<h2>Degrees & Programs</h2><ul>” “<li>” “</li>” “</ul>” “degreeIds=$degreeIds”)
#end

Are there any other approaches that would allow me to use the sys_DropDownMultiple control instead of a normal slot control?

This isn’t the whole solution to your problem, but I did want to point out one thing:

the parameters of the auto slot must be in URL query format

This is incorrect. There are 2 possible ways to pass parameters to a slot, you can pass a string in URL format, or you can use a Map variable.

To define a Map variable, you just reference it by name:

$slotparams.maxresults = 10
$slotparams.template = "myTemplate"
$slotparams.ids = "1,2,3,4,5"

In the #slot macro, you just refer to the variable without enclosing it in quotes:

#slot("myslot" "" "" "" "" $slotparams)

In your query you can do something like this:

select .... from rx:type where id in (:idlist)

This is a much better solution than using multiple slots.

The sys_AutoSlotContentFinder allows you to pass in a parameter called query. So you could use some kind of loop to build up a JSR-170 query* in a string variable called $query, then call the #slot macro (or #initslot if doing a “raw slot”) like this:

#slot("myslotname" "<ul>" "<li>" "</li>" "</ul>" "query=$query&template=mytemplatename&max_results=100")

*I haven’t tested how many conditional statements can be added to a JSR-170 query, so you may run into trouble there.

This approach will work, but you should use the Map form rather than the String form as described in my previous post. Otherwise the spaces and punctuation in $query will need to be escaped first.

Dave

When I attempt to use the Map form I receive the error “Problem assembling output for item: 1-101-1944 with template: erauPgWWCenter exception: unexpected token: rx:sys_contentid see log for stack trace”. The console log doesn’t give any other clues to the problem, has anyone else used the IN operator within a slot?

Slot query:

SELECT rx:degree_name, rx:degree_type, rx:temp_web FROM rx:erauDegreeProgram WHERE rx:sys_contentid IN (:ids) Order by rx:degree_name

Slot code:


#set($slotparams.ids = '1946,1952')
#slot("erauDegreeList" "Degrees & Programs" "<li_>" "<li_>" "<ul_>" $slotparams)

When I modify the slot query to use a standard = operator and only a single slotparam I can’t get a result either. “Problem assembling output for item: 1-101-1944 with template: erauPgWWCenter exception: parameter ids not defined see log for stack trace”.

SELECT rx:degree_name, rx:degree_type, rx:temp_web FROM rx:erauDegreeProgram WHERE rx:sys_contentid = :ids Order by rx:degree_name

Lastly, I tried just using the IN operator without passing any parameters and could not receive a result. (same error as before)

SELECT rx:degree_name, rx:degree_type, rx:temp_web FROM rx:erauDegreeProgram WHERE rx:sys_contentid IN ('1947,1948') Order by rx:degree_name

I could get a result with a simple = operator and without any params.

SELECT rx:degree_name, rx:degree_type, rx:temp_web FROM rx:erauDegreeProgram WHERE rx:sys_contentid = '1947' Order by rx:degree_name

It turns out I was wrong, we don’t support “IN” in JCR Queries (and the JCR spec does not require this support, either). (Bad news for those of you who thought I knew everything, I suppose).

You have to use the “or” operator. You can build the query dynamically, either in JEXL or Velocity. (see my post in another recent thread about JEXL and Velocity Maps: http://forum.percussion.com/showpost.php?p=4690&postcount=4 ).

I used the $user.psoStringTools.getStringBuilder() method to build the query. I suppose that you could do this with ordinary concatenation, but this way looks better (and will run faster).

Assuming some basics are defined in the bindings, the Velocity code looks like this:

	
#set($qrybldr = $user.psoStringTools.getStringBuilder("select rx:sys_contentid, rx:sys_folderid from nt:base where "))
#set($idlist = $user.psoListTools.asList([930,931,933])))
#set($operator = "") 
#foreach($id in $idlist)
   #set($nop1 = $qrybldr.append($operator))
   #set($nop2 = $qrybldr.append("rx:sys_contentid = "))
   #set($nop3 = $qrybldr.append($id))
   #set($nop4 = $qrybldr.append(" "))
   #set($operator = " or ")
#end
#set($slotparams.query = $qrybldr.toString())
#set($slotparams.template = "rffSnTitleLink") 
#slot("rffAutoIndex" "" "" "" "" $slotparams)

I hope this helps, and I’m sorry if I steered you down the wrong path.

Dave

Thanks for your help so far, logically everything makes sense but I am still running into trouble with passing the map variable. Could you show what bind variables are needed (if any) to pass the map variable? It appears that my JSR-170 query does not recognize the map variable, “Problem assembling output for item: 1-101-1944 with template: erauPgWWCenter exception: unexpected token: :wclause see log for stack trace”


#set($myChildren = $sys.item.getProperty("degrees").getValues())
#set($qrybldr = $user.psoStringTools.getStringBuilder("where "))
#set($operator = "")

#foreach($myChild in $myChildren)
	#set($nop1 = $qrybldr.append($operator))
	#set($nop2 = $qrybldr.append("rx:sys_contentid = "))
        #set($nop3 = $qrybldr.append($myChild.String))
	#set($nop4 = $qrybldr.append(" "))
	#set($operator = " or ")
#end
			
#set($slotparams.wclause = $qrybldr.toString())
						
#slot("erauDegreeList" "" "" "" "" $slotparams)

JSR-170 Query:

SELECT rx:degree_name, rx:degree_type, rx:temp_web FROM rx:erauDegreeProgram :wclause Order by rx:degree_name

In the Bindings, define “$slotparams.template”. This will define create a Map for “$slotparams” with one entry (named “template”).

That should be sufficient for your example.

Dave

I think I have tried every variation of defining the variable.

Variables: $slotparams.wclause
Value (JEXL expression): “”
(also tried): ‘’
(also tried): $user.psoStringTools.getStringBuilder("where ")

When I looked in the System Velocity Macro definition for the slot I noticed the variable was called $params, not $slotparams so I tried changing all references to this but I am still getting the same error.

erauDegreeList slot parameters:

Type: Regular
Allowed Relationship Types: Active Assembly
Content finder: sys_AutoSlotContentFinder

Sorry, I didn’t look closely enough at your code.

You cannot define the whole “where clause” as a single substitution variable. You can only define the right hand side of an expression.

Go back and look at my example earlier in this thread. You will notice that I build the ENTIRE query in the query builder and pass it to $slotparams.query. This is the only way that it will work.

Dave

I really don’t think it is passing the map variable correctly, now I am getting “Problem assembling output for item: 1-101-1944 with template: erauPgWWCenter exception: expecting “select”, found ‘:myquery’ see log for stack trace”

Slot with binding set to $slotparams.myquery = “”:


#set($myChildren = $sys.item.getProperty("degrees").getValues())
#set($qrybldr = $user.psoStringTools.getStringBuilder("select rx:degree_name, rx:degree_type, rx:temp_web FROM rx:erauDegreeProgram where "))
#set($operator = "")
#foreach($myChild in $myChildren)
        #set($nop1 = $qrybldr.append($operator))
	#set($nop2 = $qrybldr.append("rx:sys_contentid = "))
        #set($nop3 = $qrybldr.append($myChild.String))
	#set($nop4 = $qrybldr.append(" "))
	#set($operator = " or ")
#end
			
#set($nop5 = $qrybldr.append(" order by rx:degree_name"))
#set($slotparams.myquery = $qrybldr.toString())
						
#slot("erauDegreeList" "" "" "" "" $slotparams)

erauDegreeList Slot:
query: :myquery

I believe that the problem is where you define $slotparams.myquery


#set($slotparams.myquery = $qrybldr.toString())

it should probably be:


#set($slotparams.query = $qrybldr.toString())

as i believe the query and template “values”/“names” are specific and the slot looks for those specifically.

Note: In order for me to get this to work, i had to specify blank values for $slotparams.query and $slotparams.template in the bindings tab of the template as for some reason velocity wasn’t / isn’t creating new objects (see http://forum.percussion.com/showthread.php?t=864). The blank values in the bindings initialize the map, creating the objects.

PS. Thanks Dave, this saves me from creating a large number of slots (ie, sort ascending vs descending)

Changing all references from “myquery” to “query” initially did not have an effect, but adding a $slotparams.template variable caused the error to change to “Problem assembling output for item: 1-101-1944 with template: erauPgWWCenter exception: query is a required argument see log for stack trace”.

Any thoughts?

Could you comment out the slot call and just print out the query?


 $qrybldr.toString()

See if it what you expect it to be…

Oh and in the actual slot, leave the query parameter blank…

Add $slotparams.template = “” and $slotparams.query ="" in the bindings tab for the required arguments problem.

i believe the query and template “values”/“names” are specific and the slot looks for those specifically.

This is correct, the parameters need to be named “query” and “template”, and as Jit suggests, you need Bindings for these.

It should not matter that you have a Query defined in the slot definition, as the query will be overriden by the one in the slot parameters.

I know that the Fast Forward autoindices select slots rather than building queries, but this approach (building the query on the fly) is probably simpler to understand, and it can potentially save you from creating lots of extra slots.

Dave

Ok I am getting some results now, I had to:
[ul]
[li]remove the $user.psoStringTools.getStringBuilder() method and just use a simple #set($qrybldr="") statement.
[/li][li]remove the .append() method for concatenation… is there another way to do this, I have tried using + signs but this isn’t working?
[/li][/ul]

(leaving/removing the :query map variable in the slot query produced the same results)

Why do you have a :query variable in your query? This is not necessary (and may even be related to your problem).

Go back and look at my example again. Do what I did, and it will work.

Dave

I guess the question is do you have the pso toolkit installed?

one way to do concat via velocity


#set($str = "first")
#set($str = "${str}last")

which should result in the string “firstlast”

I don’t have a :query variable in the query, just in the query placeholder of the slot (the map variable reference). I have tried passing a complete query with and without having this value present and the query passes the same way. (see attached photo of the erauDegreeList slot).

The only part I can’t get to work is the alternative string concatenation.

Thanks to Dave and jitendra for their help with this issue, I think everything is functioning correctly now, for those of you interested in the final version:

Page slot call:


#set($myChildren = $sys.item.getProperty("degrees").getValues())
#set($qrybldr = "")
#set($operator = "")
#foreach($myChild in $myChildren)
	#set($qrybldr = "${qrybldr} ${operator}")
	#set($qrybldr = "${qrybldr} rx:sys_contentid = ")
	#set($qrybldr = "${qrybldr} ${myChild.String}")
	#set($qrybldr = "${qrybldr} ")
	#set($operator = " or ")
#end
			
#set($qrybldr = "select rx:degree_name, rx:degree_type, rx:temp_web from rx:erauDegreeProgram where ${qrybldr}")
#set($qrybldr = "${qrybldr} order by rx:degree_name")
			
#set($slotparams.template = "erauSnDegreeList")
#set($slotparams.query = $qrybldr.toString())	

#slot("erauDegreeList" "" "" "" "" $slotparams)

erauDegreeList slot: (same as screen shot below)