Solved

Dynamic 3-tier vertical menu - how?

Posted on 2014-02-26
12
696 Views
Last Modified: 2014-03-01
I want to create a 3-tier hierarchical menu that functions like the one here: http://css-tricks.com/snippets/

I want a fixed layout of 3 columns side-by-side. The first column contains letters A-Z.
Clicking a letter populates the second column - starting from the top, not from the position of the selected letter (so the ASP.Net Menu control is out). The selected item in column 2 then populates column 3, again from the top.

What are the options?
0
Comment
Question by:TimHudspith
  • 6
  • 5
12 Comments
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39888712
I don't understand the link you posted or at least it does not match up with what you are trying to achieve.

If you have 3 div's each one column.  You could use ajax to grab all choices starting with "a" and place in column 2 and so on.  Or with a page refresh, send to the url and grab the querystring.

<div id="col1">
    <ul>
         <li><a href="">a</a></li>
         <li><a href="">b</a></li>
         <li><a href="">c</a></li>
         <li><a href="">z</a></li>
    </ul>
</div>
<div id="col2">
    <ul>
         <li><a href="">Choices from Col1</a></li>
         <li><a href="">Choices from Col1</a></li>
         <li><a href="">Choices from Col1</a></li>
         <li><a href="">Choices from Col1</a></li>
    </ul>
</div>
<div id="col1">
    <ul>
         <li><a href="">Choices from Col2</a></li>
         <li><a href="">Choices from Col2</a></li>
         <li><a href="">Choices from Col2</a></li>
         <li><a href="">Choices from Col2</a></li>
    </ul>
</div>

Open in new window


If the total choices are not very many, I would just send all choices to the browser at once and use js/jquery to display. I have used chained many times http://www.appelsiini.net/projects/chained.  If you end up having to send 1000 choices to the browser at once, that may be slow.  But sending 50 or 100 options may be ok.  Then you could let people make multiple choices from col1,2 and 3 without hitting the db each time.  Or you could have it hardcoded.


From the sample code, you can see it is easy to set up.  They just use the class from the first column to populate the 2nd and so on.
<select id="mark" name="mark">
  <option value="">--</option>
  <option value="bmw">BMW</option>
  <option value="audi">Audi</option>
</select>
<select id="series" name="series">
  <option value="">--</option>
  <option value="series-3" class="bmw">3 series</option>
  <option value="series-5" class="bmw">5 series</option>
  <option value="series-6" class="bmw">6 series</option>
  <option value="a3" class="audi">A3</option>
  <option value="a4" class="audi">A4</option>
  <option value="a5" class="audi">A5</option>
</select>

Open in new window

0
 

Author Comment

by:TimHudspith
ID: 39891892
I have the 3-column <div> structure in place and all my A-Z items in a <ul> in the first <div>. Columns 2 and 3 will have to be populated dynamically from the database - there are approx 1000 entries at the moment but this will grow. I'm new to web dev so need some pretty detailed guidance on how to take this forward using AJAX to grab the data for the next column (coming from SQL Server).

I'm building this in ASP.Net by the way, if that changes things.
0
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39891941
I think 1000 entries is too much to send to the browser.

What would happens is you would pick a letter in column one. That would send an ajax call to populate column 2 and so on.
0
 

Author Comment

by:TimHudspith
ID: 39891955
OK, but what I need to know is how AJAX calls and returns data from SQL Server, then iterates that to populate the second <ul>.
0
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39892199
Here is a working sample of what I am talking about  http://jsbin.com/gusebitu/1/edit

This is using jquery ajax https://api.jquery.com/jQuery.ajax/

The first column you would populate on page load

The 2nd column would populate by clicking a letter.  In my sample, I am hitting the url     'http://jsbin.com/hutiyike/1.js.  This is static data and in your case could be php/asp.  Notice I am passing the variable id.  The get really looks like http://jsbin.com/hutiyike/1.js?id=a  or somepage.php?id=a.  Use your own logic to grab all the "a" words.

The 2nd pass does the same thing but a little different. I am passing an attribute data-item. This would be generated by your serverside code.  You can grab the data from that by using jquery attr("data-item").  The -item can be whatever you want to call it.  This would hit your 2nd url that will get us the next set of results for the last column.



<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <div class="col">
    <ul class="first">
      <li><a href="#">A</a></li>
      <li><a href="#">B</a></li>
      <li><a href="#">C</a></li>
    </ul>
    </div>
  <div class="col two"></div>
  <div class="col three"></div>
  
</body>
</html>

Open in new window

// http://jsbin.com/hutiyike/1.html
// sample data
//<li><a href="#" data-item="1">Aardvark</a></li>
//<li><a href="#" data-item="2">Aardwolf</a></li>
//<li><a href="#" data-item="3">Aasvogel</a></li>

//http://jsbin.com/yupiwolu/1.html
//sample data
//<li><a data-item="1">col 3 A</a></li>
//<li><a data-item="2">col 3 B</a></li>
//<li><a data-item="3">col 3 C</a></li>
$(function () {
    // first column select
    $('.first li a').click(function (e) {
        e.preventDefault();
        var firstLetter = $(this).text();


        $.ajax({
            type: 'get',
            url: 'http://jsbin.com/hutiyike/1.js',
            dataType: "html",
            data: {
                id: firstLetter
            }
        }).done(function (msg) {
            $('div.two').html('<ul>' + msg + '</ul>');

            $('.two ul li a').click(function () {
                theData = $(this).attr('data-item');
                $.ajax({
                    type: 'get',
                    url: 'http://jsbin.com/yupiwolu/1',
                    dataType: "html",
                    data: {
                        id: theData
                    }
                }).done(function (msg) {
                    $('div.three').html('<ul>' + msg + '</ul>');

                });
            });


        }); // ajax




    }); //click



});

Open in new window

.col{width:100px;float:left;margin-right:10px;border-left-style:solid;min-height:100px;

Open in new window

0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:TimHudspith
ID: 39894712
Dealing with the AJAX call first - I'm getting an undefined error.

I've created a function in the code-behind file (HomePage.aspx.vb) to run a parameterised query on the database using the letter clicked in the list as the parameter. It returns the data (a list of categories beginning with the letter clicked) as xml.

<WebMethod()>
    Public Shared Function GetCategory(letter As String) As String
        Using dtb As New DataTable
            Using myConn As New dbConn
                Using conn As SqlConnection = myConn.cnn
                    Dim strCmd As String = "SELECT Category FROM T_Categories WHERE Letter = '" + letter + "'"
                    Using dap As New SqlDataAdapter(strCmd, conn)
                        dap.Fill(dtb)
                        Using sw As StringWriter = New StringWriter()
                            dtb.TableName = letter & "_Categories" 'or next line fails
                            dtb.WriteXml(sw, XmlWriteMode.IgnoreSchema)
                            Return sw.ToString
                        End Using
                    End Using
                End Using
            End Using
        End Using
    End Function

Open in new window


This works in VB but I run into problems when I call this with AJAX. You can see below that I've set it up to give me basic feedback so I know if I'm on the right track, but it just gives me 'error'.

<script type="text/javascript">
        $(document).ready(function () {

            $("#A2Z li").click(function (e) {
                e.preventDefault();
                var Letter = $(this).text();

                $.ajax({
                    type: "GET",
                    url: "HomePage.aspx.vb/GetCategory",
                    data: Letter,
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function (response) {
                        alert("success");
                    },
                    failure: function (response) {
                        alert("failure");
                    },
                    error: function (response) {
                        alert("error");
                    }
                });
            });
        });
</script>

Open in new window

0
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39894775
Can you please post a link to your working sample?

I am not a .net developer, I am sorry if this is a dumb question, but you have the url going to a .vb, is that correct?

url: "HomePage.aspx.vb/GetCategory",

Open in new window


The url should be something you can surf to.  My guess is you need to use the .aspx page.
0
 

Author Comment

by:TimHudspith
ID: 39897212
I'm inching forward with this. My AJAX call is now successfully returning data from my VB function. I had to change the format of the AJAX data parameter to '{letter: "' + Letter + '" }', and point to the correct file - as you said. So the first section of my JQuery looks like this:

$(function () {

            $("#A2Z li").click(function (e) {
                e.preventDefault();
                var Letter = $(this).text();
               
                $.ajax({
                    type: "POST",
                    url: "HomePage.aspx/GetCategory",
                    contentType: "application/json; charset=utf-8",
                    data : '{letter: "' + Letter + '" }',
                    dataType: "json",
                    success: OnSuccess,
                    error: function (xhr, ajaxOptions, thrownError) {
                        alert("Error" + xhr.status);
                    },
                    failure: function (response) {
                        alert(response.d);
                    }
                }); //ajax
            });

Open in new window


The data returned (string data type) looks like this:

<Document Element>
    <Categories>
          <Category>Item A<Category>
    <Categories>
    <Categories>
          <Category>Item B<Category>
    <Categories>
<Document Element>
         
Not very elegant but it's coming through at least. I want to iterate the <Category> nodes and add them as <li> elements to a <ul> I have in my second <div>. The code I have is below but it doesn't work:

function OnSuccess(response) {
                $xml = $($.parseXML(response));
                $xml.find("<Category>").each(function(node){
                    var text = $(node).text();
                    var myli = $('<li>' + text + '</li>');
                    $('#Categories').append(myli);
                })
})

Open in new window

0
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39897247
Work on your xml, it does not appear to be valid.  Everything should be closed in the same order it was opened.
0
 
LVL 52

Accepted Solution

by:
Scott Fell,  EE MVE earned 500 total points
ID: 39897261
Using the jquery docs as an example and after fixing up your xml output, you can try the code below.  Then replace for your response.

var xml = "<DocumentElement><Categories><Category>Item A</Category></Categories><Categories><Category>Item B</Category></Categories></DocumentElement>",
  xmlDoc = $.parseXML( xml ),
  $xml = $( xmlDoc ),
  $Categories = $xml.find( "Categories" );

$Categories.each(function(){
  console.log($(this).text());
});
 

Open in new window

0
 

Author Comment

by:TimHudspith
ID: 39897375
Thanks for all that.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Browsers only know CSS so your awesome SASS code needs to be translated into normal CSS. Here I'll try to explain what you should aim for in order to take full advantage of SASS.
CSS is a visual language used to classify objects and define rules about how they should be displayed. CSS skills aren’t restricted to developers anymore, there is a big benefit to having a basic understanding of the language, regardless of your occ…
In this tutorial viewers will learn how to embed videos in a webpage using HTML5. Ensure your DOCTYPE declaration is set to HTML5: "<!DOCTYPE html>": Use the <video> tag to insert a video. Define the src as the URL of your video; this is similar to …
In this tutorial viewers will learn how to embed custom externally-hosted Google Fonts using the Google Font API in CSS Go to the Google Fonts website at google.com/fonts: Browse or search based on font properties or name to find a suitable font for…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now