Skip to main content
December 28, 2010
Answered

Another way to do this maybe?

  • December 28, 2010
  • 3 replies
  • 5018 views
Hi I have a CF application that uses a form page to enter data into the input fields, then passes those fields as SESSION variables to the action page so that the use can view hwo the page is going to look. basically is an application to build new html documents/pages.

Everything so far works fine. I have need to keep adding input fields at various stages, and so I have added a text area for the purpose of adding a list of sorts which is a list of cross references to a particular product related to the page being built.

The cross reference list variable: SESSION.crossRefList is then passed to the action page and displayed in an unordered list by means of <cfloop> like so:

<cfif SESSION.crossRefList NEQ "">

<ul>           <cfloop index="crossRefList" list="#FORM.crossRefList#" delimiters="#chr(13)##chr(10)#">             <li><cfoutput>#crossRefList#</cfoutput></li>           </cfloop>         </ul>
</cfif>


All is fine with this except: Each page may have one list or it may have 20 lists. And each list is started with a brand name that is ideally enclosed in an <h3> tag.

I would love to be able for the data entry girl to enter this without having to actually enclose the first list item in <h3> tags, however, it ezcapes me on how this would be accomplished, since again this is completely dynamic and the number if list items is unknown. Here is an example of the lists I'm talking about, then you can see what I trying to figure out.

Alpine SKY10 Apollo Products Imager 100 Best Hood K15 Callisto 3094071 Cole-Parmer Compound Microscope Trinocular, Catalog No. A-48924-30 Fenix 3069061 Helix 3003051 Kitchenaid Locos 3072071 Lumos 3071071 3093071 Rumex 3001061 Solaris 3043061 Sunnex Flexible Halogen Light Thermadore Hood Light HG5W36TS

I hope this all makes sense. Again, The way I have it now, the data entry girl has to type in the <h3> tags for the bolded texts above to be styled correctly. I would love to be able to have this done for her so she wouldnt have to worry about that. Thanks for any help and if you need any more info, let me know.
Ok well the text of lists above didn't translate well when I copied and pasted. The first Item in each list should be bold, or in my code would be an <h3> tag.
    This topic has been closed for replies.
    Correct answer ilssac

    Hi ilssac, I actually reworked this code another way...lol and have it working pretty well. I would still like to know why I couldnt get the code you gave me working, so I will post the data that I entered and how it was entered.

    Not sure how the best way to do this would be though, except to show you the text and what delimiters I used to seperate each word/word phrase.

    The first word I typed in was

    function(){return A.apply(null,[this].concat($A(arguments)))}Product Name       //then hit enter for a carriage return

    Then the next word, which would be on the next line was seperated by another delimiter, the pipe I used last:

    function(){return A.apply(null,[this].concat($A(arguments)))}number | name | another name | another number

    When i used ANY delimiter in the above text, they delimiter would show as text in the list and would not seperate each word in a new list item.

    The only way I could get each word to display on seperate lines (ie in a list type format) was to hit enter AFTER each word. But This also placed each word in the heading tag of the first cfloop, then it placed each word in the plain <li> cfloop as well. So it was repeating each word for the two lists, like this:

    function(){return A.apply(null,[this].concat($A(arguments)))}

    Product Name

    Product Name

    number

    number

    name

    name

    another name

    another name

    another number

    another number

    Like I said, I tried different variations but I either had the loops repeating each word when using both, or when I commented out the first loop, the list was displayed once, but the first word was not in the heading tag of courses.

    Now what I did was to just use a single loop, then a cfif to look for a character, like the pipe or whatever I want, and if its present, then display the preceeding word in the heading tag, otherwise, just display in a plain <li> tag. Here is the code I'm using now:

              <cfoutput>
                <cfloop index="brandGroup" list="#FORM.crossRefList#" delimiters="#chr(13)##chr(10)#">
                  <!--- header --->
                  <cfif NOT find("|", brandGroup)>
                    <br />
                   <h3>#brandGroup#</h3>
                    <!--- detail line --->
                    <cfelse>
                    <ul>
                      <cfloop index="productGroup" list="#brandGroup#" delimiters="|">
                        <li>#productGroup#</li>
                      </cfloop>
                    </ul>
                  </cfif>
                </cfloop>
              </cfoutput>

    Not sure if this is a proper way to accomplish this, but it doesnt seem any less user friendly than the previous way, Do you see any downside to this?


    Here is a complete example of what I was original trying to propose.  I am worried about your solution using the same delimiters to distinguish different types of data.

    <cfsavecontent variable="inputData">
    BrandGroup:product1|product2|product3
    A Brand:foobar|george|gracie
    Another Brand:something|something else|yet another, something
    </cfsavecontent>

    <cfoutput>
    <cfloop list="#inputData#" index="BrandGroup" delimiters="#chr(13)##chr(10)#">
    <!--- Each Brand Group and associate list of products are delimited by carriage returns and line feeds. --->
        <h2>#listFirst(BrandGroup,":")#</h2>
        <!--- The Brand name is the first element delimited by the colon(:) character --->
        <ul>
            <cfloop list="#listLast(BrandGroup,':')#" index="product" delimiters="|">
            <!--- The list of products is the last element delimited by the colon(:) --->
            <!--- The items in the list of products is delimited by the pipe(|) character. --->
            <li>#product#</li>
            </cfloop>
        </ul>
    </cfloop>
    </cfoutput>

    This should produce the following output:

         <h2>BrandGroup</h2>
         <ul>
              <li>product1</li>
              <li>product2</li>
              <li>product3</li>
         </ul>
         <h2>A Brand</h2>
         <ul>
              <li>foobar</li>
              <li>george</li>
              <li>gracie</li>
         </ul>
         <h2>Another Brand</h2>
         <ul>
              <li>something</li>
              <li>something else</li>
              <li>yet another, something</li>
         </ul>

    BrandGroup

    • product1
    • product2
    • product3

    A Brand

    • foobar
    • george
    • gracie

    Another Brand

    • something
    • something else
    • yet another, something

    3 replies

    ilssac
    Inspiring
    December 28, 2010

    There has to be some way to programmatically determining what is a brand name and what is a product.

    Three possible ideas depending on how hard you want to work and|or how trainable the input user is.

    1) A user input form with a repeating section:

    It is not to difficult to use JavaScript to all a 1-N repeating form input section.  You could then design the user interface such that the user inputs the brand name in one form control and the list of selected products in the second form control.  There is then a third control that will dynamically add a new brand and list control if another set is needed.

    You can see this on a page I built for a game I play: http://ilsweb.com/games/demographics.html.  IF you change some of the values on the page, you will see other slider controls added and removed from the page as necessary.  Your application would probably be simpler then this example but it was handy.

    2) You compare the values intered to a databsase to see which are brands and|or products.

    This is pretty straight forward.  You take the list entered by the user and do a SELECT from a table of brand names and|or a table of products.  IF it is found then you know what the list value is and how to treat it in your output.

    3) You train the user to input the values with different delimiters.  Then you can output the data as a nested list.

    In this case the user utilizes three delimiters to separate the list of brands and the nested list of products for each brand.  Any three distinct delimiter can be used like pipes (|) commas (,) and colons (:) etc.

    I.E.

    Apollo:products Imager 100

    Best Hood:K15

    Callisto:3094071

    Cole-Parmer:Compound Microsope|Tranocular, Catalog No. A-48-30

    Then you could loop over that something like this

    <cfoutput>

    <cfloop index=brandGroup" list="#form.crossRefList#" delimiters="#chr(13)##chr(10)#">

         <h3>#listFirst(brandGroup,":")#</h3>

          <ul>

          <cfloop index="product" list="#listLast(brandGroup,":")#" delimiter=","> <!--- the comma is the default delimiter but I'm be explicit here -->

            <li>#product#</li>

         </cfloop>

          </ul>

    </cfloop>

    </cfoutput>

    But in reality you are doing a LOT of work to try and avoid the work of making this a better, database driven system.

    December 28, 2010

    Hi ilssac, I was doing some reading on the suggestion of the above poster. That seemed like a good way to do it, however I was having trouble figuring out, like you mentioned, to differentiate between which text would be a brand name and which would be a product number of that brand name.

    You also mentioned me doing alot of work to avoid making this a well designed database driven application. The fact is this is NOT a database driven site, and probably never will be, at least not in the next few years. My employer is adament about keeping his site design as is, which means completely static and management hell! lol He is convinced, to some degree, that dynamically created pages are not indexed and ranked as well as statice plain text page and page names. I have been working on a parallel site written in CF and using  MySQL, but thats quite a bit down the road till completion, since I think I have about 20% of the products in the database as of now.

    I am very intrigued with your third suggestion though. I think the user could in fact learn to enter different delimiters based on which text she were entering and although I was thinking I could somehow use a nested cfloop of sorts, I hadn't even thought of this simple resolution and wasnt sure I could use different delimiters for the same cfloop. This may be the easiest way to accomplish this all the way around. It certainly beats having her wrap heading tags around text.

    ilssac
    Inspiring
    December 28, 2010

    That's good.  I just noticed my output loops did not match the data example I provided.

    <cfoutput>
    <cfloop index=brandGroup" list="#form.crossRefList#" delimiters="#chr(13)##chr(10)#">
         <h3>#listFirst(brandGroup,":")#</h3>
          <ul>
          <cfloop index="product" list="#listLast(brandGroup,":")#" delimiter="|">
            <li>#product#</li>
         </cfloop>
          </ul>
    </cfloop>
    </cfoutput>

    I forgot I had changed the product delimiter to a pipe (|) because you must make sure the delimiter is never a character that might be part of the data in the list, like the comma in "Tranocular, Catalog No. A-48-30".

    P.S.  Data driven site is not mutually exclusive with static site.  As you are doing now, ColdFusion is perfectly capable of writing out static pages.  It is just as good at writing out those pages from information stored in a database as it is from information directly from a form like you are doing now.

    With a database based version, you would have more options for creating a better user interface for data input making use of look up tables and other features to mitigate data input error that are bound to happen with your current completely manual approach.

    As for your employer believing that dynamic pages are not indexed as well as static ones.  His information is outdated and largely incorrect.  As long as there are distinct and static url paths for each and every 'page' you wish to have indexed by search engines and these dynamic pages utilize all the other search engine optimization best practices (i.e. descriptive titles, relevant content, proper page layout and headings, etc) they will be index just as well as equal quality static pages.  The only real problem would be if one were to only use some type of dynamic JavaScript based form element (like a jump menu) to provide navigation to all the products.  Search engines can not manipulate form controls, so they would never see those links and be able to follow them.

    To provide a bit of the best of both worlds for a web site I built for my father (www.sierraoutdoorrecreation.com).  I use a standard dynamic page to display each of the 'products' on the site (outdoor recreation locations in this example) from the database.  But rather than using a URL variable or some other means, when data is entered for a new product, the ColdFusion processing code also creates a two line file for that product when the data is added to the database.

    <cfset productID = 123> <!--- where '123' is the key product ID value from the database for this page --->

    <cfinclude template="productTemplate.cfm">

    Thus there is a distinct and separate page for each and every product in the site as far as search engines are concerned.  But all of those files are generated with the single "productTemplate.cfm" file, thus there is one point to edit when new updates need to be made to the site.

    Participating Frequently
    December 28, 2010

    You can obviously easily switch to using <ul>'s (even nested) like so if your needs dictate:

    <cfoutput>
        <cfloop collection="#xRef#" item="i">
            <ul>
                <li><h3>#i#</h3>
                    <ul>
                        <cfloop array="#xRef#" index="a">
                            <li>#a#</li>
                        </cfloop>
                    </ul>
                </li>
            </ul>
        </cfloop>
    </cfoutput>

    Participating Frequently
    December 28, 2010

    Sounds like you're trying to do some complex logic with a simple list.  This is where complex objects need to be employed.  Consider using a struct of arrays to store your data.  Then you can loop over things nicely and get the desired results.  Here's an example:

    <cfset xRef = {} />
    <cfset xRef["Alpine"] = [] />
    <cfset arrayAppend(xRef["Alpine"], "SKY10") />

    <cfset xRef["Cole Parmer"] = [] />
    <cfset arrayAppend(xRef["Cole Parmer"], "Compound Microscope") />
    <cfset arrayAppend(xRef["Cole Parmer"], "Trinocular, Catalog No. A-48924-30") />

    <cfdump var="#xRef#">

    <cfoutput>
        <cfloop collection="#xRef#" item="i">
            <h3>#i#</h3>
            <cfloop array="#xRef#" index="a">
                <p>#a#</p>
            </cfloop>
        </cfloop>
    </cfoutput>