919 - 926 - 9847

So, I hacked my FarCry core tonight... but the result is pretty cool.

I have a client request to add filtering by category in the Open Library picker. In fact, really thinking on this, it seems odd that this ability isn't there anyway. What the heck good is categorizing all of your images if you can't find an easy way to filter them out?

So, it's with that in mind, I set out trying to get this functionality in place. I had to hack up /farcry/core/webtop/facade/library.cfm to do this, so it's an at your own risk operation. The problem I run into is that the formtools tag and the wizard tag call this library picker. Unless you extend every object that uses these tags (because you can't extend a tag that I see), I'm kind of stuck editing this one file. Mayhap Mat Bryant is following along and can offer up some advice?

At any rate, here is what I did to add a drop down category list to filter results by.

First, you need to add a new cfparam at the top of the file. This ensures that our field is defined, in case it's blank.


<cfparam name="session.stLibraryFilter['#request.ftJoin#'].category" default="" />

Next, add the following into the ft:processForm action="search". This catches our new form field.


<cfset session.stLibraryFilter['#request.ftJoin#'].category = lCase(form.filtercat)>

Add this to processForm action="Refresh". This clears out the category value when the Refresh button is clicked.


<cfset session.stLibraryFilter[request.ftJoin].category = "" />

Next, add this block below the cfif block that catches the presence of the .criteria value. This will create a query to return our filtered data.


<cfif len(session.stLibraryFilter[request.ftJoin].category)>
    <cfset oCat = createObject("component", "farcry.core.packages.types.category") />
    <cfset qSearchResults2 = oCat.getDataQuery(lCategoryIDs="#session.stLibraryFilter[request.ftJoin].category#"
        ,typename="#request.ftJoin#"
        ,maxRows="100"
        ,bMatchAll="0"
        ,sqlOrderBy="label ASC",
        lFields="label"
        ) /
>

    
    <cfset filterCriteria = session.stLibraryFilter[request.ftJoin].Criteria />
    <cfif NOT qSearchResults2.RecordCount>
        <cfoutput><h3>No Results matched search. All records have been returned</h3></cfoutput>
        <cfset session.stLibraryFilter['#request.ftJoin#'].qResults = queryNew("objectid,label") />
        
    <cfelse>
        <cfif qSearchResults2.RecordCount GT 100>
            <cfoutput><h3>#qSearchResults2.RecordCount# results matched search. Results have been limited to 100.</h3></cfoutput>
            
            <cfquery dbtype="query" name="qSearchResults_inside" maxrows="100">
            SELECT objectid as key, label FROM qSearchResults2
            <cfif len(filterCriteria)>
                WHERE label like '%#filterCriteria#%'
            </cfif>
            </cfquery>
        <cfelse>
            <cfquery dbtype="query" name="qSearchResults_inside" >
            SELECT objectid as [key], label FROM qSearchResults2
            <cfif len(filterCriteria)>
                WHERE LOWER(label) like '%#filterCriteria#%'
            </cfif>
            </cfquery>    
        </cfif>
        <cfset session.stLibraryFilter['#request.ftJoin#'].qResults = qSearchResults_inside />
    </cfif>
            
    
</cfif>

Last, we need to modify the form. Add this select into the last cell (or create one). This populates the select list from all of the categories in the system.


<cfset oCategory = createObject("component",'farcry.core.packages.farcry.category')>
        <cfset rootID = application.catid['root'] >
        <cfset qCategory = oCategory.getAllCategories() />
        
        <cfoutput><select id="filtercat" name="filtercat">
                <option></option>
        </cfoutput>
        <cfloop query=qCategory>
            <cfoutput><option value="#objectid#" <cfif objectid EQ session.stLibraryFilter[request.ftJoin].category>selected</cfif>>#objectname#</option></cfoutput>
        </cfloop>
        <cfoutput></select></cfoutput>

And, it's done. The only issue I'm seeing is that the category seems to stick around, where the text filter does not. I'm still working on why that would be, and I cannot find the variables used for the storage of those values anywhere else. However, it's a small price to pay.

I need to clarify where that first param needs to be. There's a line that set's request.ftJoin = url.ftJoin. The param must be below this cfset! I'm not sure if this is new, but this tripped me up today.

To answer Jeff's question, see the screenshots attached.

Unfiltered content:

Filter by keyword:

Filter by category:

Filter by category and keyword:

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Jeff Coughlin's Gravatar Can you post a screenshot of this in action?
# Posted By Jeff Coughlin | 1/27/09 2:18 AM
Matthew Williams's Gravatar Sure. The screenshots are now attached. We have unfiltered content, filtered by keyword, filtered by category, and filtered by both.
# Posted By Matthew Williams | 1/27/09 8:34 AM
Jeff Coughlin's Gravatar Ahh. I thought you had actually displayed the category tree (granted, I didn't actually look at your code :) ).
# Posted By Jeff Coughlin | 1/27/09 9:27 AM
Matthew Williams's Gravatar Well, there's no reason it cannot be done that way. In fact, if you set the category as a filter when looking at the main content screen, it does a tree view. In this particular instance, they have too many categories. It's going to push the selection fields halfway down the page. Unless maybe there's code in place to not open the various levels of categories by default?
# Posted By Matthew Williams | 1/27/09 12:02 PM
Matthew Bryant's Gravatar Love your work Matthew,

I will take a closer look and add this functionality to an upcoming release of core. Nice addition, keep em coming.....

Mat Bryant
# Posted By Matthew Bryant | 1/27/09 12:56 PM
Jeff Coughlin's Gravatar No, you're right. Showing only categories actually used for the objects is the better option.

So far, I like it.

Suggestion: Maybe show each category like a breadcrumb trail in the dropdown?

ie:
series>>product>>blue
.../series/product/blue

If more than 3 items, prefix with an ellipses (in order to keep real estate manageable). Not sure if the "3" would be a setting in FC config.

Thoughts?
# Posted By Jeff Coughlin | 1/28/09 11:51 AM
Matthew Williams's Gravatar That would make it more readable, for sure. Right now, it's just pulling all the categories, and doesn't really pay any mind to how they're structured. It looks like this would need to be built into category.cfc... perhaps copy the behavior of getTreeData to return an array/struct/query that has strings formatted such that the cats are displayed as:

cat1 >> something1
cat1 >> somethign2
cat1 >> something2 >> someotherthing
cat2 >> thisthing1

That would seem the best way to handle this visually. I'm going to be tied up through the end of the week, and likely the weekend, on surgeries and pregnancy issues so I'm not sure I'd make much headway on this. Sorry, I'd like to do more with it, but real life is just getting in the way of productivity this week ;). But I would think the formatting would best be done in the category.cfc. We can then just loop over the list/struct/query/array/whatever in the library.cfm select picker from the result of the function return.
# Posted By Matthew Williams | 1/28/09 12:18 PM