-5

I did my best not to post a duplicate topic by doing a full search on Stack including some of the suggested Similar Questions on right side panel of this page but could not find a decent post that could help me. Here is a partial list of my search queries:

https://stackoverflow.com/search?q=javascript+access+deep+object+literals (first search query)

Javascript collection

https://stackoverflow.com/search?q=javascript+access+nested+object+literals (second search query)

javascript access chain with nested object literals

Accessing Properties of nested Javascript literals in a for loop ) Javascript - Assigning multiple variables to object properties using curly braces in variable declaration

And now on to my question:

I have a collection of nested definition objects inside an array that I am having difficulty accessing so that I could build a list of anchors from it for my nav bar. I created a function to hoist the array so I can place it anywhere in my code but that is not a problem (I don't think?).

function hoistNav() {
    const nav = [];
    nav[0] = {text: 'HOME', att: {href: 'home.html', class: 'nav', id: 'zero'}};
    nav[1] = {text: 'POSTS', att: {href: 'posts.html', class: 'nav', id: 'one'}};
    nav[2] = {text: 'CONTACT', att: {href: 'con.html', class: 'nav', id: 'two'}};
    return nav;
}

I would like to create links by accessing all attributes inside obj.att like this:

function createAnchor(obj) {
    let el = document.createElement('a');
    el.textContent = obj.text;
    for(let key in obj.att){
        el.setAttribute(key, [key]);
    }
    return el;
}

I also need to create a list of links with another function but that will be ignored for simplicity. A typical sample run should be like this:

let nav = hoistNav();// returns an array of nested objects

let obj = nav[0];// a sample run

createAnchor(obj);// should return: <a href="home.html" class="nav" id="zero">HOME</a>

As it is now the above code isn't working for me. What am I doing wrong? Also is there a best practices way of listing and destructuring all properties including nested ones for objects similar to this?

Modus Tollens
  • 5,083
  • 3
  • 38
  • 46
Jules Manson
  • 214
  • 2
  • 13
  • 1
    On your object under ```hoistNav```, you've got ```id=``` inside of the object. Don't you mean ```id:```? – Matheus Avellar Feb 04 '18 at 19:55
  • 1
    `As it is now the above code isn't working for me.` And you have no errors coming up in your console?. – Keith Feb 04 '18 at 19:56
  • 1
    "isn't working" isn't a useful problem description. What do you see instead? What have you determined using the powerful debugger built into your browser? Debugging is the **first** step (well, maybe after checking documentation for the functions you're using). Please update your question with a [mcve] demonstrating the problem, ideally a **runnable** one using Stack Snippets (the `[<>]` toolbar button; [here's how to do one](https://meta.stackoverflow.com/questions/358992/ive-been-told-to-do-a-runnable-example-with-stack-snippets-how-do-i-do-tha)). – T.J. Crowder Feb 04 '18 at 19:56
  • @Keith Nice catch! I fixed the error but that was not the source of problem I am having. – Jules Manson Feb 04 '18 at 20:04

1 Answers1

1

The line

el.setAttribute(key, [key]);

tries to set the attribute to an array containing the key as its only entry (and thus will set href to "href" since the array will get coerced to string). You probably meant

el.setAttribute(key, obj.att[key]);
// ------------------^^^^^^^

Live Example:

function hoistNav() {
    const nav = [];
    nav[0] = {text: 'HOME', att: {href: 'home.html', class: 'nav', id: 'zero'}};
    nav[1] = {text: 'POSTS', att: {href: 'posts.html', class: 'nav', id: 'one'}};
    nav[2] = {text: 'CONTACT', att: {href: 'con.html', class: 'nav', id: 'two'}};
    return nav;
}

function createAnchor(obj) {
    let el = document.createElement('a');
    el.textContent = obj.text;
    for(let key in obj.att){
        el.setAttribute(key, obj.att[key]);
    }
    return el;
}

let nav = hoistNav();

let obj = nav[0];

let anchor = createAnchor(obj);
document.body.appendChild(anchor);
console.log(anchor.outerHTML);

Side note: Not quite sure what hoistNav is for, you could just make nav global to your code (but not actually global):

"use strict"; // Strict mode to ensure correct handling of function decl in block

// Scoping block to avoid creating globals
{

  // Note use of literal notation
  const nav = [
    {text: 'HOME', att: {href: 'home.html', class: 'nav', id: 'zero'}},
    {text: 'POSTS', att: {href: 'posts.html', class: 'nav', id: 'one'}},
    {text: 'CONTACT', att: {href: 'con.html', class: 'nav', id: 'two'}}
  ];

  function createAnchor(obj) {
      let el = document.createElement('a');
      el.textContent = obj.text;
      for (let key in obj.att) {
          el.setAttribute(key, obj.att[key]);
      }
      return el;
  }

  // Sample run
  let obj = nav[0];
  let anchor = createAnchor(obj);
  document.body.appendChild(anchor);
  console.log(anchor.outerHTML);
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • So even though I did an for(let key in obj.att) I still needed explicitly point to obj.att in el.setAttribute(key, obj.att[key]);? By the way thank you so much. – Jules Manson Feb 04 '18 at 20:09
  • @JulesManson: Yes. `key` is the name of each property in `obj.att`, so `"href"`, `"class"`, etc. You're using that fact by making it the first argument to `setAttribute`. To get the *value* of that property within the loop, you need `obj.att[key]`. (Another option would be to use the new [`Object.entries`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries): `for (const entry of Object.entries(obj.att))` and then use `entry[0]` for the property name and `entry[1]` for the value. But what you have is fine with the change above.) – T.J. Crowder Feb 04 '18 at 20:12
  • 1
    Of course. The for loop just iterates the 'key' variable over the keys of the obj.att object, what you do with them is up to you. It does nothing else by itself. – n0m4d3 Feb 04 '18 at 20:13