Query using selected option value from select

voltmer1's Avatar

voltmer1

18 Aug, 2016 05:02 PM

I would like to use the $_query object to search, filtering by a dynamic-metadata set that has the selected option in a select field. Currently it adds the options from the "news-and-events" metadata set if they are selected on the news-list-page (metadata), but the query doesn't display ONLY the metadata items that were selected in the output of the search it has ALL the pages with metadata from "news-and-events". What am I missing?

Example:

#set ( $news_list_page = $_XPathTool.selectSingleNode($contentRoot, "/system-index-block/calling-page/system-page") )
#set ( $news_list_page_metadata = $news_list_page.getChildren('dynamic-metadata') )
#set ( $query = $_.query() )
#set ( $query = $query.byMetadataSet("Main-Taxonomy-List") )
#set ( $query = $query.byContentType("news-detail") )
#set ( $query = $query.includePages(true) )
#set ( $query = $query.includeFiles(false) )
#set ( $query = $query.includeBlocks(false) )
#set ( $query = $query.includeFolders(false) )
#set ( $query = $query.includeSymlinks(false) )
#set ( $query = $query.sortBy("created") )
#set ( $query = $query.sortDirection("desc") )
#set ( $query = $query.maxResults(12) )
#set ( $news = $query.execute() )
<div class="region news-list-region">
    <div class="region-holder">
        <!-- Filter form -->
        <form class="filter-form">
            <div class="filter-form-holder">
                <div class="filter-form-item">
                    <span class="filter-form-label">Search by:</span>
                </div>
                <div class="filter-form-item">
                    <div class="filter-form-select-wrapper">
                        <select class="filter-form-select" name="" id="select-1">
                            <option value="Recent news">Recent news</option>
                            <option value="2015-2016">2015-16</option>
                            <option value="2014-2015">2014-15</option>
                            <option value="2013-2014">2013-14</option>
                        </select>
                    </div>
                </div>
                <div class="filter-form-item">
                    <div class="filter-form-select-wrapper">
                        <label for="topics" class="hide-for-screen-reader">Please choose topic</label>
                        <select class="filter-form-select" name="topics" id="topics">
                            <option value="All Topics">All Topics</option>
                            #foreach( $news_items in $news_list_page_metadata )
                                #if( 'news-and-events' == $news_items.getChild('name').value )
                                    #set( $taxonomy_list = $news_items.getChildren('value') )
                                    #foreach( $taxonomy_item in $taxonomy_list )
                                        <option value="${_EscapeTool.xml($taxonomy_item.value)}">${_EscapeTool.xml($taxonomy_item.value)}</option>
                                    #end
                                #end
                            #end
                        </select>
                    </div>
                </div>
                <div class="filter-form-item">
                    <button type="submit" class="filter-form-btn btn btn-primary">Search</button>
                </div>
            </div>
        </form>
  1. 1 Posted by Wing Ming Chan on 18 Aug, 2016 06:30 PM

    Wing Ming Chan's Avatar

    Hi Steve,

    I believe that you need to use hasMetadata() to filter out unwanted pages. hasMetadata() takes two String parameters, the first one being the identifier of the field (could be a dynamic field), the second being a value you want the field to have.

    Wing

  2. 2 Posted by voltmer1 on 19 Aug, 2016 01:16 PM

    voltmer1's Avatar

    Thanks Wing. I don't know how I could set the second argument of the hasMetadata() to the selected option from the select prior to the actual query. There is always going to be a scope issue.

    #set ( $query = $_.query() )
    #set ( $query = $query.byMetadataSet("Main-Taxonomy-List") )
    #set ( $query = $query.byContentType("news-detail") )
    #set ( $query = $query.includePages(true) )
    #set ( $query = $query.includeFiles(false) )
    #set ( $query = $query.includeBlocks(false) )
    #set ( $query = $query.includeFolders(false) )
    #set ( $query = $query.includeSymlinks(false) )
    #set ( $query = $query.sortBy("created") )
    #set ( $query = $query.sortDirection("desc") )
    #set ( $query = $query.maxResults(12) )
    #set ( $news = $query.execute() )
    <div class="region news-list-region">
        <div class="region-holder">
            <!-- Filter form -->
            <form class="filter-form">
                <div class="filter-form-holder">
                    <div class="filter-form-item">
                        <span class="filter-form-label">Search by:</span>
                    </div>
                    <div class="filter-form-item">
                        <div class="filter-form-select-wrapper">
                            <select class="filter-form-select" name="" id="select-1">
                                <option value="Recent news">Recent news</option>
                                <option value="2015-2016">2015-16</option>
                                <option value="2014-2015">2014-15</option>
                                <option value="2013-2014">2013-14</option>
                            </select>
                        </div>
                    </div>
                    <div class="filter-form-item">
                        <div class="filter-form-select-wrapper">
                            <label for="topics" class="hide-for-screen-reader">Please choose topic</label>
                            <select class="filter-form-select" name="topics" id="topics">
                                <option value="All Topics">All Topics</option>
                                #foreach( $news_items in $news_list_page_metadata )
                                    #if( 'news-and-events' == $news_items.getChild('name').value )
                                        #set( $taxonomy_list = $news_items.getChildren('value') )
                                        #foreach( $taxonomy_item in $taxonomy_list )
                                            <option value="${_EscapeTool.xml($taxonomy_item.value)}">${_EscapeTool.xml($taxonomy_item.value)}</option>
                                        #end
                                    #end
                                #end
                            </select>
                        </div>
                    </div>
                    <div class="filter-form-item">
                        <button type="submit" class="filter-form-btn btn btn-primary">Search</button>
                    </div>
                </div>
            </form>
            <!-- News list -->
            <ul class="news-list">
                #foreach( $single_news in $news.hasMetadata("news-and-events", "${_EscapeTool.xml($taxonomy_item.value)}") ))
                    #set( $headline = $single_news.getStructuredDataNode('headline').textValue )
                    #set( $byline = $single_news.getStructuredDataNode('byline').textValue )
                    #set( $calendar = $single_news.getStructuredDataNode('calendar').textValue )
                    #set( $thumbnail_image = $single_news.getStructuredDataNode('thumbnail-image'))
                    #set( $news_link = $single_news.link )
                    #set( $metadata = $single_news.metadata )
                    #set( $dynamic_fields = $metadata.dynamicFields )
                    <li class="news-list-item">
                        <article class="news-block is-blue">
                            <div class="news-block-holder">
                                #set( $stop_loop = false )
                                #if( $dynamic_fields.size() > 0 )
                                    #foreach( $dynamic_field in $dynamic_fields )
                                        #set( $chanwTextSize = $dynamic_field.Values.size() )
                                        #if( $chanwTextSize > 0 )
                                            #foreach( $value in $dynamic_field.Values )
                                                #if( $value != "" )
                                                    <strong class="news-block-taxonomy">$value</strong>
                                                    #set( $stop_loop = true )
                                                    #break
                                                #end
                                            #end
                                        #end
                                        #if( $stop_loop )
                                            #break
                                        #end
                                    #end
                                #end
                                <div class="news-block-img">
                                    #if (!$_PropertyTool.isNull($thumbnail_image.asset))
                                            <img src="${thumbnail_image.asset.link}" alt="${thumbnail_image.asset.metadata.title}"/>
                                        #else
                                        #set( $thumbnail_image = '/assets/images/img-news-list-01.jpg' )
                                           <img src="$thumbnail_image" alt="News Image" /> 
                                    #end
                                 </div>
                                <div class="news-block-body">
                                    <a href="${news_link}" class="news-block-link">$headline</a>
                                </div>
                            </div>
                        </article>
                    </li>
                #end
    
  3. 3 Posted by Wing Ming Chan on 19 Aug, 2016 02:17 PM

    Wing Ming Chan's Avatar

    Steve,

    hasMetadata is a method of the $query object and has to be called right at the beginning. This means that you will only get pages whose metadata field of that id has that value. This is a very severe restriction imposed on the $query object by Cascade, and I don't think you can retrieve pages that do not have that field or pages having that field but not that value.

    See http://www.hannonhill.com/kb/Script-Formats/ for more discussion and http://www.upstate.edu/cascade-admin/formats/velocity/api-documenta... for the API documentation.

    Wing

  4. 4 Posted by voltmer1 on 19 Aug, 2016 02:26 PM

    voltmer1's Avatar

    Rats! Could I instead filter the results after the query is executed at this point? (where $news is the query execute() )

     #foreach( $single_news in $news )
                    #set( $headline = $single_news.getStructuredDataNode('headline').textValue )
                    #set( $byline = $single_news.getStructuredDataNode('byline').textValue )
                    #set( $calendar = $single_news.getStructuredDataNode('calendar').textValue )
                    #set( $thumbnail_image = $single_news.getStructuredDataNode('thumbnail-image'))
                    #set( $news_link = $single_news.link )
                    #set( $metadata = $single_news.metadata )
                    #set( $dynamic_fields = $metadata.dynamicFields )
                    <li class="news-list-item">
                        <article class="news-block is-blue">
                            <div class="news-block-holder">
                                #set( $stop_loop = false )
                                #if( $dynamic_fields.size() > 0 )
                                    #foreach( $dynamic_field in $dynamic_fields )
                                        #set( $chanwTextSize = $dynamic_field.Values.size() )
                                        #if( $chanwTextSize > 0 )
                                            #foreach( $value in $dynamic_field.Values )
                                                #if( $value != "" )
                                                    <strong class="news-block-taxonomy">$value</strong>
                                                    #set( $stop_loop = true )
                                                    #break
                                                #end
                                            #end
                                        #end
                                        #if( $stop_loop )
                                            #break
                                        #end
                                    #end
                                #end
    
  5. 5 Posted by Wing Ming Chan on 19 Aug, 2016 02:30 PM

    Wing Ming Chan's Avatar

    Sure. But then you have to work with the MetadataAPIAdapter objects and DynamicMetadataFieldImpl objects. See my API documentation for available methods in these two classes.

    Wing

  6. 6 Posted by voltmer1 on 19 Aug, 2016 02:33 PM

    voltmer1's Avatar

    Thanks Wing! Every time I try to access your documentation it says I need a login to access the page. Do you have a new URL?

  7. 7 Posted by Wing Ming Chan on 19 Aug, 2016 02:36 PM

    Wing Ming Chan's Avatar

    Make sure the domain in the URL starts with www.upstate.edu. Sometimes I inadvertently copied a URL from our development server, starting with web.upstate.edu.

    http://www.upstate.edu/cascade-admin/formats/velocity/api-documenta...

    Wing

  8. 8 Posted by voltmer1 on 19 Aug, 2016 03:18 PM

    voltmer1's Avatar

    Okay, how do I instantiate either of the API adapter objects in Velocity?
    (didn't like this)

    #set ( $metaDataField = DynamicMetadataFieldImpl() )
    
    Then I tried to use a method:
    $metaDataField.getValue('news-and-events')
    
  9. 9 Posted by Wing Ming Chan on 19 Aug, 2016 04:06 PM

    Wing Ming Chan's Avatar

    Cascade API objects are created by Cascade and supplied to you. You never instantiate them. When you start with $currentPage, for example, call getMetadata method through the object, what you get is a MetadataAPIAdapter object. And when you call getDynamicField through the MetadataAPIAdapter object, you get a DynamicMetadataFieldImpl object. So you have to go through these objects and call the right methods to get to the values. My API documentation becomes handy when you need to do that.

    Wing

  10. 10 Posted by voltmer1 on 19 Aug, 2016 04:08 PM

    voltmer1's Avatar

    Sounds like reflection?
    Then why did I have to create an instance of the query object using:

    $query = $_.query()
    
  11. 11 Posted by Wing Ming Chan on 19 Aug, 2016 04:19 PM

    Wing Ming Chan's Avatar

    That's how Hannon Hill decided to expose the object. query is probably a factory method returning a singleton.

    Talking about reflection, I introduced it into the discussion of Velocity last year and developed an entire library of Java objects. To find out more about this topic, see

    https://github.com/wingmingchan/velocity/blob/master/library/chanw_...
    https://github.com/wingmingchan/velocity/blob/master/library/chanw_...

    Wing

  12. 12 Posted by Bradley Wagner on 19 Aug, 2016 04:20 PM

    Bradley Wagner's Avatar

    The query object provides method chaining for things like: hasMetadata, byContentType where each method returns a version of the query object with additional criteria or sorting applied.

  13. 13 Posted by Wing Ming Chan on 19 Aug, 2016 04:24 PM

    Wing Ming Chan's Avatar

    Bradley,

    Thanks for the info. The chained methods can alter the state of the query object, so that it can still be a singleton. Right?

    Wing

  14. 14 Posted by Bradley Wagner on 19 Aug, 2016 04:26 PM

    Bradley Wagner's Avatar

    It's not specifically implemented as a singleton, no. I would think about it more as factory method where the resultant object supports method chaining.

  15. 15 Posted by Wing Ming Chan on 19 Aug, 2016 04:32 PM

    Wing Ming Chan's Avatar

    That's precisely what I am trying to get at. Does it mean that if I call query() twice, I get two separate instances? Can I retrieve two separate sets of assets independently?

    Wing

  16. 16 Posted by Bradley Wagner on 19 Aug, 2016 04:49 PM

    Bradley Wagner's Avatar

    Correct, multiple query() calls will create separate query objects.

  17. 17 Posted by voltmer1 on 19 Aug, 2016 04:58 PM

    voltmer1's Avatar

    Bradley, Is there anyway to tie the query object hasMetadata() method to a value of a select option?

  18. 18 Posted by Bradley Wagner on 19 Aug, 2016 05:02 PM

    Bradley Wagner's Avatar

    Not sure I'm following. Is hasMetadata not working for you when querying for a specific value?

  19. 19 Posted by voltmer1 on 19 Aug, 2016 06:36 PM

    voltmer1's Avatar

    I don't know how to get the value of the select into the hasMetada property since it has to be set at the beginning and the select with the dropdown creating the option value (that needs to be in the hasMetadata method) in a separate prior foreach loop as the query is called, so the variable is out of scope.

  20. 20 Posted by Bradley Wagner on 19 Aug, 2016 06:46 PM

    Bradley Wagner's Avatar

    I'm not quite following what this code is trying to do but one thing I can say is that calling hasMetadata() after the query has been executed will not return results, merely a modified version of the query object. it needs to be set before executing the query and getting the results.

    When you're calling:

                #foreach( $single_news in $news.hasMetadata("news-and-events", "${_EscapeTool.xml($taxonomy_item.value)}") ))
    
    where are you trying to pull $taxonomy_item from?

    If you're able to get that variable to update, thix might be as simple as calling:

    $newsQuery.hasMetadata(("news-and-events", "${_EscapeTool.xml($taxonomy_item.value)}") )
    #foreach ($single_news in $newsQuery.execute())
    ...
    

    Let me know if that makes sense.

  21. 21 Posted by voltmer1 on 19 Aug, 2016 07:10 PM

    voltmer1's Avatar

    Yes, that makes perfect sense, but unfortunately the variable $taxonomy_item is created within a separate foreach loop prior. I've initialized the $taxonomy_item globally, but it doesn't seem to update:

    #set ( $taxonomy_item = "" )
                            <label for="topics" class="hide-for-screen-reader">Please choose topic</label>
                            <select class="filter-form-select" name="topics" id="topics">
                                <option value="All Topics">All Topics</option>
                                #foreach( $news_items in $news_list_page_metadata )
                                    #if( 'news-and-events' == $news_items.getChild('name').value )
                                        #set( $taxonomy_list = $news_items.getChildren('value') )
                                        #foreach( $taxonomy_item in $taxonomy_list )
                                            <option value="${_EscapeTool.xml($taxonomy_item.value)}">${_EscapeTool.xml($taxonomy_item.value)}</option>
                                       #end
                                    #end
                                #end
                            </select>
                        </div>
                    </div>
                    <div class="filter-form-item">
                        <button type="submit" class="filter-form-btn btn btn-primary">Search</button>
                    </div>
                </div>
            </form>
            <ul class="news-list">
               #set( $newsQuery = $query.hasMetadata("news-and-events", "${_EscapeTool.xml($taxonomy_item.value)}" ))
                #foreach ($single_news in $newsQuery.execute())
                    #set( $metaValue = $metadataField.getValue('news-and-events') )
                    #set( $headline = $single_news.getStructuredDataNode('headline').textValue )
                    #set( $byline = $single_news.getStructuredDataNode('byline').textValue )
                    #set( $calendar = $single_news.getStructuredDataNode('calendar').textValue )
                    #set( $thumbnail_image = $single_news.getStructuredDataNode('thumbnail-image'))
                    #set( $news_link = $single_news.link )
                    #set( $metadata = $single_news.metadata )
                    #set( $dynamic_fields = $metadata.dynamicFields )
    
  22. 22 Posted by voltmer1 on 23 Aug, 2016 03:30 PM

    voltmer1's Avatar

    Any ideas as to why my variable $taxonomy_item is not updating?

  23. 23 Posted by Penny on 25 Aug, 2016 01:46 PM

    Penny's Avatar

    Hi Voltmer,

    I was looking at your code and it appears to me that $taxonomy_item will only live in your foreach. The moment you exit that, the variable is no longer available.

    I'm a little confused on what you are attempting in velocity. Are you trying to have Velocity deliver results of a filter/search provided to web visitors? If so, that isn't possible with this approach. Velocity will essentially provide static HTML on page render.

    If I am misunderstanding what you are doing above and you are wanting to create say static lists provided selections of filters on the Cascade CMS page, I have done something similar for Carnegie Mellon using a hash map. The following is a snippet of my code from that project.

    #set ( $categories = $_XPathTool.selectNodes($newsSettings, "categories/value") )
                #set($allArticles = {})
                #foreach($category in $categories)
                    ##set( $imagePath = $_EscapeTool.xml($articleObj.getStructuredDataNode("syndication").getChild("image").asset.link) )
                    #set ( $articles = $_.query().byMetadataSet("News").siteName($currentPageSiteName).hasMetadata("categories", "${category.value}").execute() )
                    #foreach($article in $articles)
                        #set ( $articleData = {
                            "id": $article.identifier,
                            "title": $_EscapeTool.xml($article.metadata.title),
                            "link": $_EscapeTool.xml($article.link),
                            "path": $_EscapeTool.xml($article.path)
                        })
                        #set ( $_void = $allArticles.put($articleData.get("link"), $articleData))
                    #end
                #end
    
  24. 24 Posted by voltmer1 on 25 Aug, 2016 01:55 PM

    voltmer1's Avatar

    Thanks Penny.
    I am trying to filter news articles based on the option selected from a couple of dropdown select fields, which contain metadata (taxonomy) values to be matched with the news articles with matching metadata, then displaying them on the page.

  25. 25 Posted by Penny on 25 Aug, 2016 02:23 PM

    Penny's Avatar

    Sorry to beat a dead horse but I still need a tiny bit of clarification, who will be making the "selection" for filtering?

    The web visitor or the person creating the web page in the CMS?

    Or is it a combo? I create a web page and say these are the categories that my web visitors can filter by?

    Thanks!

  26. 26 Posted by voltmer1 on 25 Aug, 2016 02:56 PM

    voltmer1's Avatar

    Sorry, should have been clearer. The web user will make the selections from the webpage to view the results.

  27. 27 Posted by Penny on 25 Aug, 2016 03:29 PM

    Penny's Avatar

    That was what I thought. So what you are trying to do is partly not how the system works.

    You can create the filter options using Velocity but for the display of results and on-demand filtering, you can not use Velocity. Once the page is rendered, Velocity no longer exists.

    What I would recommend doing is using Velocity to create a JSON or XML file of results that can be queried using JQuery or some server side language like php or .net.

    Velocity could be used if you were creating a page with all of the data preloaded and then using the select to filter down based on a provided class. Below is an example. But you will notice that the data is on the page and it is really Javascript that does the filtering.
    http://www.northeastern.edu/law/news/multimedia/index.html

  28. 28 Posted by voltmer1 on 25 Aug, 2016 03:38 PM

    voltmer1's Avatar

    Your example is exactly what I would like to achieve. The default option on the dropdown on page load is "all categories", then the user would filter it down, by selecting from the dropdowns.
    So, you are just using Velocity $_.query to pull in all the data into the page on load, then filtering? Do you have an example of your script?

  29. 29 Posted by Penny on 25 Aug, 2016 05:40 PM

    Penny's Avatar

    So all you really need to do with Velocity is pull in all of the news article data. You would then output each item as an li element or div or whatever your Jquery/server side script will look for. On the class, you can then output information for filter classes.

    Your Velocity therefore doesn't need to look for hasMetadata. It just needs to query by Content Type. Get ALL news articles. Then output all of the necessary data for each article. So it sounds like you just need one query in Velocity.

    You then need to have a Jquery/server side script to do the filtering. From that example, this is the script they have: http://www.northeastern.edu/law/files/scripts/filter-media.js

  30. 30 Posted by voltmer1 on 29 Aug, 2016 07:31 PM

    voltmer1's Avatar

    Thanks Penny! I've got a problem though. I have many selections that can be made in each news article's dynamic data, so I am iterating through them to get all the different selections, but since this is within a separate foreach I can't pass the metadata back out to the inclosing list item to have the filter work correctly (hide/show based on the class named with the pulled metadata).

            <ul class="news-list news-articles mediaListing">
                #foreach ($single_news in $news)
                    #set( $metaValue = $metadataField.getValue('news-and-events') )
                    #set( $headline = $single_news.getStructuredDataNode('headline').textValue )
                    #set( $byline = $single_news.getStructuredDataNode('byline').textValue )
                    #set( $calendar = $single_news.getStructuredDataNode('calendar').textValue )
                    #set( $thumbnail_image = $single_news.getStructuredDataNode('thumbnail-image') )
                    #set( $news_link = $single_news.link )
                    #set( $newsYear = $single_news.getParent().name)
                    #set( $metadata = $single_news.metadata )
                    #set( $dynamic_fields = $metadata.dynamicFields )
                    <li class="news-list-item mediaListingEntry $newsYear $metadata.dynamicFields.value">
                        <article class="news-block is-blue">
                            <div class="news-block-holder">
                                #set( $stop_loop = false )
                                  #if( $dynamic_fields.size() > 0 )
                                    #foreach( $dynamic_field in $dynamic_fields )
                                        #set( $chanwTextSize = $dynamic_field.Values.size() )
                                    #if( $chanwTextSize > 0 )
                                            #foreach( $value in $dynamic_field.Values )
                                                #if( $value != "" )
                                                    <strong class="news-block-taxonomy $value">$value</strong>
                                                    #set( $stop_loop = true )
                                                    #break
                                                #end
                                            #end
                                        #end
                                        #if( $stop_loop )
                                            #break
                                        #end
                                    #end
                                #end
                                <div class="news-block-img">
                                    #if (!$_PropertyTool.isNull($thumbnail_image.asset))
                                            <img src="${thumbnail_image.asset.link}" alt="${thumbnail_image.asset.metadata.title}"/>
                                        #else
                                        #set( $thumbnail_image = '/assets/images/img-news-list-01.jpg' )
                                           <img src="$thumbnail_image" alt="News Image" /> 
                                    #end
                                 </div>
                                <div class="news-block-body">
                                    <a href="${news_link}" class="news-block-link">$headline</a>
                                </div>
                            </div>
                        </article>
                    </li>
                #end
            </ul>
    
    I am also having an issue getting this javascript to load using require.js

Comments are closed, but you can start a new discussion.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac