Search code examples
javascriptjavascript-objectsobject-literaldestructuringclient-side-scripting

Javascript accessing nested properties of an object literal


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?


Solution

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