You are here

Using dynamic queries in the Content Presenter

In the past I already talked a lot about the Content Presenter. It is very powerful to display content in all sorts of way. It can interact with Site Studio elements and it is easy to use by using its wizard.

One of the hidden gems of the content presenter is not the wizard but the plain old input parameters you would expect from a taskflow. The wizard everybody uses to configure the content presenter is just a facade to hide the complexity of those input parameters. In most cases this is sufficient but when you want to do more complex things, you would soon bump into issues by using the wizard.

Suppose that you want to display a list of news items from different categories and display a filter so the user can select their preferred category. There is no way of doing this by using the normal way. You would need to introduce a parameter in the query of the content presenter.

In this example I will explain how it is done. You can download the example application from here.

In order to make this work, you have to add a custom metadata field to UCM: xCategory. This field will be used in our query to filter on the category the user wants.

In the application you can find a news.jspx page which has 3 buttons. One that will display all the news items, one for the sport items and one for the normal news items:

  1. <af:commandButton text="All" id="cmdAll"
  2.           partialSubmit="true">
  3.     <af:setActionListener from="#{true}"
  4.             to="#{}"/>
  5.    <af:setActionListener from="#{true}"
  6.             to="#{}"/>
  7. </af:commandButton>
  8. <af:commandButton text="Sport" id="cmdSport"
  9.              partialSubmit="true">
  10.     <af:setActionListener from="#{true}"
  11.            to="#{}"/>
  12.    <af:setActionListener from="#{false}"
  13.            to="#{}"/>
  14. </af:commandButton>
  15. <af:commandButton text="News" id="cmdNews"
  16.           partialSubmit="true">
  17.    <af:setActionListener from="#{true}"
  18.             to="#{}"/>
  19.   <af:setActionListener from="#{false}"
  20.             to="#{}"/>
  21. </af:commandButton>

As you can see, these buttons don't have a direct actionListener but they use the setActionListener to invoke a setter from a property of my managed bean. By doing this, we know which items to display and we can build the query.

The query is a CMIS query. CMIS resembles to a normal SQL so the syntax should be familiar if you know SQL. I explained a little bit more about CMIS in another post

The dynamic query will also be build in the NewsBean:

  1. public String getNewsQuery(){
  2.   String query = "SELECT * FROM ora:t:IDC:GlobalProfile WHERE ora:p:xCategory in (\'dummy\' ";
  3.   if(news){
  4.      query += ", \'news\' ";
  5.  }
  6.  if(sport){
  7.    query += ", \'sport\'";
  8.  }
  9.  query += ")";
  10.    System.out.println("new query: " + query);
  11.    return query;
  12. }

As you can see, depending on the state of the news and sport boolean, we add them to the query.

The next thing is to provide this query to the content presenter.

When you take a look at the bindings of the news.jspx page, you will see that I use following values for the content presenter input parameters:

  • datasourceType: ${'dsTypeQueryExpression'} which tells the content presenter that the datasource is a CMIS query.
  • datasource: ${pageFlowScope.newsBean.newsQuery} which is a reference to the getNewsQuery method that will generate the query

I'll come back to the tempalteView in a minute...

Also notice that the Refresh attribute of the content presenter is set to ifNeeded. This is required for the taskflow to refresh when you press one of the 3 buttons.

When you run this without specifying a templateView, the content presenter will use the default one. When you are using a CMIS query in the datasource, the content presenter will know that he has to use a multiple items template because the query can return multiple items. This will result that you will get a list of links from all the items returning in the query:

Let's say that all of these items are wiki documents than you want to display the actual content instead of a link. This can be easily done by creating a content presenter template for multiple items that uses the default view for single items:

  1. <dt:contentListTemplateDef var="nodes">
  2.   <af:panelGroupLayout id="pnlContent" layout="vertical">
  3.      <af:iterator id="it" var="node" value="#{nodes}">
  4.         <dt:contentTemplate node="#{node}"
  5.              nodesHint="#{nodes}" id="content"/>
  6.         <af:spacer height="10px" id="spC"/>
  7.       </af:iterator>
  8.   </af:panelGroupLayout>
  9. </dt:contentListTemplateDef>

As you can see, nothing fancy. The most important part is that we include the single item template without specifying a templateView. This is because than it will use the default one being the one that displays the actual content.

When you run this, you will see that the actual content will be displayed:

You also have to make sure that the content presenter template is not hidden in the resource manager. Otherwise it will default back to the regular one with the links so if you have created the content presenter template and assigned it to the taskflow, make sure to check the content presenter templates in runtime to see if its stats is set to shown:

You can also do the exact same at runtime! So let's create a new page at runtime and add an empty content presenter on it:

Now instead of opening the wizard, open the properties by clicking on the wrench in the gray box:

In the data source dropdown you can select Query Expression which will tell the content presenter that the data source field will contain a CMIS query.

Now you can specify whatever query you want in the Data Source. Let's say we want to make a sports page and only display the sport items. We can use following value:

What makes this even more powerful is the fact that you can use Expression Language in the data source field so that query can also be dynamic.:

So as you can see, the content presenter is really powerful. Even more than you might think!



Hi Yannick,
great blog thansk for sharing,
i have one doubt about scope. why we need to register our bean in page flow scope i tried other scope like request and session but nothing is displayed.
so wanted to understand why pgae flow scope is requied.

Because in this example the CP instance has its own requests so the request from the page is a different one from the CP. That's why you cannot use the request scope.

I'm not sure why session scope does not work... It should work though.

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer