1

I have a json doc that I am pulling from to populate a table as well as several other items on a sheet. At the same "level" of the document, I have objects and arrays. I am not sure how to manage displaying the children of the array and the children of the object in Vue.

I have tried using various if statements to show the children of the object and the children of the array separately, but have had no luck.

I can't show the actual code due to privacy but here is an overly simplistic example of the data I am looking at for this problem:

"Pairs": [
        {
            "Value": {
                "Id": "123"
            },
            "Children": [
                "Id": "111",
                "String": {
                    "Value": "999",
                    "Children": [
                        {
                            "Key": "555"
                        },
                        {
                            "Key": "444"
                        },
                    ]
                }
            ]   
        },
        {
            "Value": {
                "Id": "456"
            },
            "Children": [
                "Id": "178",
                "Strings": [
                    {
                        "Value": "845",
                        "Children": [
                            {
                                "Key": "079"
                            },
                            {
                                "Key": "106"
                            }
                        ]
                    },
                        "Value": "578",
                        "Children": [
                            {
                                "Key": "279"
                            },
                            {
                                "Key": "745"
                            }
                        ]
                ]
            ]
        }
]

Then here is my table on the front end in Vue

<table>
    <template v-for="Pair in Pairs">
        <template v-for="Child in Pair.Children">
            <template v-for="String in Child.Strings"> --- PROBLEM HERE
                <tr v-for="Child in String.Children">
                    <td>{{Child.Key}}</td>
                </tr>
            </template>
        </template>
    </template>
</table>  

As you can see from the above example, the first of the objects in the Pairs array has an object called "String" and the second has an array called "Strings". As you may expect, I get an undefined error when I try to access either the object String or the array Strings in my Vue document. I am pretty stuck.

2
  • Could you not use a computed property to get the data into a form that would be more suited to rendering? Commented Jul 17, 2019 at 15:43
  • @skirtle honestly I am not sure. I am not that experienced with Vue and was making my way along okay until I ran into this. Commented Jul 17, 2019 at 15:56

1 Answer 1

2

Typically something like this would be done using a computed property to get the data into a form that is simpler to work with in the template. Something like this:

const Pairs = [
  {
    "Value": {
      "Id": "123"
    },
    "Children": [{
      "Id": "111",
      "String": {
        "Value": "999",
        "Children": [
          {
            "Key": "555"
          },
          {
            "Key": "444"
          }
        ]
      }
    }]
  },
  {
    "Value": {
      "Id": "456"
    },
    "Children": [{
      "Id": "178",
      "Strings": [
        {
          "Value": "845",
          "Children": [
            {
              "Key": "079"
            },
            {
              "Key": "106"
            }
          ]
        },
        {
          "Value": "578",
          "Children": [
            {
              "Key": "279"
            },
            {
              "Key": "745"
            }
          ]
        }
      ]
    }]
  }
]

new Vue({
  el: '#app',
  
  data () {
    return { Pairs }
  },
  
  computed: {
    rows () {
      const pairs = this.Pairs
      const rows = []
      
      for (const pair of pairs) {
        for (const child of pair.Children) {
          const strings = child.Strings || [child.String]
          
          for (const string of strings) {
            const row = []
            rows.push(row)

            for (const innerChild of string.Children) {
              row.push(innerChild.Key)
            }
          }
        }
      }
      
      return rows
    }
  }
})
td {
  border: 1px solid #000;
}
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
  <table>
    <tr v-for="row in rows">
      <td v-for="entry in row">{{ entry }}</td>
    </tr>
  </table>
</div>

I had to add some extra braces into the sample data as it wasn't valid in its original form.

It should be possible to achieve this just with a small change to the template instead but generally its encouraged to keep the template simple and put anything complicated into the JS portion of the component.

<template v-for="String in Child.Strings || [Child.String]">

The code above assumes that one of Strings or String will always exist. If they could both be missing then you might use something like this instead:

<template v-for="String in [].concat(Child.Strings || Child.String || [])">

Or move the logic into a method:

<template v-for="String in getStrings(Child)">
methods: {
   getStrings(Child) {
      // Pull out Strings or [String] as appropriate
   }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you so much for that thorough answer. Can I call this new Vue from an external file? The operation of this particular output is strange and I don't believe I am allowed to change the html file because the program reads everything before it generates the html output. I could be wrong but I don't think I can put any methods or anything in the html file. Hopefully that makes sense as a question.
@PhilT41 I don't know what you're asking. You mention new Vue but that seems to suggest you've misunderstood my answer. I need to use new Vue to get a complete, running example but you wouldn't be adding that part to your code. These should just be changes to existing components.
That's where I am having an issue. I don't have components. I have a bunch of js functions in a js file that are used to return variables which are objects, arrays, or values from the json data, then they are called in the html doc using Vue. I am having a lot of trouble working with this. For example, to get pairs, I would be using:
function getPairs(Data) { try { let pairs = Data.Pairs; for (pair of pairs) { let children = pair.Children; return children; } } catch { logError("Could not determine child"); return {}; } } then in a try function I would run: Data.pairs = getPairs(Data) Finally in the Vue it would be: <template v-for="child of children"> <span v-for="String in child.Strings || [child.String]">{{ String.Value }}</span> </template> This is just an example of usage. I guess I'm not sure how to use your answer to fit with this?
Also, I totally forgot that SO comments don't format for code, apologies for that nightmare of a comment above.
|

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.