Unable to change the main data of slot object in VueJS

When running this demo and selecting "modify in child", the text will be updated. However, if you choose "modify top level through slot", the text remains unchanged, and attempting to click the other button afterwards will not work.

Is there a way to update a top-level property of the slot? For instance, a boolean or string. It seems that modifying it directly within the child component works fine, but doing so through the slot does not.

If the data object in the child contains nested properties, it is possible to modify a sub-property through the slot (see the original version of this question for a demonstration), but updating a top-level property seems to be problematic.

const Child = {
  template: `<div>
          {{ object }}
          <slot name="named" v-bind="object">
          </slot>
          <button @click="click">child</button>
        </div>`,
  data() {
    return {
      object: {
        string: "initial"
      }
    }
  },
  methods: {
    click() {
      this.object.string = "modified in child"
    }
  }
}
new Vue({
  components: {
    Child,
  },
  template: `
          <div class="page1">
            <Child>
              <template v-slot:named="slot">
                <button @click="click(slot)">modify top level through slot</button>
              </template>
            </Child>
          </div>`,
  methods: {
    click(slot) {
      slot.string = "updated top level through slot"
    }
  }
}).$mount('#app')
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fe888b9bbeccd0c8d0cfcf">[email protected]</a>/dist/vue.min.js"></script>

Answer №1

When you encounter a situation where you are unable to modify the root object but can alter its properties, it's likely due to the exposed slot variable being a shallow clone. This means that the top level reference differs from the object reference in the child component. To illustrate this, I have included a console.log and enclosed .string in an object display. Try clicking the child and then modify buttons for demonstration.

Your attempt to expose the child component's state to the parent component so you can manipulate the child's state directly goes against Vue's intended usage. The recommended approach is to elevate the state higher up in the component tree and pass down deterministic props through your component hierarchy.

Directly referencing and modifying state in child components is considered an antipattern. It is advised to design components with deterministic behavior to promote standalone and reusable components while also yielding performance benefits.

For further insights, refer to this explanation:
Both Vue and React operate on similar concepts.

const Child = {
  template: `<div>
          {{ object }}
          <slot name="named" v-bind="object">
          </slot>
          <button @click="click">child</button>
        </div>`,
  data() {
    return {
      object: {
        string: {x: "initial"}
      }
    }
  },
  methods: {
    click() {
      window.ChildObjectReference = this.object;
      this.object.string.x = "modify in child"
    }
  }
}
new Vue({
  components: {
    Child,
  },
  template: `
          <div class="page1">
            <Child>
              <template v-slot:named="slot">
                <button @click="click(slot)">modify top level through slot</button>
              </template>
            </Child>
          </div>`,
  methods: {
    click(slot) {
      console.log( `slot: `,slot, `\nobject = `, window.ChildObjectReference,
         `\nslot !== ref as object: `, slot === window.ChildObjectReference,
         `\nslot.string === ref object.string: `, slot.string === window.ChildObjectReference.string)
    }
  }
}).$mount('#app')
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5721223217657961796666">[email protected]</a>/dist/vue.min.js"></script>

Explore the interaction between slot and parent component below:

const Child = {
  template: `<div>
          {{ object }}
          <slot name="named" v-bind="object">
          </slot>
          <button @click="click">child</button>
        </div>`,
  data() {
    return {
      object: {
        string: "initial"
      }
    }
  },
  methods: {
    click() {
      this.object.string = "modify in child"
    }
  }
}
new Vue({
  data: {
    topLevelObject: { property: "top level initial" }
  },
  components: {
    Child,
  },
  template: `
          <div class="page1">
            <Child>
              <template v-slot:named="slot">
                <div>this is v-bind:'object' on slot 'named' put into variable slot: {{ slot }}</div>
                <button @click="click(slot)">modify top level through slot</button>
              </template>
            </Child>
            Top Level state: {{ topLevelObject }}
          </div>`,
  methods: {
    click(slot) {
      this.topLevelObject.property = "slot.string pushed to top level: " + slot.string
    }
  }
}).$mount('#app')
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0670736346342830283737">[email protected]</a>/dist/vue.min.js"></script>

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

Changing array indices in JavaScript by splicing elements

I'm experiencing a curious issue that seems to involve overwriting array indices after splicing, or at least that's what I suspect. This problem arises in a small game project built using phaser 2 - essentially, it's a multiplayer jumping ga ...

Activate automatic click or force trigger JavaScript function

In the MVC view I am working with, there is a form that allows for file submission. //Submit file <% using (Html.BeginForm("MethodName","ControllerName", FormMethod.Post, new { enctype = "multipart/form-data"})) { %> <input type=" ...

Modifying the color of multiple cells simultaneously

I'm currently facing an issue where I need to change the cell color of multiple cells at once, all stored within a specific range. However, I only want certain cells to change based on a particular condition. While I can manually change each cell, it& ...

Is it necessary to have n_ if I've already set up lodash?

After some research, I came across a recommendation to install lodash. However, upon visiting the lodash website, they suggest that for NodeJS, n_ should be installed instead. Are both necessary? Is one more comprehensive than the other? Do I even need eit ...

Why is my code throwing an error stating "Unable to assign value to innerHTML property of null"?

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <div class="container">Lorem ipsum</div&g ...

Update the href attribute with values from the form fields

My current project involves creating a form with 5 input fields: Service type Number of days Number of children Number of adults I want to dynamically change the value of a button based on these variables using JavaScript. Here is my code so far: JS ...

obtain data from an array using Angular 5

i need assistance with retrieving values from an array. Below is my code snippet: this.RoleServiceService.getRoleById(this.id).subscribe(data => { this.roleData.push(data['data']); console.log(this.roleData); }) however, the resulting ar ...

The Tauri JS API dialog and notification components are failing to function, resulting in a null return value

Currently, I am getting acquainted with the tauri framework by working on a small desktop application. While testing various tauri JS API modules, most of them have been functioning as expected except for the dialog and notification modules. Whenever I tes ...

javascript - determine whether a hyperlink has been accessed

Is there a method to determine if a link has been visited? In Firefox, the color of a link changes after clicking on it, which leads me to believe it is possible. Edit: This question pertains to a Firefox extension, so I am unable to modify the HTML or CS ...

Having trouble with the full-screen feature not functioning properly?

I am currently in the process of creating a custom video player and I need to include a full-screen button. However, when I click on it, the video does not expand to fill up the entire screen. I am using javascript, css3, and html5 for this project. Any as ...

React Native, state values are stagnant

I created an edit screen where I am attempting to update the post value through navigation v4 using getParams and setParams. However, when I modify the old value and click the save button, it does not update and no error is displayed. The old values still ...

The Serverless Function appears to have encountered a critical error and has

Currently, I am in the process of deploying a backend Express app on Vercel. The server is primarily focused on handling a mailing API using Nodemailer. Below is my package.json: Here is my server.js file: import express from "express"; import ...

Ways to automatically refresh a page in Javascript after a short period of user inactivity

Similar Question: How Can I Modify This Code To Redirect Only When There Is No Mouse Movement I am looking to update a web page automatically if the user is inactive, specifically through key presses or mouse clicks using Javascript. ...

What is a unique method for creating a wireframe that replicates the structure of a square grid without using interconnected nodes

Currently, I am in the process of designing the wire frame styles for human body OBJs and my goal is to achieve a wire frame similar to the image below. In the following lines, you will find the code snippets that illustrate how I create the wire frame alo ...

Ways to display jQuery values as HTML text

Trying to concatenate the HTML text with the values of item.certificate_name has been a challenge for me. I've experimented with various methods, but none of them seem to work. The specific line I'm referring to is where I wrote . I have alread ...

What is the best way to prevent double clicks when using an external onClick function and an internal Link simultaneously

Encountering an issue with nextjs 13, let me explain the situation: Within a card component, there is an external div containing an internal link to navigate to a single product page. Using onClick on the external div enables it to gain focus (necessary f ...

Enhance accessibility: Improving screen reader and tab focus behavior with vue-router

It seems that focus resetting and screen readers detecting route changes are not integrated into vue-router. I understand why Vue might have omitted this feature, considering the varying use cases, but I am surprised by the lack of information on accessib ...

What is the solution for fixing the "Invalid Element Type" error?

Hey there! I'm currently working on creating a Twitter clone using React, but I've run into an error that's giving me some trouble. The error message reads: "Element type is invalid: expected a string (for built-in components) or a class/fu ...

Error: The function of forEach is not applicable to todoList

_serilizedList(todoList){ let serialized = '*My to-dos:*\n'; todoList.forEach((t, i)=> { serialized += '*${i}* - ${t}\n'; }); return serialized; } Unexpected TypeError: todoList.forEach is not ...

Issue encountered while attempting to pass a function to a child component in React (Uncaught error: TypeError - result is not a function)

How can I pass the result obtained from an API call made in a child component to the parent component? Let's take a look: PARENT COMPONENT: const Parent = () => { function logResult(resultFromAPI) { console.log(resultFromAPI); } ...