7 Replies Latest reply on Aug 29, 2007 7:05 PM by cf_dev2

    dynamic return from a function based on an argument

    sjlsam2
      I have a function that I am using to output a nested list of child/parent relationships

      the function works wonderfully except that i want to be able to change the way the list is displayed depending on an argument being passed

      i want the list to be displayed twice on the same page, one with output in a table, and one with output in a drop down box
      i thought the easiest way would be to create an argument that can be used in IF statements

      look at my code below

      quote:

      <!--- establish default values --->
      <cfparam name="output" default="">
      <cfparam name="catNameOutput" default="">
      <cfparam name="indent" default="">

      <cffunction name="GenerateCategories" access="public" returntype="string">
      <!--- this holds the outermost parent value being passed to the function --->
      <cfargument name="GenCatParent" type="uuid" required="yes" default=0 >

      <!--- this holds the nested level we are on --->
      <cfargument name="level" type="numeric" required="yes" default=0 >

      <!--- this holds the output_type we need for display purposes --->
      <cfargument name="output_type" type="numeric" required="yes" default=0 >

      <!--- grab the children of the received category --->
      <cfquery name="rsCategoryChildren" datasource="webdsn">
      SELECT * FROM dbo.BlogCategories
      WHERE catParent = '#GenCatParent#'
      ORDER BY catName ASC
      </cfquery>
      <cfloop query="rsCategoryChildren">
      <!--- keep track of the indentation needed depending on which level we are at --->
      <cfloop from="0" to="#arguments.level#" index="i">
      <cfset indent = indent & "  ">
      </cfloop>

      <!--- if the nest is being used in the dropdown on the category manage page, we need to use option tags --->
      <cfif arguments.output_type EQ 1>
      <cfset catNameOutput = "<option value='" & catPK & "'>" & indent & Trim(catName) & "</option>">
      </cfif>

      <!--- if the nest is being used in the table on the category manage page, we need to use table row tags --->
      <cfif arguments.output_type EQ 2>
      <cfset catNameOutput = "<tr> <td>edit</td> <td>delete</td> <td>" & indent & Trim(catName) & "</td> </tr>">
      </cfif>

      <cfset output = output & catNameOutput>

      <!--- reset the indentation --->
      <cfset indent = "">

      <!--- check for children of this child --->
      <cfquery name="checkForKids" datasource="webdsn">
      SELECT * FROM dbo.BlogCategories
      WHERE catParent = '#rsCategoryChildren.catPK#'
      ORDER BY catName ASC
      </cfquery>
      <!--- if there are any, call this function recursively --->
      <cfif checkForKids.recordcount GT 0>
      <cfset GenerateCategories(genCatParent=catPK, level = level +1, output_type = arguments.output_type)>
      </cfif>
      </cfloop>

      <cfreturn output>

      </cffunction>

      <cfquery name="rsCategoryParents" datasource="webdsn">
      SELECT * FROM dbo.BlogCategories
      WHERE catParent IS NULL
      ORDER BY catName ASC
      </cfquery>



      and here is how i am calling the function for each situation (the table and the dropdown):

      quote:


      <table width="100%" class="managementtable">
      <tr bgcolor="#F6F6F6">
      <td> </td>
      <td> </td>
      <td>Category Name</td>
      </tr>

      <cfloop query="rsCategoryParents">
      <cfoutput><tr> <td>edit</td> <td>delete</td> <td>#Trim(catName)#</td> </tr></cfoutput>
      <cfset recursivecats = GenerateCategories(genCatParent=catPK,level=0,output_type=2)>
      <cfoutput>#recursivecats#</cfoutput>
      </cfloop>

      </table>
      <!---------------------------------------------------------------------------->
      <select name="select">
      <option>None</option>

      <cfoutput query="rsCategoryParents">
      <option value="#catPK#">#Trim(catName)#</option>
      <cfset recursivecats = GenerateCategories(genCatParent=catPK,level=0,output_type=1)>
      #recursivecats#
      </cfoutput>

      </select>



      calling the function for the table and the dropdown on the same page does not work
      if the function is first called with the argument for table, it tries to also output the table formatted code when the function is called again (even if it is called again with the argument for dropdown)

      is there another way i can have the same function output two different sets of data based on an argument? what am i doing wrong

      thanks for your time
        • 1. Re: dynamic return from a function based on an argument
          nummsa Level 1
          Check out the returntype="any" attribute in the CFFUNCTION tag.

          I would recommend against using this because I'm more of a proponent of "scrict typing", but coldfusion allows it.
          • 2. Re: dynamic return from a function based on an argument
            sjlsam2 Level 1
            hello, thanks for the fast reply
            but the returntype is not my issue

            the variable being returned is called output
            output is set to different strings as a result of an argument being 1 or 2

            for some reason, whenever i call the function on a page twice, output gets set to whatever the first argument is, that is being requested

            for example

            <function name='test'>
            <if type = 1><set output = "Joe"></if>
            <if type = 2><set output = "Bob"></if>
            <return output>
            </function>

            Now I call the function twice on the same page:
            test(type=1)
            <br />
            test(type=2)

            The output SHOULD look like this:
            Joe
            Bob

            Instead the output comes out looking like this:
            Joe
            Joe

            The IF statements are done correctly, and the function is receiving the argument correctly, but my dynamic output is not working

            my full code of the function is in the first post
            • 3. Re: dynamic return from a function based on an argument
              nummsa Level 1
              Try getting rid of the cfparam name="output" line. It seems the scope of this variable is getting lost so that every instance of the ouput variable is global possible. I've found a few scope problems in the past.
              In your cffunction where it's doing the cfset on the output variable, do a debugging cfoutput or cfdump to show that the cfif logic is working correctly. Even try outputing the output variable at that time after you set it to make sure it's alright then also dump the output variable as it's returned from the function.
              • 4. Re: dynamic return from a function based on an argument
                sjlsam2 Level 1
                i was able to fix my problem by creating a different cfreturn based on the argument
                • 5. Re: dynamic return from a function based on an argument
                  cf_dev2 Level 1
                  I didn't read the code thoroughly, but personally I wouldn't mix the db and html code that way. IMO it complicates the code and makes it harder to follow. But whatever option you choose, you should always VAR variables that are only used inside a function. When you don't use "var" unscoped variables are placed in the shared VARIABLES scope, which is likely to cause more scope problems in the future.

                  • 6. Re: dynamic return from a function based on an argument
                    Swift Level 1
                    sjlsam2,

                    Yeah, I think the main problem you had was a scoping one. For the second function call, the output variable already contained all of the output code from the first function call. In fact, I wouldn't be surprised to find that the output string for the second function call contained the output of the first plus the output of the second, and that it didn't render correctly on screen. A View Source would have determined that.

                    Anyhow, I suggest that you VAR your output variable as cf_dev2 suggests, and delete the three CFParam lines at the top. Further, your recursive call would therefore need to return it's result to the output variable, thus completing the recursive loop. See below:

                    ...
                    <!--- this holds the output_type we need for display purposes --->
                    <cfargument name="output_type" type="numeric" required="yes" default=0 >

                    <CFSet Var Output = "">
                    <CFSet Var catNameOutput = "">
                    <CFSet Var indent= RepeatString("  ", Arguments.Level)>

                    <!--- grab the children of the received category --->
                    <cfquery name="rsCategoryChildren" datasource="webdsn">
                    SELECT * FROM dbo.BlogCategories
                    ...


                    and


                    ...
                    <!--- if there are any, call this function recursively --->
                    <cfif checkForKids.recordcount GT 0>
                    <cfset Output = Output & GenerateCategories(genCatParent=catPK, level = level +1, output_type = arguments.output_type)>
                    </cfif>
                    </cfloop>


                    This is what I suggest with your code. HTH :)
                    Swift
                    • 7. Re: dynamic return from a function based on an argument
                      cf_dev2 Level 1
                      >Further, your recursive call would therefore need to return it's result to the output >variable, thus completing the recursive loop.

                      Good point.