Different ways to display a static content list using Vue's named slots

I'm struggling to make the following setup work:

My parent template

<comp>
  <a href="#" slot="links">link 1</a>
  <a href="#" slot="links">link 2</a>
</comp>

and in my component comp, the template looks like this:

<ul class="comp">
  <li class="comp-item"><slot name="links"></slot></li>
</ul>

Right now, all my anchors are going into that single li tag (which is expected), but I want to have multiple li elements for each named slot I insert, like so:

<ul class="comp">
  <li class="comp-item"><a href="#" slot="links">link 1</a></li>
  <li class="comp-item"><a href="#" slot="links">link 2</a></li>
</ul>

Is there a way to achieve this without using scoped slots? Since my content is pure HTML, I feel it's unnecessary to wrap static content inside props to render them.

Most Vue UI frameworks seem to require using another custom component for each list item, which seems like overkill for this issue. Is there an alternative approach?

Answer №1

You can easily achieve this using a render function.

Vue.component("comp", {
  render(h){
    let links = this.$slots.links.map(l => h('li', {class: "comp-item"}, [l]))
    return h('ul', {class: 'comp'}, links)
  }
})

Check out this example in action:

console.clear()

Vue.component("comp", {
  render(h){
    let links = this.$slots.links.map(l => h('li', {class: "comp-item"}, [l]))
    return h('ul', {class: 'comp'}, links)
  }
})

new Vue({
  el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <comp>
    <a href="#" slot="links">link 1</a>
    <a href="#" slot="links">link 2</a>
  </comp>
</div>

Alternatively, you can utilize a small utility component to render vNodes with a template like so:

Vue.component("vnode", {
  functional: true,
  render(h, context){
    return context.props.node
  }
})

Vue.component("comp", {
  template: `
    <ul class="comp">
      <li class="comp-item" v-for="link in $slots.links"><vnode :node="link" /></li>
    </ul>
  `
})

new Vue({
  el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <comp>
    <a href="#" slot="links">link 1</a>
    <a href="#" slot="links">link 2</a>
  </comp>
</div>

Answer №2

If you want to utilize scoped slots instead of regular slots, here is how you can do it:

Within your comp component, ensure that it receives a prop called links, which should be an array of links (initialized as a custom option). Iterate through the links and pass each individual link as data to the slot, similar to passing props to a component.

Vue.component("comp", {
  template: `
    <ul class="comp">
      <li class="comp-item" v-for="link in links">
          <slot v-bind="link"></slot>
      </li>
    </ul>
  `,
  props: ["links"]
})

new Vue({
  el: "#app",
  // custom static option , accessed using vm.$options.links
  links: [
      {text: "link1"},
      {text: "link2"},
      {text: "lin3"}
  ]
})

In the parent component where the comp component is being used, make sure to use a <template> element with the special attribute slot-scope, indicating that it is a template for a scoped slot.

The value assigned to slot-scope will be the name of a temporary variable holding the props object passed from the child:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <comp :links="$options.links">
      <template slot-scope="link">
          <a href="#">{{link.text}}</a>
      </template>
  </comp>
</div>

You can view a working example on this JSFiddle link

Answer №3

If you prefer not to store your data in an array and display a list using v-for

You have the option to place all of them directly in the component without using a slot:

<ul class="custom-comp">
  <li class="comp-item"><a href="#">link 1</a></li>
  <li class="comp-item"><a href="#">link 2</a></li>
</ul>

Alternatively, you can use a slot:

<custom-comp>
  <ul class="custom-comp" slot="links">
    <li class="comp-item"><a href="#">link 1</a></li>
    <li class="comp-item"><a href="#">link 2</a></li>
  </ul>
</custom-comp>

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

Tips for incorporating an additional dataset bar using chart.js

I'm having a bit of trouble trying to modify the following script. Currently, it only displays one bar per label, but I need it to show 2 bars per label. Despite my numerous attempts using different variations with and without commas and "{}", I can&a ...

Tips for Sending Emails from an Ionic Application without Utilizing the Email Composer Plugin

I am attempting to send an email from my Ionic app by making an Ajax call to my PHP code that is hosted on my server. Below is the code for the Ajax call: $scope.forget = function(){ $http({ method: 'POST', url: 's ...

Creating a multipart/form-data request using JavaScript/jQuery

After much searching and experimentation, I have been trying to understand the process of constructing a request to be sent using something similar to $.ajax({ contentType: "multipart/form-data", type: "POST", data: ...

Having trouble making the menu stay at the top of the page in IE7

Check out the demo here: http://jsfiddle.net/auMd5/ I'm looking to have the blue menu bar stay fixed to the top of the page as you scroll past it, and then return to its original position when scrolling back up. This functionality works in all brows ...

Tips on transforming two same-length arrays into a single array of objects using JavaScript

I have a dilemma with two arrays that have been structured as follows: arr1 = [10, 20, 30, 40, 50]; arr2 = ['x', 'y', 'z', 'w', 'v']; My goal is to utilize JavaScript in order to transform these arrays of ...

Having trouble with asynchronous JSON calls in JavaScript when setting async to false

I'm having trouble figuring out what I'm doing wrong in this scenario. The issue is that I can't seem to reassign the variable poster_path with the fetched poster-path from the JSON call. What's puzzling to me is that I even tried setti ...

Utilizing multiple optional key values in Vue Router

When working with vue-router, I am faced with the challenge of creating a route that can handle multiple optional parameters. For example, the route needs to be able to handle scenarios like: /something/a/1/b/2/c/3 /something/a/1/b/2 /something/a/1/c/3 /s ...

Transitioning from ng-repeat filter to Typescript

As I migrate my project from AngularJS to modern Angular 8, one of the steps is converting JavaScript code to TypeScript. During this process, I encountered a challenging issue with the `ng-repeat` filter feature. Initially, my HTML template looked like t ...

Troubleshooting: Dealing with the issue of the inability to locate a module using the "@" path during VueJS unit testing

I encountered an issue with a component: <template> <span :class="lightClassName"> <i class="fas fa-circle markIcon" /> </span> </template> <script> import { EnumAttendanceStatuses } from "@/enums"; export ...

The PasswordResetView in Django using Vue.js encounters a 403 Forbidden error when attempting to post with Axios due to an

I'm currently working on building a unique Email Restore page in the frontend using Vue.js. My goal is to send email input data via Axios to /api/v1/accounts/password_reset/, essentially utilizing the original ResetPasswordView as an endpoint instead ...

Issues with integrating VUE frontend with PHP backend and API

Apologies for any language mistakes as English is not my native tongue. I hope my message is clear enough. We are in the process of developing a user system where users, upon logging in, can perform various actions such as joining events, updating their p ...

The data in AngularJS is not being successfully incorporated into the service

Utilizing angularjs and ajax, I am attempting to retrieve data from a webservice and pass it to the controller. To accomplish this, I am using a holder (a factory method or service). The setup works fine without the webservice, but when trying to fetch dat ...

Tips for displaying Ajax response in a modal popup

I have a link that, when clicked, sends an AJAX request and successfully receives a response in the form of an HTML file, which I then append to a div. However, I want to display this div as a modal popup and I have attempted the following: In the HTML fi ...

Issue regarding ports: deployment of a project using vue.js and node.js on Heroku encountered errors

Having issues deploying my fullstack project. It builds and runs smoothly locally, but on Heroku, I encounter a 503 Service Unavailable error after running the 'git push heroku master' command and the subsequent automatic build process. This coul ...

What methods are available to modify the colors in an Apex bar chart?

Currently, I am in the process of constructing a bar chart using react, mui, and apex-chart. One specific requirement I have is to modify the colors of the bars displayed on the chart. Despite my efforts in attempting various solutions, I have been unsucce ...

Problem with the WP Rocket helper plugin that excludes JS scripts from Delay JS only at specific URLs

Looking for assistance with a helper plugin that excludes scripts from "Delay Javascript Execution"? You can find more information about this plugin here. The specific pages where I want to exclude slick.min.js and jquery.min.js are the home page and tabl ...

The argument provided needs to be a function, but instead, an object instance was received, not the original argument as expected

I originally had the following code: const util = require('util'); const exec = util.promisify(require('child_process').exec); But then I tried to refactor it like this: import * as exec from 'child_process'; const execPromis ...

Integrating SCORM with Vue.js and Laravel for dynamic e-learning functionality

We are currently working on integrating Articulate SCORM files into our platform. Our setup involves using Laravel for the API and vue.js for the front end. Successfully, we have managed to store the file both in the database and the file system. We are no ...

Locating Elements in Protractor: Exploring Nested Elements within an Element that is Also a Parent Element Elsewhere on the Page

<div class="base-view app-loaded" data-ng-class="cssClass.appState"> <div class="ng-scope" data-ng-view=""> <div class="ng-scope" data-ng-include="'partial/navigation/navigation.tpl.html'"> <div class="feedback-ball feedback- ...

How can you target the current component and use createElement within VueJS?

My goal is to gain access to the current component and generate a div within it once the component is ready. The following is the code snippet for my component, which demonstrates my attempt to target the this element and create a new div within it using ...