2

I have created a script to add a menu to a site that I am working on, it pulls the menu data from a JSON file and inserts it into the page. When the page loads, the sub-menu doesn't open when clicked :|

So I added one to the HTML file to see if there was an issue there and that one works perfectly.

I have the dev site live here https://ketchup.dev.danielcoates.co.uk/ (No longer available 30/03/17) if you need to see more of the code.

The Menu HTML

<div class="side-content">
  <ul class="nav-main">
    <li id="menu-0">
      <a class="nav-submenu" data-toggle="nav-submenu" href="#">
        <i class="si si-user"></i>
        <span class="sidebar-mini-hide">User Profile</span>
      </a>
      <ul>
        <li>
            <a href="base_pages_profile.html">Profile</a>
        </li>
        <li>
            <a href="base_pages_profile_v2.html">Profile v2</a>
        </li>
        <li>
            <a href="base_pages_profile_edit.html">Profile Edit</a>
        </li>
      </ul>
    </li>
  </ul>
</div>

The Menu Code

$(document).ready(function() {
  $.getJSON('/menu/menu.json', function(data) {

    // convert json into array
    var menu = [];
    $.each(data, function(k, v){
      for (var i = 0; i < v.length; i++) {
        menu.push(v[i]);
      };
    });

    for(var i=0; i < menu.length; i++) {
      if(menu[i]['type'] == 'item') {
        $('.nav-main').append('<li id="menu-' + menu[i]['id'] + '"></li>');
        $('#menu-' + menu[i][['id']]).append('\
          <a href="' + menu[i]['link'] + '">\
            <i class="' + menu[i]['icon'] + '"></i>\
            <span class="sidebar-mini-hide">' + menu[i]['title'] + '</span>\
          </a>'
        );

      } else if(menu[i]['type'] == 'header') {
        $('.nav-main').append('<li id="menu-' + menu[i]['id'] + '"></li>');
        $('#menu-' + menu[i][['id']]).append('\
          <li class="nav-main-heading">\
            <span class="sidebar-mini-hide">' + menu[i]['title'] + '</span>\
          </li>'
        );

      } else if(menu[i]['type'] == 'submenu') {
        $('.nav-main').append('<li id="menu-' + menu[i]['id'] + '"></li>');
        $('#menu-' + menu[i][['id']]).append('\
          <a class="nav-submenu" data-toggle="nav-submenu" href="#">\
            <i class="' + menu[i]['icon'] + '"></i>\
            <span class="sidebar-mini-hide">' + menu[i]['title'] + '</span>\
          </a>'
        )
      } else if(menu[i]['type'] == 'submenu-item') {
        $('#menu-' + menu[i]['parent']).append('<ul><li><a href="/test">Test</a></ul>');
      };
    };
  });
});

The JSON

{
  "menu":
  [
    { "id": 1,
      "parent": 0,
      "type": "item",
      "active": false,
      "title": "Dashboard",
      "icon": "si si-speedometer",
      "link": "/dashboard"
    },
    { "id": 2,
      "parent": 0,
      "type": "header",
      "active": false,
      "title": "Pocurement",
      "icon": false,
      "link": false
    },
    { "id": 3,
      "parent": 0,
      "type": "item",
      "active": false,
      "title": "Suppliers",
      "icon": "si si-notebook",
      "link": "/suppliers"
    },
    { "id": 4,
      "parent": 0,
      "type": "item",
      "active": true,
      "title": "Duty Calculator",
      "icon": "si si-calculator",
      "link": "/app/duty_calculator"
    },
    { "id": 5,
      "parent": 0,
      "type": "header",
      "active": false,
      "title": "Products",
      "icon": false,
      "link": false
    },
    { "id": 6,
      "parent": 0,
      "type": "submenu",
      "active": false,
      "title": "Manage Products",
      "icon": "si si-tag",
      "link": "#"
    },
    { "id": 7,
      "parent": 6,
      "type": "submenu-item",
      "active": false,
      "title": "List Products",
      "icon": false,
      "link": "/products/list"
    }
  ]
}
1

2 Answers 2

1

I have found a solution, tho not an elegant one :/

The problem seems to come from the functionality for the sub menu opening residing inside a function called uiNav inside the main \assets\js\app.js file. I think this is being initialised before the JSON menu is loaded.

By placing that code inside the menu.js call back and placing it in the uiNav function it solves the issue.

The final code that resides in the app.js file is

var uiNav = function() {
  $.getJSON('/menu/menu.json', function(data) {

    // convert json into array
    var menu = [];
    $.each(data, function(k, v){
      for (var i = 0; i < v.length; i++) {
        menu.push(v[i]);
      };
    });

    for(var i=0; i < menu.length; i++) {
      if(menu[i]['type'] == 'item') {
        $('.nav-main').append('<li id="menu-' + menu[i]['id'] + '"></li>');
        $('#menu-' + menu[i][['id']]).append('\
          <a href="' + menu[i]['link'] + '">\
            <i class="' + menu[i]['icon'] + '"></i>\
            <span class="sidebar-mini-hide">' + menu[i]['title'] + '</span>\
          </a>'
        );

      } else if(menu[i]['type'] == 'header') {
        $('.nav-main').append('<li id="menu-' + menu[i]['id'] + '"></li>');
        $('#menu-' + menu[i][['id']]).append('\
          <li class="nav-main-heading">\
            <span class="sidebar-mini-hide">' + menu[i]['title'] + '</span>\
          </li>'
        );

      } else if(menu[i]['type'] == 'submenu') {
        $('.nav-main').append('<li id="menu-' + menu[i]['id'] + '"></li>');
        $('#menu-' + menu[i][['id']]).append('\
          <a class="nav-submenu" data-toggle="nav-submenu" href="#">\
            <i class="' + menu[i]['icon'] + '"></i>\
            <span class="sidebar-mini-hide">' + menu[i]['title'] + '</span>\
          </a>'
        )
      } else if(menu[i]['type'] == 'submenu-item') {
        $('#menu-' + menu[i]['parent']).append('<ul><li><a href="/test">Test</a></ul>');
      };
    };

    // When a submenu link is clicked
    jQuery('[data-toggle="nav-submenu"]').on('click', function(e){
        // Get link
        var $link = jQuery(this);

        // Get link's parent
        var $parentLi = $link.parent('li');

        if ($parentLi.hasClass('open')) { // If submenu is open, close it..
            $parentLi.removeClass('open');
        } else { // .. else if submenu is closed, close all other (same level) submenus first before open it
            $link
                .closest('ul')
                .find('> li')
                .removeClass('open');

            $parentLi
                .addClass('open');
        }

        // Remove focus from submenu link
        if ($lHtml.hasClass('no-focus')) {
            $link.blur();
        }

        return false;
    });
  });
};
Sign up to request clarification or add additional context in comments.

Comments

0

You are trying to iterate over the value of each array's key, instead of its length.

Try replacing for (var i = 0; i < v.length; i++) by for (var i = 0; i < data.length; i++) in order to loop on the whole array.

Let me know if that worked! I could have missed something :)

3 Comments

Changing v.length to data.length stops the JSON menu loading completely, and breaks the page even further. The code I have above will output the menu to the page, but won't allow me to access the submenu.
Yeah I realized seconds after posting that it was not going to fix anything, sorry! Looking further into it
I found a solution, I have posted it as an answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.