I have an array that looks like so:
files = [
  'Dashboard/Logs/Errors',
  'Dashboard/Logs/Other',
  'Accounts/Main',
]
I want to make it look like this:
navigation = [
  {
    "title": "Dashboard",
    "dropdown": [
      {
        "title": "Logs",
        "dropdown": [
          {
            "title": "Errors",
          },
          {
            "title": "Other",
          }
        ]
      }
    ]
  },
  {
    "title": "Accounts",
    "dropdown": [
      {
        "title": "Main",
      }
    ]
  }
]
I have the following so far:
var navigation = [];
for (var i = 0; i < files.length; i++) {
  var parts = files[i].split('/');
  navigation.push({title: parts[0]});
  for (var j = 1; j < parts.length; j++) {
  }
}
I am having difficulties figuring out a decent way to do this. What I have so far already doesn't work because it creates two objects under navigation each with title: "Dashboard". Any ideas for a clever approach? Thanks :)
To convert an array to an object, use the reduce() method to iterate over the array, passing it an object as the initial value. On each iteration, assign a new key-value pair to the accumulated object and return the result. Copied!
Arrays are a special type of objects. The typeof operator in JavaScript returns "object" for arrays. But, JavaScript arrays are best described as arrays.
This should produce the desired output:
var files = [
  'Dashboard/Logs/Errors',
  'Dashboard/Logs/Other',
  'Accounts/Main',
];
var navigation = [];
// Iterates through a navigation array and returns the object with matching title, if one exists.
var getNavigationObject = function(nav, title) {
  for (var i = 0; i < nav.length; i++) {
    if (nav[i].title == title) {
      return nav[i];
    }
  }
};
// Adds a file to the nav.
// The input is an array of file components (i.e. file.split('/'))
// This works by recursively adding each component of a file.
var addToNav = function (nav, components) {
  var n = getNavigationObject(nav, components[0]);
  if (!n) {
    n = {
      title: components[0]
    };
    nav.push(n);
  }
  if (components.length > 1) {
    n.dropdown = n.dropdown || [];
    addToNav(n.dropdown, components.slice(1));
  }
};
// Actually call `addToNav` on each file.
files.forEach(function(e) {
  addToNav(navigation, e.split('/'));
});
// Produces the result in string form.
JSON.stringify(navigation, null, 2)
This works by recursively checking if a given element already matches the component of the file. If it does, it recurs into that component's "dropdown". Otherwise, it creates it.
This is an approach with a temporary object and some array methods with no search overhead.
var files = ['Dashboard/Logs/Errors', 'Dashboard/Logs/Other', 'Accounts/Main'],
    navigation = function (data) {
        var r = [], o = {};
        data.forEach(function (a) {
            var s = r;
            a.split('/').reduce(function (p, b) {
                if (p.children) {
                    p.value.dropdown = p.value.dropdown || [];
                    s = p.value.dropdown;
                    p = p.children;
                }
                if (!(b in p)) {
                    p[b] = { value: { title: b }, children: {} };
                    s.push(p[b].value);
                }
                return p[b];
            }, o);
        });
        return r;
    }(files);
document.write('<pre>' + JSON.stringify(navigation, 0, 4) + '</pre>');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With