0

I'm trying to loop through a JSON file and append the info to the relevant containers. There's two levels to this, the first level and the second level. The first level has handle types (Victorian, Chrissi, Garda) and the second level has the finish (Brass, Chrome, Satin Nickel). My issue is, when you get to the second level, I'm having difficulty grouping options to the relevant handle type. I hope this makes sense.

So if you click on "Victorian", then it should load the next menu with only "Victorian" finish options. I'm using the data-trigger/data-target attribute to link menus together.

Here's how it should work:

Screenshot for Menu 1 Screenshot for Menu 2

Click the door handle icon, it loads the first menu which gives the following options:-

Title = Choose a family

Options = Victorian - Chrissi - Garda.

You then click "Victorian", and it gives you the victorian finish options, so the next menu should be:-

Title = Choose a finish

Options = Brass, Chrome, Satin Nickel (based on the type you selected)

The same would go for the other options.

Here's the JSON file:

{
    "Families": {
        "title": "Choose a family",
        "options": [
            {
                "name": "Victorian",
                "thumbnail": "/modules/DoorSelector/images/victorian_thumb.jpg",
                "options": {
                    "title": "Choose a finish",
                    "options": [
                        {
                            "name": "Brass",
                            "thumbnail": "/modules/DoorSelector/images/victorian_brass.jpg",
                            "material": "brass",
                            "sku": "DFU0611"
                        },
                        {
                            "name": "Chrome",
                            "thumbnail": "/modules/DoorSelector/images/victorian_chrome.jpg",
                            "material": "chrome",
                            "sku": "DFU0611"
                        },
                        {
                            "name": "Satin Nickel",
                            "thumbnail": "/modules/DoorSelector/images/victorian_satin_nickel.jpg",
                            "material": "satin_nickel",
                            "sku": "DFU0611"
                        }
                    ]
                }
            },
            {
                "name": "Chrissi",
                "thumbnail": "/modules/DoorSelector/images/chrissi_thumb.jpg",
                "options": {
                    "options": [
                        {
                            "name": "Brass",
                            "thumbnail": "/modules/DoorSelector/images/chrissi_brass.jpg",
                            "material": "brass",
                            "sku": "Chrissi"
                        },
                        {
                            "name": "Chrome",
                            "thumbnail": "/modules/DoorSelector/images/chrissi_chrome.jpg",
                            "material": "chrome",
                            "sku": "Chrissi"
                        },
                        {
                            "name": "Satin Nickel",
                            "thumbnail": "/modules/DoorSelector/images/chrissi_satin_nickel.jpg",
                            "material": "satin_nickel",
                            "sku": "Chrissi"
                        }
                    ]
                }
            },
            {
                "name": "Garda",
                "thumbnail": "/modules/DoorSelector/images/garda_thumb.jpg",
                "options": {
                    "options": [
                        {
                            "name": "Brass",
                            "thumbnail": "/modules/DoorSelector/images/garda_brass.jpg",
                            "material": "brass",
                            "sku": "DFU0820"
                        },
                        {
                            "name": "Chrome",
                            "thumbnail": "/modules/DoorSelector/images/garda_chrome.jpg",
                            "material": "chrome",
                            "sku": "DFU0820"
                        },
                        {
                            "name": "Satin Nickel",
                            "thumbnail": "/modules/DoorSelector/images/garda_satin_nickel.jpg",
                            "material": "satin_nickel",
                            "sku": "DFU0820"
                        }
                    ]
                }
            }
        ]
    }
}

This is as far I've come. As you can see, when it comes to the second level options/finish, it's just displaying all of them.

My current HTML:

<div data-target="handles" class="handlesOuterContainer show">
    <div class="levelOneHandles">
        <p class="menuTitle">Choose a family</p>
        <div class="menuOption"><img class="familyThumbnail back" src="/modules/DoorSelector/images/arrow_back.jpg">
        </div>
        <div data-trigger="handles_victorian" class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/victorian_thumb.jpg">
            <p class="familyTitle">Victorian</p>
        </div>
        <div data-trigger="handles_chrissi" class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/chrissi_thumb.jpg">
            <p class="familyTitle">Chrissi</p>
        </div>
        <div data-trigger="handles_garda" class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/garda_thumb.jpg">
            <p class="familyTitle">Garda</p>
        </div>
    </div>
    <div data-target="handles_victorian" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/victorian_brass.jpg">
            <p class="familyTitle">Victorian</p>
        </div>
    </div>
    <div data-target="handles_victorian" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/victorian_chrome.jpg">
            <p class="familyTitle">Victorian</p>
        </div>
    </div>
    <div data-target="handles_victorian" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/victorian_satin_nickel.jpg">
            <p class="familyTitle">Victorian</p>
        </div>
    </div>
    <div data-target="handles_chrissi" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/chrissi_brass.jpg">
            <p class="familyTitle">Chrissi</p>
        </div>
    </div>
    <div data-target="handles_chrissi" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/chrissi_chrome.jpg">
            <p class="familyTitle">Chrissi</p>
        </div>
    </div>
    <div data-target="handles_chrissi" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/chrissi_satin_nickel.jpg">
            <p class="familyTitle">Chrissi</p>
        </div>
    </div>
    <div data-target="handles_garda" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/garda_brass.jpg">
            <p class="familyTitle">Garda</p>
        </div>
    </div>
    <div data-target="handles_garda" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/garda_chrome.jpg">
            <p class="familyTitle">Garda</p>
        </div>
    </div>
    <div data-target="handles_garda" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/garda_satin_nickel.jpg">
            <p class="familyTitle">Garda</p>
        </div>
    </div>
</div>

How the HTML should look:

<div data-target="handles" class="handlesOuterContainer show">
    <div class="levelOneHandles">
        <p class="menuTitle">Choose a family</p>
        <div class="menuOption"><img class="familyThumbnail back" src="/modules/DoorSelector/images/arrow_back.jpg">
        </div>
        <div data-trigger="handles_victorian" class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/victorian_thumb.jpg">
            <p class="familyTitle">Victorian</p>
        </div>
        <div data-trigger="handles_chrissi" class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/chrissi_thumb.jpg">
            <p class="familyTitle">Chrissi</p>
        </div>
        <div data-trigger="handles_garda" class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/garda_thumb.jpg">
            <p class="familyTitle">Garda</p>
        </div>
    </div>
    <div data-target="handles_victorian" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/victorian_brass.jpg">
            <p class="familyTitle">Brass</p>
        </div>
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/victorian_chrome.jpg">
            <p class="familyTitle">Chrome</p>
        </div>
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/victorian_satin_nickel.jpg">
            <p class="familyTitle">Satin Nickel</p>
        </div>
    </div>

     <div data-target="handles_chrissi" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/chrissi_brass.jpg">
            <p class="familyTitle">Brass</p>
        </div>
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/chrissi_chrome.jpg">
            <p class="familyTitle">Chrome</p>
        </div>
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/chrissi_satin_nickel.jpg">
            <p class="familyTitle">Satin Nickel</p>
        </div>
    </div>

     <div data-target="handles_garda" class="levelTwoHandles">
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/garda_brass.jpg">
            <p class="familyTitle">Brass</p>
        </div>
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/garda_chrome.jpg">
            <p class="familyTitle">Chrome</p>
        </div>
        <div class="menuOption"><img class="familyThumbnail" src="/modules/DoorSelector/images/garda_satin_nickel.jpg">
            <p class="familyTitle">Satin Nickel</p>
        </div>
    </div>
</div>

JQuery:

$.getJSON("/modules/DoorSelector/handles.json", function(data){

    var levelOneHandlesContainer = '.levelOneHandles';

    // main container title
    $(levelOneHandlesContainer).append('<p class="menuTitle">'+data.Families.title+'</p>');

    // back button
    $(levelOneHandlesContainer).append('<div class="menuOption"><img src="/modules/DoorSelector/images/arrow_back.jpg" class="familyThumbnail back"></div>');

    // loop through objects
    $.each(data.Families.options, function(index, value) {

        // write options to container
        $(levelOneHandlesContainer).append('<div class="menuOption" data-trigger="handles_'+value.name.toLowerCase()+'"><img src='+value.thumbnail+' class="familyThumbnail" /><p class="familyTitle">'+value.name+'</p></div>');

        // second level
        $.each(this, function(index, value2) {
            $.each(this.options, function(index, value3) {
                $('.handlesOuterContainer').append('<div class="levelTwoHandles" data-target="handles_'+value.name.toLowerCase()+'"><div class="menuOption"><img src='+value3.thumbnail+' class="familyThumbnail" /><p class="familyTitle">'+value.name+'</p></div></div>');
            });
        });
    });

});
Madness
  • 618
  • 2
  • 7
  • 22

3 Answers3

1

Instead of implementing this logic multiple times, it might be easier to create the full Structure (once the JSON is loaded) and add eventListeners, which toggle active-classes, which then show/hide the element. Something like this (not fully functional, just an example of how to do it):

HTML (after created from the configObject)

<div class="level-1">
  <h1>title here</h1>
  <div class="option-1 handle">
    <h2>label option 1</h2>
    <div class="handle-content">
      this is the content of the first handle, shown as soon as the parent gets the .active class
      ...
    </div>
  </div>
  <div class="option-2 handle">
    <h2>label option 2</h2>
    <div class="handle-content">
      this is the content of the second handle, shown as soon as the parent gets the .active class
      ...
    </div>
  </div>    </div>

CSS

.handle-content {
  display: none;
}
.handle.active > .handle-content {
  display: block;
}

JS (execute this AFTER the html has been created in JavaScript)

$(".handles").on('click', function() {
  $(this).toggleClass('active');
});
MattDiMu
  • 4,873
  • 1
  • 19
  • 29
  • Thanks for your input. I'm going to rewrite the logic to this. My issue is, I can't seem to group the first menu to the second based on your selection. My each loop is just outputting everything at once. – Madness Jun 24 '16 at 12:57
  • Creating the structure using for-in loops might be a good idea. See http://stackoverflow.com/questions/2549320/looping-through-an-object-tree-recursively for further informatin/explanation – MattDiMu Jun 24 '16 at 13:07
  • Thanks buddy, I'll take a look. – Madness Jun 24 '16 at 13:10
1

The following code might give you some guidance. Even though i use select and option list the approach should be the same. When you select an item among the options of the first select list a new select list will reveal with options only available under the item selected in the first list (in your data they are all same as "Brass", "Chrome" and "Satin Nickel"). You may assign different finishes for for each main group and they will be listed accordingly.

var data = {"Families":{"title":"Choose a family","options":[{"name":"Victorian","thumbnail":"/modules/DoorSelector/images/victorian_thumb.jpg","options":{"title":"Choose a finish","options":[{"name":"Brass","thumbnail":"/modules/DoorSelector/images/victorian_brass.jpg","material":"brass","sku":"DFU0611"},{"name":"Chrome","thumbnail":"/modules/DoorSelector/images/victorian_chrome.jpg","material":"chrome","sku":"DFU0611"},{"name":"Satin Nickel","thumbnail":"/modules/DoorSelector/images/victorian_satin_nickel.jpg","material":"satin_nickel","sku":"DFU0611"}]}},{"name":"Chrissi","thumbnail":"/modules/DoorSelector/images/chrissi_thumb.jpg","options":{"options":[{"name":"Brass","thumbnail":"/modules/DoorSelector/images/chrissi_brass.jpg","material":"brass","sku":"Chrissi"},{"name":"Chrome","thumbnail":"/modules/DoorSelector/images/chrissi_chrome.jpg","material":"chrome","sku":"Chrissi"},{"name":"Satin Nickel","thumbnail":"/modules/DoorSelector/images/chrissi_satin_nickel.jpg","material":"satin_nickel","sku":"Chrissi"}]}},{"name":"Garda","thumbnail":"/modules/DoorSelector/images/garda_thumb.jpg","options":{"options":[{"name":"Brass","thumbnail":"/modules/DoorSelector/images/garda_brass.jpg","material":"brass","sku":"DFU0820"},{"name":"Chrome","thumbnail":"/modules/DoorSelector/images/garda_chrome.jpg","material":"chrome","sku":"DFU0820"},{"name":"Satin Nickel","thumbnail":"/modules/DoorSelector/images/garda_satin_nickel.jpg","material":"satin_nickel","sku":"DFU0820"}]}}]}};
  seldiv = document.getElementById("selcon");

function createOptions(obj){
  var df = document.createDocumentFragment(),
     len = obj.options.length,
   selel = df.appendChild(document.createElement("select")),
    opel = selel.appendChild(document.createElement("option"));
  opel.value = obj.title || "Choose a finish";
  opel.innerText = obj.title || "Choose a finish";
  opel.hidden = true;
  for (var i = 0; i < len; i++){
    opel = selel.appendChild(document.createElement("option"));
    opel.value = obj.options[i].name;
    opel.innerText = obj.options[i].name;
  }
  return df;
}

function getSubSelection(obj,key){
  var fo = obj.options.find(f => f.name == key);
  !!seldiv.children[1] ? seldiv.replaceChild(createOptions(fo.options), seldiv.children[1])
                       : seldiv.appendChild(createOptions(fo.options));
  seldiv.children[1].addEventListener("change", e => console.log("do something with " + key + " and " + e.target.value));
}

seldiv.appendChild(createOptions(data.Families));
seldiv.children[0].addEventListener("change", e => getSubSelection(data.Families,e.target.value));
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css">
  <script src="script.js" defer></script>
</head>

<body>
  <div id="selcon">
  </div>
</body>

</html>
Redu
  • 25,060
  • 6
  • 56
  • 76
0

Thanks for all your input, I managed to solve this by creating strings for my HTML and appending them as the loops went by. I'm sure this is just one way of doing this.

$.getJSON("/modules/DoorSelector/handles.json", function(data){

    var handlesOuterContainer = '.handlesOuterContainer';
    var mainTitle = '<p class="menuTitle">'+data.Families.title+'</p>';
    var backButton = '<div class="menuOption"><img src="/modules/DoorSelector/images/arrow_back.jpg" class="familyThumbnail back"></div>';
    var upButton = '<div class="menuOption"><img src="/modules/DoorSelector/images/arrow_up.jpg" class="familyThumbnail up"></div>';
    var OuterContainerString = '';          
    var InnerContainerString = '';  
    var level1str = '';
    var level2str = '';
    var level3str = '';
    var level2title ='';

    $.each(data.Families.options, function(index, value) {
        level1str += '<div class="menuOption" data-trigger="handles_'+value.name.toLowerCase()+'"><img src='+value.thumbnail+' class="familyThumbnail" /><p class="familyTitle">'+value.name+'</p></div>';
        $.each(this, function(index, value2) {
            level2str = '';
            if (value.title == "Choose a finish") {
                level1str += '<p class="menuTitle">'+value.title+'</p>';
            }

            level3str = '';
            if (value2.title!= 'undefined'){
                level2title = '<p class="menuTitle">'+value2.title+'</p>';
            }
            $.each(this.options, function(index, value3) {
                if (level2str==''){
                    level2str='<div class="levelTwoHandles" data-target="handles_'+value.name.toLowerCase()+'">' + level2title + upButton;
                }
                level3str += '<div class="menuOption"><img src='+value3.thumbnail+' class="familyThumbnail" /><p class="familyTitle">'+value3.name+'</p></div>';
            });
            InnerContainerString += level2str + level3str + '</div>';
        });
        if (OuterContainerString==''){
                level1str=mainTitle + backButton + level1str;
            }
        OuterContainerString = '<div class="levelOneHandles">' + level1str + '</div>' +  InnerContainerString;
    });
    $(handlesOuterContainer).prepend(OuterContainerString);
});
Madness
  • 618
  • 2
  • 7
  • 22