Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Roger 195 posts 474 karma points
    May 07, 2014 @ 12:43
    Roger
    0

    Dependent dropdown list

    Hi all,

    Im looking for the best way to put together a parent>child dependent dropdown list based on 2 levels of the content node tree.

    I need the first DD to populate with all the parent node names, then when a node (item) is selected from the parent DD menu, the children of that node populate the 2nd DD menu

    Any help is greatly appreciated

    Thanks!

  • Chriztian Steinmeier 2741 posts 8406 karma points MVP 6x admin c-trib
    May 07, 2014 @ 14:10
    Chriztian Steinmeier
    1

    Hi Roger,

    Here's a quick stab at how to approach something like that:

    <?xml version="1.0" encoding="utf-8" ?>
    <xsl:stylesheet
        version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:umb="urn:umbraco.library"
        exclude-result-prefixes="umb"
    >
    
        <xsl:output method="html" indent="yes" omit-xml-declaration="yes" />
    
        <xsl:param name="currentPage" />
        <xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*[@level = 1]" />
    
        <!-- Select the parent of the nodes to show in the first Dropdown -->
        <xsl:variable name="dropdownRoot" select="$siteRoot" />
    
        <!-- Get the selected values (if any) -->
        <xsl:variable name="ddOneSelected" select="umbraco.library:RequestQueryString('ddOne')" />
        <xsl:variable name="ddTwoSelected" select="umbraco.library:RequestQueryString('ddTwo')" />
    
        <xsl:template match="/">
            <p>
                <label for="ddOne">One</label>
                <select id="ddOne" name="ddOne">
                    <!-- Process first set of nodes -->
                    <xsl:apply-templates select="$siteRoot/*[@isDoc][not(umbracoNaviHide = 1)]" />
                </select>
            </p>
            <p>
                <label for="ddTwo">Two</label>
                <select id="ddTwo" name="ddTwo">
                    <xsl:if test="not($ddOneSelected)">
                        <xsl:attribute name="disabled" />
                    </xsl:if>
                    <!-- Process children of the one selected in the first dropdown -->
                    <xsl:apply-templates select="$siteRoot/*[@id = $ddOneSelected]/*[@isDoc][not(umbracoNaviHide = 1)]" />
                </select>
            </p>
        </xsl:template>
    
        <!-- Generic template for a page -->
        <xsl:template match="*[@isDoc]">
            <option value="{@id}">
                <xsl:if test="@id = $ddOneSelected or @id = $ddTwoSelected">
                    <xsl:attribute name="selected" />
                </xsl:if>
                <xsl:value-of select="@nodeName" />
            </option>
        </xsl:template>
    
    </xsl:stylesheet>
    

    Please note that I haven't added any form or submit button etc...

    /Chriztian

  • Roger 195 posts 474 karma points
    May 07, 2014 @ 14:41
    Roger
    0

    Thanks Chriztian,

    I've just remembered that the current dropdown is in a UC and built in C# This is because there are 2 other independent DD lists that are populated by the values of datatypes, not from any node values.

    I think the only way I can get it all working as one form is if there is a way of using a for each loop in XSLT to populate a DD from a datatype. is this possible?

    Basically, its all part of a search system with 4 DD options. the first 2 options are what you've helped me with above. The other 2 options are DD's that are populated from datatypes

    Thanks

    Roger

  • Roger 195 posts 474 karma points
    May 07, 2014 @ 15:42
    Roger
    0

    Hi Chriztian, I think we're getting closer. We tried using GetPreValues to iterate through the data type. See at the bottom of the code below. Its not working at the moment, it doesn't like this: <xsl:for-each select="$typeList//preValue">

    Also, the initial DD is populating as per your post above but the 2nd one stays disabled. I take it this is because there is no script to fire the on select or something?

    Here's the code so far:

    <?xml version="1.0" encoding="UTF-8"?>
    

    ]>

    <xsl:param name="currentPage" />
    <xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*/Venues/Country/Region/County" />
    
    <!-- Select the parent of the nodes to show in the first Dropdown -->
    <xsl:variable name="dropdownRoot" select="$siteRoot" />
    
    <!-- Get the selected values (if any) -->
    <xsl:variable name="ddOneSelected" select="umbraco.library:RequestQueryString('ddOne')" />
    <xsl:variable name="ddTwoSelected" select="umbraco.library:RequestQueryString('ddTwo')" />
    
    <xsl:template match="/">
        <p>
            <label for="ddOne">One</label>
            <select id="ddOne" name="ddOne">
                <!-- Process first set of nodes -->
                <xsl:apply-templates select="$siteRoot/*[@isDoc][not(umbracoNaviHide = 1)]" />
            </select>
        </p>
        <p>
            <label for="ddTwo">Two</label>
            <select id="ddTwo" name="ddTwo">
                <xsl:if test="not($ddOneSelected)">
                    <xsl:attribute name="disabled" />
                </xsl:if>
                <!-- Process children of the one selected in the first dropdown -->
                <xsl:apply-templates select="$siteRoot/*[@id = $ddOneSelected]/*[@isDoc][not(umbracoNaviHide = 1)]" />
            </select>
        </p>
    </xsl:template>
    
    <!-- Generic template for a page -->
    <xsl:template match="*[@isDoc]">
        <option value="{@id}">
            <xsl:if test="@id = $ddOneSelected or @id = $ddTwoSelected">
                <xsl:attribute name="selected" />
            </xsl:if>
            <xsl:value-of select="@nodeName" />
        </option>
    </xsl:template>
    
        <xsl:variable name="typeList" select="umbraco.library:GetPreValues('1130')"/>
        <xsl:for-each select="$typeList//preValue">  
            <option value="{@id}">
                <xsl:value-of select="current()"/>
            </option>
    </xsl:for-each>
    

  • Chriztian Steinmeier 2741 posts 8406 karma points MVP 6x admin c-trib
    May 07, 2014 @ 16:54
    Chriztian Steinmeier
    0

    Hi Roger,

    The reason it doesn't like the for-each (I'm guessing) is because it's a direct child of the stylesheet element where only a couple of elements are allowed; the code itself seems OK... so we'll put it into the root template (match="/") along with the other two selects, and add the necessary "glue" bits as well:

    Add a variable at the top to hold the QueryString value:

    <xsl:variable name="ddThreeSelected" select="umbraco.library:RequestQueryString('ddThree')" />
    

    Add this new <select> just after the two first:

    <p>
        <select id="ddThree" name="ddThree">
            <xsl:if test="not($ddTwoSelected)">
                <xsl:attribute name="disabled" />
            </xsl:if>
            <xsl:variable name="preValues" select="umbraco.library:GetPreValues(1130)" />
            <!-- Process the prevalues of a datatype -->
            <xsl:apply-templates select="$preValues//preValue" />
        </select>
    </p>
    

    And add a template for the <preValue> output (this way we can reuse it for the 4th DD if that's datatype as well):

    <!-- Template for a <preValue> -->
    <xsl:template match="preValue">
        <option value="{.}">
            <xsl:if test=". = $ddThreeSelected">
                <xsl:attribute name="selected" />
            </xsl:if>
            <xsl:value-of select="." />
        </option>
    </xsl:template>
    

    Yes - you'll need to wrap a <form> around it and wire a script up to submit the form in the selects' change events, but I always just put a submit button in to make sure it works with no scripts at all — afterwards, I can always hide the button and do some AJAX-fiddling, but I don't want to have to make sure that works as long as I haven't got the other stuff working correctly first.

    /Chriztian

  • Paul Griffiths 359 posts 999 karma points
    May 07, 2014 @ 16:57
    Paul Griffiths
    0

    Hi Both

    this code is now populating all the necessary values but it is not populating (on checkchange) ddTwo (suburb) based on what City/Town has been selected in ddOne.

    <xsl:output method="html" indent="yes" omit-xml-declaration="yes" />
    
        <xsl:param name="currentPage" />
        <xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*/Venues/Country/Region/County" />
    
        <!-- Select the parent of the nodes to show in the first Dropdown -->
        <xsl:variable name="dropdownRoot" select="$siteRoot" />
    
        <!-- Get the selected values (if any) -->
        <xsl:variable name="ddOneSelected" select="umbraco.library:RequestQueryString('ddOne')" />
        <xsl:variable name="ddTwoSelected" select="umbraco.library:RequestQueryString('ddTwo')" />
    
        <xsl:template match="/">
                <fieldset>
                    <legend>venue search</legend>
    
                    <!-- Populates city/town based on values in the content tree -->    
                        <div class="short-select">
                                <select id="ddOne" name="ddOne">
                                    <option value="0">Select City/Town</option>
                                    <!-- Process first set of nodes -->
                                <xsl:apply-templates select="$siteRoot/*[@isDoc][not(umbracoNaviHide = 1)]" />
                                </select>
                        </div>
    
                    <!-- Populates suburbs based on the value selected in ddOne (City/Town) --> 
                        <div class="short-select">  
                                <select id="ddTwo" name="ddTwo">
                                    <xsl:if test="not($ddOneSelected)">
                                        <xsl:attribute name="disabled" />
                                    </xsl:if>
                                    <option value="0">Select Suburb</option>
                                    <!-- Process children of the one selected in the first dropdown -->
                                    <xsl:apply-templates select="$siteRoot/*[@id = $ddOneSelected]/*[@isDoc][not(umbracoNaviHide = 1)]" />
                                </select>
                        </div>
    
                    <!-- Populates Function Types pre values defined in the function types data type -->    
                        <div class="short-select">
                                <select>    
                                    <option value="0">Select Function Type</option>
                                    <xsl:variable name="typeList" select="umbraco.library:GetPreValues('1130')"/>
                                        <xsl:for-each select="$typeList//preValue">                                     
                                            <option value="{@id}">                                          
                                                <xsl:value-of select="current()"/>
                                            </option>
                                        </xsl:for-each>
                                </select>
                    </div>
    
                    <!-- Populate Capcity values static values dont need to change -->              
                    <div class="short-select">
                                <select>
                                    <option value="0">Select Capacity</option>
                                    <option value="50">upto 50 Guests</option>
                                    <option value="100">upto 100 Guests</option>
                                    <option value="150">upto 150 Guests</option>
                                    <option value="200">upto 200 Guests</option>
                                    <option value="300">upto 300 Guests</option>
                                    <option value="400">upto 400 Guests</option>
                                    <option value="500">upto 500 Guests</option>
                                    <option value="750">upto 750 Guests</option>
                                    <option value="1000">upto 1000 Guests</option>
                                    <option value="2000">upto 2000 Guests</option>
                                    <option value="3000">upto 3000 Guests</option>
                                    <option value="4000">upto 4000 Guests</option>
                                    <option value="5000">upto 5000 Guests</option>
                                    <option value="10000">upto 10,000 Guests</option>
                                    <option value="20000">upto 20,000 Guests</option>
                                    <option value="1000000">upto 20,000 + Guests</option>
                                </select>
                    </div>
                    <input type="submit" class="btnVenueSearch" title="Find my perfect function room"></input>
                    <a class="advance-search-link" href="/" title="Click advance serach">Advance Search</a>
    
                </fieldset>
        </xsl:template>
    
        <!-- Generic template for a page -->
        <xsl:template match="*[@isDoc]">
            <option value="{@id}">
                <xsl:if test="@id = $ddOneSelected or @id = $ddTwoSelected">
                    <xsl:attribute name="selected" />
                </xsl:if>
                <xsl:value-of select="@nodeName" />
            </option>
        </xsl:template> 
    
    </xsl:stylesheet>
    

    enter image description here

    Any ideas?

    Thanks

    Paul

  • Paul Griffiths 359 posts 999 karma points
    May 07, 2014 @ 16:59
    Paul Griffiths
    0

    sorry Chriztian

    I just replied without realising you had written to Roger.

    Paul

  • Paul Griffiths 359 posts 999 karma points
    May 08, 2014 @ 14:01
    Paul Griffiths
    0

    Hi Chriztian,

    Wondering if you could shed some light on how to achieve the folling that is if it is possible

    1. How to post the form variables to the results page when the button click defaults to the page runat=server and ignores the search form

    2. What is the best script required to trigger the 2nd DD when a selection is made in the first DD.

    below is a shot of how the current code looks

    <xsl:output method="html" indent="yes" omit-xml-declaration="yes" />
    
        <xsl:param name="currentPage" />
        <xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*/Venues/Country/Region/County" />
    
        <!-- Select the parent of the nodes to show in the first Dropdown -->
        <xsl:variable name="dropdownRoot" select="$siteRoot" />
    
        <!-- Get the selected values (if any) -->
        <xsl:variable name="ddOneSelected" select="umbraco.library:RequestQueryString('ddOne')" />
        <xsl:variable name="ddTwoSelected" select="umbraco.library:RequestQueryString('ddTwo')" />
    
        <xsl:template match="/">
            <form name="search-form" id="search-form" method="post" action="/search.aspx">
                <fieldset>
                    <legend>venue search</legend>
    
                    <!-- Populates city/town based on values in the content tree -->   
                        <div class="short-select">
                                <select id="ddOne" name="ddOne">
                                    <option value="0">Select City/Town</option>
                                    <!-- Process first set of nodes -->
                                <xsl:apply-templates select="$siteRoot/*[@isDoc][not(umbracoNaviHide = 1)]" />
                                </select>
                        </div>
    
                    <!-- Populates suburbs based on the value selected in ddOne (City/Town) -->   
                        <div class="short-select">   
                                <select id="ddTwo" name="ddTwo">
                                    <xsl:if test="not($ddOneSelected)">
                                        <xsl:attribute name="disabled" />
                                    </xsl:if>
                                    <option value="0">Select Suburb</option>
                                    <!-- Process children of the one selected in the first dropdown -->
                                    <xsl:apply-templates select="$siteRoot/*[@id = $ddOneSelected]/*[@isDoc][not(umbracoNaviHide = 1)]" />
                                </select>
                        </div>
    
                    <!-- Populates Function Types pre values defined in the function types data type -->   
                        <div class="short-select">
                                <select id="ddThree" name="ddThree">   
                                    <option value="0">Select Function Type</option>
                                    <xsl:variable name="typeList" select="umbraco.library:GetPreValues('1130')"/>
                                        <xsl:for-each select="$typeList//preValue">                                       
                                            <option value="{@id}">                                           
                                                <xsl:value-of select="current()"/>
                                            </option>
                                        </xsl:for-each>
                                </select>
                    </div>
    
                    <!-- Populate Capcity values static values dont need to change    -->           
                    <div class="short-select">
                                <select name="ddFour" id="ddFour">
                                    <option value="0">Select Capacity</option>
                                    <option value="50">upto 50 Guests</option>
                                    <option value="100">upto 100 Guests</option>
                                    <option value="150">upto 150 Guests</option>
                                    <option value="200">upto 200 Guests</option>
                                    <option value="300">upto 300 Guests</option>
                                    <option value="400">upto 400 Guests</option>
                                    <option value="500">upto 500 Guests</option>
                                    <option value="750">upto 750 Guests</option>
                                    <option value="1000">upto 1000 Guests</option>
                                    <option value="2000">upto 2000 Guests</option>
                                    <option value="3000">upto 3000 Guests</option>
                                    <option value="4000">upto 4000 Guests</option>
                                    <option value="5000">upto 5000 Guests</option>
                                    <option value="10000">upto 10,000 Guests</option>
                                    <option value="20000">upto 20,000 Guests</option>
                                    <option value="1000000">upto 20,000 + Guests</option>
                                </select>
                    </div>
                    <input type="button" onclick="window.location.href='/search.aspx'" class="btnVenueSearch" title="Find my perfect function room"/>
                    <a class="advance-search-link" href="/" title="Click advance serach">Advance Search</a>
    
                </fieldset>
            </form>
        </xsl:template>
    
        <!-- Generic template for a page -->
        <xsl:template match="*[@isDoc]">
            <option value="{@id}">
                <xsl:if test="@id = $ddOneSelected or @id = $ddTwoSelected">
                    <xsl:attribute name="selected" />
                </xsl:if>
                <xsl:value-of select="@nodeName" />
            </option>
        </xsl:template>
    </xsl:stylesheet>
    

    Thanks for your time mate

    Paul

  • Chriztian Steinmeier 2741 posts 8406 karma points MVP 6x admin c-trib
    May 08, 2014 @ 20:21
    Chriztian Steinmeier
    0

    Hi Paul,

    1. So I'm not 100% sure I understand your first question - but what I'd do first was to change the <input type="button"> to a submit button: <input type="submit"> and remove the JavaScript.

      I can see you're using a POST form, so you'd want to change the use of RequestQueryString() to use RequestForm() instead, where the values are fetched.

    2. To trigger the "next" dropdown you need to manually submit the form when a selection is made in the first dropdown - you can use the onchange handler for that, e.g.: <select onchange="this.form.submit()"> or if you're using jQuery, do it somewhere in your code:

      $('select').on('change', function() { this.form.submit(); });
      

    When this all works, you'll have a form that posts every time a selection is made, and the values are picked up accordingly. This needs to work as full page reloads before you start to only refresh the form parts of the page.

    /Chriztian

  • Roger 195 posts 474 karma points
    May 09, 2014 @ 13:28
    Roger
    0

    Hi Chriztian, I think the issue is that the site uses web forms and when I use the submit button, it ignores the action of the search form and fires the main page form

    Thanks

    Roger

  • Paul Griffiths 359 posts 999 karma points
    May 12, 2014 @ 16:16
    Paul Griffiths
    0

    Hi all,

    Still struggling to find a solution for this if anyone has any help. Just to reiterate what is trying to be achieved here please read below. I have the following content tree structure

     Merseyside   (type = county)
            Liverpool (type = city/town)
                 Area of Liverpool 1 (type = suburb)
                 Area of Liverpool 2 (type = suburb)
                 Area of Liverpool 3 (type = suburb)
            Birkenhead (type = city/town)
                 Area of Birkenhead 1 (type = suburb)
                 Area of Birkenhead 2 (type = suburb)
    etc......
    

    On the website I have a search form which consists of two drop down Lists and using the following XSLT kindly helped by chriztian I can populate the city/town dropdown list with all the city/town nodes :) great.

    <!-- Select the parent of the nodes to show in the first Dropdown -->
    <xsl:variable name="dropdownRoot" select="$siteRoot" />
    
    <!-- Get the selected values (if any) -->
    <xsl:variable name="ddOneSelected" select="umbraco.library:RequestQueryString('ddOne')" />
    <xsl:variable name="ddTwoSelected" select="umbraco.library:RequestQueryString('ddTwo')" />
    
    <xsl:template match="/">            
                <legend>venue search</legend>               
                <!-- Populates city/town based on values in the content tree -->    
                    <div class="short-select">
                            <select id="ddOne" name="ddOne">
                                <option value="0">Select City/Town</option>
                                <!-- Process first set of nodes -->
                            <xsl:apply-templates select="$siteRoot/*[@isDoc][not(umbracoNaviHide = 1)]" />
                            </select>
                    </div>              
                <!-- Populates suburbs based on the value selected in ddOne (City/Town) --> 
                    <div class="short-select">  
                            <select id="ddTwo" name="ddTwo">
                                <xsl:if test="not($ddOneSelected)">
                                    <xsl:attribute name="disabled" />
                                </xsl:if>
                                <option value="0">Select Suburb</option>
                                <!-- Process children of the one selected in the first dropdown -->
                                <xsl:apply-templates select="$siteRoot/*[@id = $ddOneSelected]/*[@isDoc][not(umbracoNaviHide = 1)]" />
                            </select>
                    </div>
    

    With all this in place i have the two drop down lists are rendered fine and the city/town dropdownlist is populated with the city/towns. GREAT!

    However, the problem is that im struggling to populate the suburb drop down list based on the value that is selected in the city town. So for example if someone selects Liverpool as the city/town then i need the suburb Dropdownlist to be populated with the child nodes of Liverpool which in my example would be Area of Liverpool 1, Area of Liverpool 2, Area of Liverpool 3.

    Can what i am trying to do be achieved through using a script? because i need some kind of action to occur that also stores the value selected in the city/town but also populates the suburb based on the selection that been made. Ive tried to use <select id="ddOne" name="ddOne" onchange="this.form.submit()">but it is just clearing the values when post back occurs.

    Any information regarding this issue would be gratefully appreciated as i'm really struggling.

    Thanks

    Paul

  • Chriztian Steinmeier 2741 posts 8406 karma points MVP 6x admin c-trib
    May 12, 2014 @ 20:07
    Chriztian Steinmeier
    0

    Hi guys,

    I'm sorry but I don't think I can help you get around the Webforms issue — I never understood why they had to break perfectly good frontend code and handle everything in that __postBack() thing :-)

    One way to maybe fix this (and I do think it's a case of "fixing the wrong problem") would be to handle the first two selects client-side - i.e. render all possibilities in the second one, and then have a script remove the options that shouldn't be selectable in ddTwo when a selection is made in ddOne. But it's a jump into a rabbit hole that will only get deeper for every small change you make to the page.

    /Chriztian

  • Paul Griffiths 359 posts 999 karma points
    May 12, 2014 @ 20:21
    Paul Griffiths
    0

    Hello chriztian

    As always thanks for your response regarding the issue, it's been a right pain in the arse lol. I've done lots of research and lots of posting in other forums but up to now I've not had much luck. :( I will speak with Roger tomorrow and see if we can find a solution.

    If we do manage to get a fix I will post the solution up hear just incase anyone else has a similar issue.

    Anyway thanks very much mate

    Paul

Please Sign in or register to post replies

Write your reply to:

Draft