Unexpected behavior encountered when looping through a list in Vue <template> markup

I am currently using my app.js to dynamically generate tabs like the code snippet below:

Input:

<tabs>
    <div>
        <a slot="header">Tab 1</a>
        <article slot="content">
            <h2>Tab 1 Content</h2>
            <p>Lorem ipsum dolor sit amet</p>
        </article>
    </div>
    <div>
        <a slot="header">Tab 2</a>
        <article slot="content">
            <h2>Tab 2 Content</h2>
            <p>Sed ut perspiciatis unde</p>
        </article>
    </div>
    <div>
        <a slot="header">Tab 3</a>
        <article slot="content">
            <h2>Tab 3 Content</h2>
            <p>Neque porro quisquam est</p>
        </article>
    </div>
</tabs>

For each div, there is one tab where the header slot represents the title of the tab and the content slot contains the tab content.

The challenge is to transform the input above into the following output:

Output:

<section class="tabs">
    <nav class="tabs-nav">
        <ul class="tabs-list">
            <li class="tabs-listitem">
                <a class="tabs-trigger">Tab 1</a>
            </li>
            <li class="tabs-listitem">
                <a class="tabs-trigger">Tab 2</a>
            </li>
            <li class="tabs-listitem">
                <a class="tabs-trigger">Tab 3</a>
            </li>
        </ul>
    </nav>
    <div class="tabs-body">
        <article>
            <h2>Tab 1 Content</h2>
            <p>Lorem ipsum dolor sit amet</p>
        </article>
        <article>
            <h2>Tab 2 Content</h2>
            <p>Sed ut perspiciatis unde</p>
        </article>
        <article>
            <h2>Tab 3 Content</h2>
            <p>Lorem ipsum dolor sit amet</p>
        </article>
    </div>
</section>

To achieve this transformation in my render function or Vue template, I need assistance on iterating through slots using this.$slots.header without getting undefined values.

If you have any insights or suggestions on how to approach this problem, it would be greatly appreciated. Thank you!

Answer №1

This Vue loop example showcases basic functionality that may be helpful.

Vue.component('tabs', {
  props: ['tabs'],
  template: `
  <section class="tabs">
      <nav class="tabs-nav">
          <ul class="tabs-list">
              <li v-for="item in tabs" :key="item" class="tabs-listitem">
                  <a class="tabs-trigger">{{item.title}}</a>
              </li>
          </ul>
      </nav>
      <div class="tabs-body">
          <article v-for="item in tabs" v-html="item.content" :key="item"></article>
      </div>
  </section>`
})

var app = new Vue({
  el: '#app',
  data () {
    return {
      tabs: [
        {
          title: 'Tab 1',
          content: '<h1>Tab 1 Content</h1>'
        },
        {
          title: 'Tab 2',
          content: '<h1>Tab 2 Content</h1>'
        },
        {
          title: 'Tab 3',
          content: '<h1>Tab 3 Content</h1>'
        }
      ]
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6c1a19092c5e4259425d5b">[email protected]</a>/dist/vue.js"></script>
<div id="app">
  <tabs :tabs="tabs"></tabs>
</div>

Answer №2

The property known as $slots includes slots that represent immediate children, meaning any nested named slots (like the ones in your example) would not be included. In this scenario, you would only have access to the default slot containing the wrapper divs, specifically the tabs. If working with the render function, it becomes necessary to manually process the tab's children to extract inner slots for generating the specified HTML structure:

render(h) {
  const tabs = this.$slots.default;
  const headers = tabs && tabs.map(tab => tab.children.filter(x => x.data.attrs['slot'] === 'header'));
  const bodies = tabs && tabs.map(tab => tab.children.filter(x => x.data.attrs['slot'] === 'content'));

  if (!tabs || !bodies) {
    return h('div', 'No tabs');
  }

  return h('section', [
    h('nav', { class: 'tabs-nav' }, [
      h('ul', { class: 'tabs-list' },
        headers.map(header => h('li', { class: 'tabs-listitem' }, header)))
    ]),
    h('div', { class: 'tabs-body' }, bodies)
  ]);
}

Check out the demo here

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Choosing the appropriate data type for form data on the server

Seeking assistance on uploading an audio file to my server using the following method: var fd = new FormData(); fd.append('fname', 'test.wav'); fd.append('data', soundBlob); $.ajax({ type: 'POST', url: &apos ...

Transform the appearance of the navigation bar background upon scrolling in Bootstrap

I am trying to change the background color of my navigation bar from transparent to black when scrolling. I want it to function like this template: . Previous attempts using solutions from How to Change Navigation Bar Background with Scroll? and Changing n ...

Easy way to eliminate empty elements following a class using jQuery

I'm encountering a situation where I have a group of elements following a specific class that are either empty or contain only white space. <div class="post-content"> <div class="slider-1-smart"> --- slider contents --- < ...

Modifying the status using retrieved JSON information

My goal is to retrieve data from an external API and use it to update the state of my app. Although I can see the data in the console, the state of my app remains unchanged when I try to run setState. class App extends Component { state={ jobs:[] ...

Creating a dynamic nested list in HTML using JavaScript with data retrieved from a JSON source

I'm trying to generate a dynamic nested ul\li list from a JSON array. IMPORTANT! While I can use jQuery for this transformation, it's in a node.js environment where DOM access is restricted and I must work with a string. The depth of the a ...

Sending various values from ASP.NET to a javascript function

I am currently attempting to pass multiple parameters (eventually 4 total) into a JavaScript function from my ASP.NET code behind. In the ASCX file, I have defined the function as follows: function ToggleReportOptions(filenameText, buttonText) { /*stuff ...

js problem with assigning the expression result of a regex operation

Let's talk about a JavaScript string scenario: "h" + "e" + "l" + "l" + "o" This particular string is extracted from a regex query, enclosed within [..], and here's how I'm isolating it: var txt = '"blahblahblah["h"+"e"+"l"+"l"+"o"]fo ...

Detect mouse events using electron even when the window is not in focus

Is there a way to detect mouse events such as hover and click even when the Electron window is not the active focus? I want to ensure that my buttons' hover and click effects still function properly. Currently, I find that I have to switch back to th ...

Increase the object name in localStorage to save information entered in input fields

For testing purposes only - do not use for production. I am experimenting with storing data from 3 different input fields (text and numbers) in localStorage. My goal is to have the values increment every time the form is submitted. However, I am encounte ...

Passing references in React to parent components

Struggling to adopt the react way of thinking, I'm facing an issue with invoking the .submit() method of the form component. Within a material-ui Dialog, buttons are passed via the actions property. Now, I need to trigger the .submit() method of the ...

Looking to create an Ajax Control Toolkit AutoCompleteExtender with results that are "similar"?

The Ajax AutoCompleteExtender is all set up and functioning properly, linked to a webservice that fetches results from SQL. Now, I want to enhance the user experience by providing similar results in case they can't recall the exact name of what they& ...

Maintain the scrollable feature of the element until the final content is reached

I'm struggling to come up with the right keywords to search for my issue. I've tried using Google, but it seems my search terms are not effective. The problem I'm facing involves two relative div elements with dynamic content. This means th ...

Creating a responsive slider in CSS that matches this specific design

Looking to create a responsive sidebar based on this specific design Link to design on Figma Key focus is implementing the "< 4/12 >" functionality and ensuring it is responsive Current code can be found here: Code on JSFiddle enter code ...

Using computed properties with Nuxt's `head` property can result in error messages being displayed

While utilizing Nuxt.js, I am using head() { } method to configure SEO metadata. However, when accessing computed properties within this method, Vetur displays the following message: Property 'domain' does not exist on type 'CombinedVueInst ...

How to remove the black border on a material-ui button

I am currently working with the material-ui datepicker and buttons. Whenever I click on the datepicker icon to select a date or any of the buttons, I notice a black border appearing. How can I remove this black border from the design? https://i.sstatic.ne ...

Creating a POST Endpoint in Express JS

Hey there! Can someone help me out with creating a basic login script for an app using Express JS? I've been working on a POST function to handle this task, but unfortunately, when I try to echo back the parameters being passed (testing via Postman), ...

Update the delivery status of an Uber Eats order using the Uber Eats API

Hey there, I hope everyone is doing well. I need to update the delivery status of orders on Uber Eats through my app. I am in partnership with Uber Eats and using the Update Delivery Status API for this purpose. The API requires the scope eats.store.order ...

The function setState, along with all other functions, is not defined within the promise's .then() method

Currently, I am in the process of developing a React application that retrieves data from Firebase. Whenever I use the function below to delete a record, my attempt to refresh the page and display an updated view without the deleted record fails: deleteW ...

Retrieve the parent object from the policy field type

Imagine you have a query that retrieves a list of products like the one below. query ProductList() { products() { name price stockQuantity isAvailable @client # This field exists only locally } } In addition, you've set up a type ...

CoffeeScript equivalent of when the document is loaded

Recently, I've been delving into Coffeescript for my web application, but I'm encountering a frustrating issue. The methods are not being called until I manually reload the page. I suspect that the missing piece may be the $(document).ready(func ...