[SOLVED] Nested v-for in q-list/q-item to process nested array



  • In my next revision of a help component I came across this issue:

    I have defined a constant, nested arrray that I traverse in a q-drawer q-list consisting of q-items with router links. The array holds DOM ids that are passed through router link props to the help component, which scrolls to that id, rendering the right help information for the help topic selected through the q-item in the q-list.

    Here is a small extract of the nested array structure:

    const hilfeVerzeichnis = [
      {
        id: "1.0",
        überschrift: "Heading 1",
        unterVerzeichnis: [
          {
            id: "1.1",
            überschrift: "Subheading 1.1"
          },
          {
            id: "1.2",
            überschrift: "Sub-Heading 1.2"
          }
        ]
      },
    ...]
    

    The extract example has only 2 levels of id/headings, but in reality it could be 3 levels. So I naively wanted to traverse this array with 3 nested v-fors. I’m successful with the first level (display the q-items in q-list in q-drawer from the array, at click of q-item pass them to the help component through a prop update, which is a param of the router link). That happens through a function setRouteAndId, which is simple and does not play a role for the v-for issue:

    setRouteAndId(id) {
          this.$router.replace("/Hilfe/" + id);
          this.selectedHelpTopicId = id;
        }
    

    Now, as soon as I try to add the next level of v-fors, to traverse the sub-heading level, I get all kinds of “undefined” errors at runtime.

    Here is my current template with 2 v-fors in a q-list, which is part of q-drawer:

          <q-list bordered>
            <h6>Hilfeverzeichnis</h6>
            <q-item
              v-for="hilfeThemaEbene1 in this.hilfeVerzeichnis"
              :key="hilfeThemaEbene1.id"
              class="q-my-sm"
              clickable
              @click="setRouteAndId(hilfeThemaEbene1.id)"
              v-ripple
            >
              <q-item-section>
                <q-item-label>
                  <strong>{{ hilfeThemaEbene1.id }} {{ hilfeThemaEbene1.überschrift }}</strong>
                </q-item-label>
              </q-item-section>
                <q-item
                  v-for="hilfeThemaEbene2 in this.hilfeThemaEbene1.unterVerzeichnis"
                  :key="hilfeThemaEbene2.id"
                  class="q-my-sm"
                  clickable
                  @click="setRouteAndId(hilfeThemaEbene2.id)"
                  v-ripple
                >
                  <q-item-section>
                    <q-item-label>
                      <strong>{{ hilfeThemaEbene2.id }} {{ hilfeThemaEbene2.überschrift }}</strong>
                    </q-item-label>
                  </q-item-section>
                </q-item
            </q-item>
          </q-list>
    

    The code displays correctly the links for the first level of headings/ids in my table, but fails to process the second level down, at the nested v-for (which seems to make almost certainly no sense, but found no better choice):

    v-for=“hilfeThemaEbene2 in this.hilfeVerzeichnis.unterVerzeichnis”

    The current version of the code has a (similarly wrong?) v-if before the v-for, and the warning message for that says “[Vue warn]: Property or method “unterVerzeichnis” is not defined on the instance but referenced during render…” I tried variations of that code, with and without v-if wrappers around, but fail to do this properly.

    Alternatively, I’m thinking to “flatten” the nested array, which would allow me to traverse it with one v-for, but I would loose the hierarchy (from which I want to add some indentation and different markup for the q-items, depending on the hierarchy level - that code is not yet included).

    So my question remains whether nested v-fors are supported for this use case, and how the second v-for level down in the hierarchy needs to be done.

    I looked at [https://vuejs.org/v2/guide/list.html], but found no example for nested v-fors.



  • I found what I did wrong in the second, nested v-for. I changed that from
    v-for=“hilfeThemaEbene2 in this.hilfeVerzeichnis.unterVerzeichnis”
    to
    v-for=“hilfeThemaEbene2 in this.hilfeThemaEbene1.unterVerzeichnis”
    And removed the <div>s that had a wrong v-if.

    Corrected the code correspondingly in the last append. This solution was inspired by some code I saw here: https://codepen.io/blikblum/pen/ZQRRmm.

    With that change, there is a slight improvement: Now all the headings and first level of sub-headings are shown as links in the q-list (since the second level of v-for was processed correctly now).

    HOWEVER, at the UI in q-drawer, the second level of q-item links are nested into their parent q-items on the first level, which makes the rendered list of q-item links unusable!

    This is not very surprising, since the q-items in the template are also nested…

    So I’m still lost how can I get all those links showing up as a linear q-list in the q-drawer…



  • Issue is SOLVED: I solved this last nesting issue through re-introducing <div>s and moving each of the v-fors from their <q-item>s to their own wrapper <div>s.
    This allowed me to add a third inner level of v-for for the third level of help information.
    The “table of help content” in the drawer, made up from q-items with router links, formats very nicely now.
    And it is not hardcoded, but loaded from the nested array that controls all help topics and their nesting.
    I’m happy with it for now. Next possible improvement is to use q-expansion-items replacing those q-items.

    Looking back, the above errors look a bit stupid, but that’s what happens if one deals with this stuff for the first time.
    Hope my experience serves others to master Quasar. It’s a great piece of work.



  • Forgot to paste in the final working code (part of my q-drawer):

    <q-list bordered>
            <h6>Hilfeverzeichnis</h6>
            <div v-for="hilfeThemaEbene1 in this.hilfeVerzeichnis" :key="hilfeThemaEbene1.id">
              <q-item class="q-my-sm" clickable @click="setRouteAndId(hilfeThemaEbene1.id)" v-ripple>
                <q-item-section>
                  <q-item-label>
                    <strong>{{ hilfeThemaEbene1.id }} {{ hilfeThemaEbene1.überschrift }}</strong>
                  </q-item-label>
                </q-item-section>
              </q-item>
    
              <div
                v-for="hilfeThemaEbene2 in hilfeThemaEbene1.unterVerzeichnis"
                :key="hilfeThemaEbene2.id>
                <q-item
                  inset-level="0.4"
                  class="q-my-sm"
                  clickable
                  @click="setRouteAndId(hilfeThemaEbene2.id)"
                  v-ripple
                >
                  <q-item-section>
                    <q-item-label>{{ hilfeThemaEbene2.id }} {{ hilfeThemaEbene2.überschrift }}</q-item-label>
                  </q-item-section>
                </q-item>
    
                <div
                  v-for="hilfeThemaEbene3 in hilfeThemaEbene2.unterVerzeichnis"
                  :key="hilfeThemaEbene3.id"
                >
                  <q-item
                    inset-level="0.8"
                    class="q-my-sm"
                    clickable
                    @click="setRouteAndId(hilfeThemaEbene3.id)"
                    v-ripple
                  >
                    <q-item-section>
                      <q-item-label>{{ hilfeThemaEbene3.id }} {{ hilfeThemaEbene3.überschrift }}</q-item-label>
                    </q-item-section>
                  </q-item>
                </div>
              </div>
            </div>
          </q-list>
    

Log in to reply