3

New in using Backbone.js and underscore.js, trying to create a list of submenus (second level) for my menulist (first level).

So this is my menulist I created in JSON (which I have confirmed exists by printing it to the browser console):

[
  {
    "name": "Sök kund",
    "path": 
    [
      {
        "subName": "Fondkonto",
        "subPath": "#fondkonto"
      },

      {
        "subName": "Kassakonto",
        "subPath": "#kassakonto"
      },

      {
        "subName": "Nytt sparande",
        "subPath": "#nyttsparande"
      }
    ]
  },

  {
    "name": "Ny kund",
    "path": "#new_customer"
  },
    {
    "name": "Dokument",
    "path": "#documents"
  },

  {
    "name": "Blanketter",
    "path": "#forms"
  }
]

And this is the code I put out to show in my index-file, which for now prints only the first-level:

<script type="text/template" id="menus">
  {{ _.each(menus, function(menu) { }}
    <li><a href="{{= menu.path }}">{{= menu.name }}</a>
      <ul>
        <li>
          <a href="{{= menu.path.subPath }}">{{= menu.path.subName }}</a>
        </li>
      </ul>
    </li>
  {{ }); }}
</script>

And in case you want to know how the view and model/collection are built:

var Menus = require("../collections/menus");

var AllMenus = Backbone.View.extend({

  el: "#menuContent",

  template: _.template(document.getElementById("menus").innerHTML),

  initialize: function() {

    "use strict";

    this.menus = new Menus();
    this.listenTo(this.menus, "reset", this.render);

    this.menus.fetch({
      reset: true,
      url: "./data/menus.json",
      success: function() {
        console.log("Succesfully loaded menus.json file.");
      },
      error: function() {
        console.log("There was some error trying to load and process menus.json file.");
      }
    });
  },

  render: function() {
    console.log( this.menus.toJSON());
    this.$el.html(this.template({ menus: this.menus.toJSON() }));
    return this;
  }

});

var viewMenus = new AllMenus();

Model:

var Menu = Backbone.Model.extend({
  defaults: {
    name: "",
    path: ""
  }
});

module.exports = Menu;

Collection:

var Menu = require("../models/menu");

var Menus = Backbone.Collection.extend({
  model: Menu
});

module.exports = Menus;

Don't mean to paste so much code, but necessary to make this so you understand how I built it up. But I got stuck by trying to show my subMenus with no success to it.

76484
  • 8,498
  • 3
  • 19
  • 30
Alexein
  • 666
  • 1
  • 11
  • 19
  • Sometimes your menu.path is a string and sometimes it's an array. When it's an array you have to use `menu.path[n].subName` notation. [See here for details](http://stackoverflow.com/a/11922384/3585500). Your template will to have to test what `menu.path` is and either print it or _.each it. – ourmandave Feb 03 '16 at 19:34

1 Answers1

1

Your data structure is wrong. You do not want to be switching between Strings and Arrays for your path value. A path should always be a String, and you should create a new property to hold the submenu Array; "submenu" would be a good name. Furthermore, your submenu items should not have subName and subPath as key names. These objects are conceptually the same as their parent objects and they should have the same keys, name and path.

Your revised data structure should look like the following:

var menus = [
    {
        "name": "Sök kund",
        "path": "#",
        "submenu": [
            {
                "name": "Fondkonto",
                "path": "#fondkonto"
            },
            {
                "name": "Kassakonto",
                "path": "#kassakonto"
            },
            {
                "name": "Nytt sparande",
                "path": "#nyttsparande"
            }
        ]
    },
    {
        "name": "Ny kund",
        "path": "#new_customer",
        "submenu": []
    },
    {
        "name": "Dokument",
        "path": "#documents",
        "submenu": []
    },
    {
        "name": "Blanketter",
        "path": "#forms",
        "submenu": []
    }
];

Next, we will update your template to iterate through the top level menu items and, conditionally, their submenus:

<script type="text/template" id="menus">
    {{ _.each(menus, function(menu) { }}
        <li>
            <a href="{{= menu.path }}">{{= menu.name }}</a>
            {{ if (menu.submenu && menu.submenu.length > 0) { }}
                <ul>
                    {{ _.each(menu.submenu, function (submenu) { }}
                        <li><a href="{{= submenu.path }}">{{= submenu.name }}</a></li>
                    {{ }); }}
                </ul>
            {{ } }}
        </li>
    {{ }); }}
</script>

Note: I assume you are doing something like the following to tell Underscore to override the default template settings with a Mustache-style syntax. I copied these settings from this answer.

_.templateSettings = {
    evaluate: /\{\{(.+?)\}\}/g,
    interpolate: /\{\{=(.+?)\}\}/g,
    escape: /\{\{-(.+?)\}\}/g 
};
Community
  • 1
  • 1
76484
  • 8,498
  • 3
  • 19
  • 30