views:

52

answers:

3

I'm using this code to display a list of platforms. If a platformID was specified upon entering the page, I would like to create a list of genres underneath the specified platform.

  1. browse.cfm was accessed via a link that specified a platformID of 1
  2. browse.cfm will list all available platforms
  3. browse.cfm will now list all available genres under platformID of 1.

    <ul>
        <li>Browse</li>
        <cfoutput query="qGetPlatforms">
        <li>
            <a href="browse.cfm?platformID=#URLEncodedFormat(Trim(qGetPlatforms.platformID))#">#qGetPlatforms.pName#</a>
            <cfif URL.platformID EQ qGetPlatforms.platformID>
            <ul>
                <cfoutput query="qGetGenres">
                <li><a href="browse.cfm?genreID=#URLEncodedFormat(Trim(qGetGenres.genreID))#">#qGetGenres.gName#</a></li>
                </cfoutput>
            </ul>
            </cfif>
        </li>
        </cfoutput>
    </ul>
    

By using this approach, however, I'm getting an invalid nesting configuration. How do I fix this? Or is there another approach to achieve the same idea?

Thanks

MY queries:

<!---Get platforms--->
<cffunction
    name="fGetPlatforms"
    access="public"
    returntype="query"
    output="false"
    hint="I get all the platforms">
    <!---Local var--->
    <cfset qGetPlatforms = "">
    <!---Database query--->
    <cfquery name="qGetPlatforms" datasource="#REQUEST.datasource#">
    SELECT 
        platforms.platformID,
        platforms.platformName AS pName
    FROM
        platforms
    </cfquery>
    <cfreturn qGetPlatforms>
</cffunction>    

<!---Get genres--->
<cffunction
    name="fGetGenres"
    access="public"
    returntype="query"
    output="false"
    hint="I get all the genres">
    <!---Local var--->
    <cfset qGetGenres = "">
    <!---Database query--->
    <cfquery name="qGetGenres" datasource="#REQUEST.datasource#">
    SELECT 
        genres.genreID,
        genres.genreName AS gName
    FROM
        genres
    </cfquery>
    <cfreturn qGetGenres>
</cffunction>
+2  A: 

You can use <cfloop query="qGetGenres"></cfloop>, they can be nested.

IMO, using cfoutput for looping over the queries is old style and should be avoided. Use cfoutput for output, cfloop for looping and you'll have more readable code.

Sergii
Sergii, thanks for the tip. It works. But if you consider using cfoutput query to be outdated, is there a way to execute the above code without it? Or would it be ok in this situation to continue using cfoutput query?
Mel
Looping with `cfoutput` is required for grouping queries, but not for simple nesting. You can simply wrap `cfoutput` around your whole piece of HTML and the variables inside the `cfloop` will be rendered as expected.
Peter Boughton
the only issue with using cfloop is that it doesn't support the group attribute, but in most cases they are interchangeable
rip747
A: 

Can you post your 2 queries?

Tim
Tim, I just did!
Mel
+1  A: 

more food for thought is to use an inner join between the two tables, combine and retrieve everything in one query and then use cfoutput's group attribute to display the results:

<cfset URL.platformID = int(val(URL.platformID))>

<cfquery name="getPlatformsAndGenres" datasource="#REQUEST.datasource#">
SELECT
    p.platformID AS platformID
    ,p.platformName AS pName
    ,g.genreID AS genreID
    ,g.genreName AS gName
FROM
    platforms p
    INNER JOIN genres g
        ON p.platformID = g.platformID
WHERE
    p.platformID = <cfqueryparam cfsqltype="cf_sql_integer" value="#URL.platformID#">
ORDER BY
    pName
    ,genreName
</cfquery>

Once you have everything in one query, you can use <cfoutput query="getPlatformsAndGenres" group="pName">
to lessen your code:

<ul>
    <li>Browse</li>
    <cfoutput query="getPlatformsAndGenres" group="pName">
    <li>
        <a href="browse.cfm?platformID=#URLEncodedFormat(Trim(platformID))#">#pName#</a>
        <ul>
            <cfoutput>
            <li><a href="browse.cfm?genreID=#URLEncodedFormat(Trim(genreID))#">#gName#</a></li>
            </cfoutput>
        </ul>
        </cfif>
    </li>
    </cfoutput>
</ul>
rip747
Interesting solution. Thanks for sharing it. I guess I will look at my code and decide what is the solution... the idea of having a single query is appealing, though...
Mel
rip747, could you please explain why you wrote the following: <cfset URL.platformID = val(URL.platformID)>? Is it to prevent someone from entering something other than a number and crashing the code? And how would it work in a setting where I'm using cffunction... would I just add the line to my function below the cfargument tag that would be the platformID... at the momement I'm activating the WHERE clause only after using IsNumeric()
Mel
@mel: you are correct in both parts of your question. using val() is a very basic form of this (you could go a lot further). for instance val() will return floats, however in this case you want only an integer. for that you would use a combination of val() and int() to make sure that floats don't get by. i'll update my answer with this.
rip747