Daniel Coates
Daniel Coates

Reputation: 73

JSON jQuery Menu Problems

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"
    }
  ]
}

Upvotes: 2

Views: 197

Answers (2)

Daniel Coates
Daniel Coates

Reputation: 73

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;
    });
  });
};

Upvotes: 1

DrunkDevKek
DrunkDevKek

Reputation: 469

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 :)

Upvotes: 0

Related Questions