2

I have tried this but it doesn't work. I'm trying to make Dynamic Menu from jQuery json data. I have insert preview below.

I'm working on fully custom UI, so I plan not to use jQuery.UI.

var data = {
        menu: [{
            name: 'Women Cloth',
            link: '0',
            sub: null
        },{
            name: 'Men Cloth',
            link: '1',
            sub: [{
                name: 'Arsenal',
                link: '0-0',
                sub: null
            }, {
                name: 'Liverpool',
                link: '0-1',
                sub: null
            }, {
                name: 'Manchester United',
                link: '0-2',
                sub: null
            }]
        }]};

    var getMenuItem = function (itemData) {
        var item = $("<li>", {
            class: 'has-children',
            id: itemData.id
        }).append(
        $("<a>", {
            href: itemData.link,
            html: itemData.name,
            id: itemData.id + '-links',
        }));
        if (itemData.sub) {
            var subMenuItem = $("<li>", {
            class: 'has-icon'
            }).append(
            $("<a>", {
                href: itemData.link,
                class: 'submenu-title',
            }));
            var subList = $("<ul>", {
                class: 'secondary-dropdown',
            });
            $.each(itemData.sub, function () {
                subList.append(subMenuItem(this));
            });
            item.append(subList);
        }
        return item;
    };
    var $menu = $("#Menu");
    $.each(data.menu, function () {
        $menu.append(
            getMenuItem(this)
        );
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="Menu"></ul>

Below is the output I needed.

<li class="has-children" id="ID">
    <a id="ID-links" href="links">Women Clothing</a>
    <ul class="cd-secondary-dropdown is-hidden">
        <li class="go-back"><a>Back</a></li>
        <li class="has-icon"><a class="submenu">submenu 1</a></li>
        <li class="has-icon"><a class="submenu">submenu 2</a></li>
        <li class="has-icon"><a class="submenu">submenu 3</a></li>
        <li class="has-icon"><a class="submenu">submenu 4</a></li>
        <li class="has-icon"><a class="submenu">submenu 5</a></li>
    </ul>
</li>

<li class="has-children" id="ID">
    <a id="ID-links" href="links">Men Clothing</a>
    <ul class="cd-secondary-dropdown is-hidden">
        <li class="go-back"><a>Back</a></li>
        <li class="has-icon"><a class="submenu">submenu 1</a></li>
        <li class="has-icon"><a class="submenu">submenu 2</a></li>
        <li class="has-icon"><a class="submenu">submenu 3</a></li>
        <li class="has-icon"><a class="submenu">submenu 4</a></li>
        <li class="has-icon"><a class="submenu">submenu 5</a></li>
    </ul>
</li>

2 Answers 2

2

You were not using $.each function as you were supposed. you are passing this as args to your function. this will undefined in the function getMenuItem

In you $.each function you need to have args as index and data. Index return the number of each key in you JSON & data is the one you need to pass to your function.

Also in your cd-secondary-dropdown you need to add ul only once and not in $.each.

I have fixed up your code and is exactly working as you wanted in your output above.

Run snippet below to see it working.

var data = {
  menu: [{
    name: 'Women Cloth',
    link: '0',
    sub: null
  }, {
    name: 'Men Cloth',
    link: '1',
    sub: [{
      name: 'Arsenal',
      link: '0-0',
      sub: null
    }, {
      name: 'Liverpool',
      link: '0-1',
      sub: null
    }, {
      name: 'Manchester United',
      link: '0-2',
      sub: null
    }]
  }]
};

var getMenuItem = function(itemData) {

  var item = $("<li>", {
    class: 'has-children',
    id: itemData.id
  }).append(
    $("<a>", {
      href: itemData.link,
      html: itemData.name,
      id: itemData.id + '-links',
    }));


  if (itemData.sub) {
    //Add UL once only
    var subList = $("<ul>", {
      class: 'secondary-dropdown',
    }); 
    //Append go back
    var goBack = $("<li>", {}).append(
      $("<a>", {
        href: '',
        html: 'Go back',
        class: 'go-back',
      }));
    //Append go back
    subList.append(goBack);
    $.each(itemData.sub, function(index, data) {
      //Sub menu
      var subMenuItem = $("<li>", {
        class: 'has-icon'
      }).append(
        $("<a>", {
          href: data.link,
          html: data.name,
          class: 'submenu-title',
        }));

      subList.append(subMenuItem);
    });

    item.append(subList);
  }
  return item;
};


var $menu = $("#Menu");
$.each(data.menu, function(index, data) {
  $menu.append(getMenuItem(data));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="Menu"></ul>

Sign up to request clarification or add additional context in comments.

6 Comments

Hi, how about the go-back li that i mention about with the aspected output.
one more question, if i want to calculate the height. for example, $('.has-children') height = 240px / (how many main categories items)
@Kelvin you need to divide / by the .length of the total categories. Would you mind accepting the answer please if i have helped and solved your question ?
@Kelvin You can try using .length like: $('.has-children') height() / $('.main-categories').length - This is just rough example only. But this week you can achieve this!. Ideally i would suggest if you can post another question add add main-categories html - so someone can help with the exact
actually is the same, just calculate how many <li class="has-children" id="ID">, from the code above, Women's Cloth and Men Cloth is Main Categories.
|
1

is this what you are trying to do? if yes, this is a way of doing it without jQuery

let data = {
        menu: [{
            name: 'Women Cloth',
            link: '0',
            sub: null
        },{
            name: 'Men Cloth',
            link: '1',
            sub: [{
                name: 'Arsenal',
                link: '0-0',
                sub: null
            }, {
                name: 'Liverpool',
                link: '0-1',
                sub: null
            }, {
                name: 'Manchester United',
                link: '0-2',
                sub: null
            }]
        }]};

const MENU_COMPONENT  = document.querySelector('#Menu');

for (const field in data.menu) {


const LI= document.createElement('li');
LI.setAttribute('class', 'has-children');
MENU_COMPONENT.appendChild(LI);
const LINK = document.createElement('a');
LINK.setAttribute('href', data.menu[field].link);
LINK.innerText = data.menu[field].name;
LI.appendChild(LINK);

const UL = document.createElement('ul');
UL.setAttribute('class', 'cd-secondary-dropdown is-hidden');
LI.appendChild(UL);

let SUBLEVEL_DATA = data.menu[field].sub;

  for (const sub in SUBLEVEL_DATA) {
    const SECOND_LEVEL_LI = document.createElement('li');
    SECOND_LEVEL_LI.setAttribute('class', 'has-icon');
    UL.appendChild(SECOND_LEVEL_LI);
    const SECOND_LEVEL_LINK = document.createElement('a');
    SECOND_LEVEL_LINK.setAttribute('href', SUBLEVEL_DATA[sub].link);
    SECOND_LEVEL_LINK.className = 'submenu';
         SECOND_LEVEL_LINK.innerText = SUBLEVEL_DATA[sub].name;
     SECOND_LEVEL_LI.appendChild(SECOND_LEVEL_LINK);
  }
  
}
<ul id="Menu"></ul>

1 Comment

how about the go-back li that i mention about with the aspected output.

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.