Creating a flexible range of Vue slots within a Render function

I'm currently working on constructing a custom component using a render function.

The component being rendered can receive an unlimited number of slots. For instance, in the following example there are three available slots (named element_1, element_2, element_3).

The code snippet below utilizing Array.reduce() is intended to achieve the same as:

scopedSlots: {
  "element_1": () => createElement('div', 'hello world'),
  "element_2": () => createElement('div', 'hello world'),
  "element_3": () => createElement('div', 'hello world'),
}

This is a simplified version using Array.reduce():

const records = [
  {
    "index": 1,
  },
  {
    "index": 2,
  },
  {
    "index": 3,
  }
]

render: function (createElement) {
  return createElement("replicator-component", {
    attrs: { elements: records.length},

    scopedSlots: records.reduce((a,x) => ({...a, 
      ['element_' + x.index]: 
      () => { createElement( 'div', 'hello world') }}), {})
  });
},

Despite implementing this logic, nothing appears on the screen and no error messages are provided. Does anyone have any suggestions?

Answer №1

The main distinction lies in the way the functions are created within your reduce function.

() => { createElement( 'div', 'hello world') }

versus how they are constructed in the hardcoded version (and also in the forEach loop in @Boussadjra's answer):

() => createElement('div', 'hello world')

In the latter case, the function actually return the created element. This difference is not related to the use of reduce, which is acceptable.

const ReplicatorComponent = {
      template: `<div>
        <h1>replicator-component</h1>
        <slot name='element_1'></slot>
        <slot name='element_2'></slot>
        <slot name='element_3'></slot>
      </div>`
    };

    const records = [
      { "index": 1 },
      { "index": 2 },
      { "index": 3 },
    ];

    Vue.component('my-component', {
      render: function(createElement) {
        return createElement(ReplicatorComponent, {
          attrs: {
            elements: records.length
          },
          scopedSlots: records.reduce((a,x) => ({
            ...a, 
            ['element_' + x.index]: () => 
              createElement( 'div', 'hello world')
           }), {})
        });
      },
    });

    new Vue({
      el: '#app',
      data: () => ({})
    });
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2d5b58486d1f0355">[email protected]</a>/dist/vue.js"></script>

    <div id="app">
      <my-component></my-component>
    </div>

Answer №2

After reading the Vue.js documentation, it seems that scoped slots are meant to be functions that receive props as their argument.

export default {
  render(createElement) {

    // ...
    // some other operations
    // ...

    // Scoped slots defined as
    // { name: props => VNode | Array<VNode> }
    scopedSlots: {
      default: props => createElement('span', props.text)
    },
  }
}

You might want to give this approach a try.

Alternatively, achieving the same result is possible with Vue's new unified v-slot system.

<!-- page component -->
<template>
  <some-component>
    <template v-for="slot in scopedSlots" v-slot:[slot]="props">
      hello {{props}}
    </template>
  </some-component>
</template>

<!-- some-component.vue -->

<template>
  <div>
    <slot v-for="slot in Object.keys($slots)" :name="slot"></slot>
  </div>
</template>

Answer №3

The issue with the reduce method lies in the missing return statement before

createElement('div', 'hello world')
:

Complete illustration

const ReplicatorComponent = {

  template: `
 <div>
    <h1>replicator-component</h1>
    
    <slot name='element_1'></slot>
    <slot name='element_2'></slot>
    <slot name='element_3'></slot>
 </div>
`
}

const records = [{
    "index": 1,
  },
  {
    "index": 2,
  },
  {
    "index": 3,
  }
]



Vue.component('my-component', {
  render: function(createElement) {

    let slotContent = records.reduce((a, x) => ({ ...a,
      ['element_' + x.index]:
        () => {
        return  createElement('div', 'hello world')
        }
    }), {})
    return createElement(ReplicatorComponent, {
      attrs: {
        elements: records.length
      },
      scopedSlots: slotContent
    });
  },
})

var app = new Vue({
  el: '#app',

  data: () => ({})
})
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e5939080a5d7cb9d">[email protected]</a>/dist/vue.js"></script>

<div id="app">
  test

  <my-component></my-component>
</div>

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

Inferring object keys in Typescript using an array as a basis

I am attempting to generate an object with specific keys based on the values within an array. Below is the code snippet: type AllowedKeys = "foo" | "bar" | "baz" interface Options { keys: AllowedKeys[] } interface AllTy ...

Retain the updated select values even when the back button is pressed

My form allows users to filter through different cars with ease and efficiency. When a user selects a "Make," the corresponding "Models" populate in the next dropdown seamlessly. However, an issue arises when a user performs a search and then clicks the ...

Delete the selected background color from custom drop-down lists in versions of Internet Explorer 9 and earlier

In my asp.net application, I have a dropdown element. I am trying to remove the default blue background color that appears when the dropdown is selected, as shown in the image below. I have tried all the solutions provided in this link, but none of them s ...

Using Angular's $scope.$watch to dynamically generate an array and calculate the total based on the ng-model's length

I am working on a form and aiming to develop a 'completion progress tracker'. The idea is that for every input field that is filled in, 10 points will be added to an array. When all ten inputs are completed, the text '100% complete' wil ...

Using MPI for sending a user-defined struct that contains a dynamic array - a guide

Explaining my question with a simple example: I have designed a custom struct that includes a dynamic array. struct my_data_type { int c; int d[]; }; The root process (process 0) possesses an array of such structs, nums[4]. I am interested in pa ...

The npm outdated command reveals that there are some modules missing in the current version

In my package.json file, I have specified babelify version 7.3.0 in the devDependencies section like this: "devDependencies": { ..., "babelify": "7.3.0", ... } Everything seems to be working fine and the dependency is downloaded from npm. However, ...

Tips for setting NgForm value within an Observable and verifying its successful implementation

Exploring the functionality of NgForm, I am testing to validate if the value of a form gets updated when the state of the store changes. @ViewChild('form') form: NgForm; ngOnInit() { this.subscription = this.store.select('shoppingList&apos ...

Can Django capture and store the name of the active user's logged-in browser in the database?

In Django, we already have session details stored in django_session and last_login in the auth_user table. However, I am interested in storing the browser name when a user logs in using their browser in the database. Currently, I can retrieve the browser ...

Tips for avoiding event listeners from being triggered multiple times

Implemented an event listener on an HTML element that was retrieved by className within the render method of highcharts, but for some reason, the listener is being triggered twice. The issue seems to be with the onClick handler in the highchart's rend ...

Making a REST API call with an ID parameter using Angular

I am currently working on an Angular application that interacts with a REST API. The data fetched from the API is determined based on the customer ID, for example: api/incident?customer_id=7. I am unsure of how to incorporate this into the API URL and serv ...

What is the best way to include a property with a name in quotes to an object after it has already been declared?

Is there a way to include a property with a quoted name to an object after its declaration? Here's a simplified scenario: var Obj = {} Instead of: Obj.dog = "Woof!"; I want to achieve: Obj."dog" = "Woof!"; Similar to: var Obj = { "dog" : " ...

How should values be properly stored in a constant using mongoose?

Within my user model, I have included timestamps. I am seeking a way to retrieve the createdAt date and store it in a variable. My initial attempt was: const date = await User.find({ serial: serialId, }).select('-_id createdAt'); The result re ...

Troubleshooting Offline.js

I've implemented Offline.js in my project, a powerful library that notifies users when they lose internet connection. Using version 0.5.0.0 of offline.js, I included offline.min.js in the _Layout Page. While it functions flawlessly in Google Chrome, I ...

Is there a way to lock an element's position on a webpage once it reaches a specific point?

Excuse me if this query seems trivial. I am currently in the process of designing a webpage with a header that has two distinct sections (upper and lower). My aim is for the lower portion of the header to remain fixed on the page as I scroll down. Is the ...

Navigate through nested HTML lists using jQuery

Struggling with a complex HTML code of nested lists on jQuery! I'm utilizing $.get(); to retrieve the HTML and then applying $(data).find(".thelist ul"); To isolate the list which resembles <ul> <li><a href="Draft-Documents-P ...

Information is not readily available through API utilization

For my project, I am implementing a search filter feature. While I can successfully retrieve data by querying the API, no data is displayed when consuming the API on the MVC side. API Controller, [HttpGet("ListExpenseByAccountingSearch/{search}" ...

Tips on searching for an entry in a database with TypeScript union types when the type is either a string or an array of strings

When calling the sendEmail method, emails can be sent to either a single user or multiple users (with the variable type string | string[]). I'm trying to find a more efficient and cleaner way to distinguish between the two in order to search for them ...

Analyzing JSON and organizing arrays with multiple values into groups

In my JSON response, the structure is as follows: { data: [ { attributes:[ { type: 'size', value: '10' }, { type: 'colour', value: 'red' ...

Using the $.ajax function with the PUT method and sending an OPTIONS request

Here is my code snippet: function test(segmentId) { var url = "http://...../api/avoidsegments/123456"; $.ajax({ url: url, type: "PUT", contentType: "application/json", data : { "appID": ig_appID, ...

Having trouble sorting elements in Vue using array sort on mobile devices?

Have you ever encountered an issue with displaying and reordering a list of components across different browsers? I've noticed that while it works flawlessly on my desktop Chrome, it's not functioning properly on mobile Safari or Chrome. Any insi ...