How can a parent component update a child component's prop value in VUE?

I'm facing an issue with managing dynamic props in Vue with TypeScript. Below is my parent component:

<script setup lang="ts">
const friends = [
  {
    id: "emanuel",
    name: "Emanuella e",
    phone: "08788",
    email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1a7f777b746f7f76767b5a7d777b73..."",
    isFavorite: true,
  },
  {
    id: "denta",
    name: "Denta W",
    phone: "08789",
    email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1d797873697c5d7a707c74...:"",
    isFavorite: false,
  },
];

function toggleFavorite(friendId:any){
  console.log(friendId);
  const identifiedFriend= friends.find(friend=>friend.id === friendId);
  if(identifiedFriend!=undefined){
    identifiedFriend.isFavorite=!identifiedFriend.isFavorite
  }
  console.log(identifiedFriend);
}
</script>

<template>
  <section>
    <header><h1>Test Friends</h1></header>
    <ul>
      <friend-container
        v-for="friend in friends"
        :id="friend.id"
        :key="friend.id"
        :name="friend.name"
        :phone="friend.phone"
        :email="friend.email"
        :isFavorite="friend.isFavorite"
        @toggle-favorite="toggleFavorite"
      >
      </friend-container>
    </ul>
  </section>
</template>

Below is my child component:

<template>
  <li>
    <h2>{{ name }} {{ isFavorite ? "(Favorite)" : "" }}</h2>
    <button @click="toggleFavorite">Toggle Favorite</button>
    <button @click="toggleDetails">Show details</button>
  
    <ul v-if="detailAreVisible">
      <li><strong>Phone: </strong>{{ phone }}</li>
      <li><strong>email: </strong>{{ email }}</li>
    </ul>
  </li>
</template>

<script setup lang="ts">

import { ref} from 'vue';

const detailAreVisible=ref(false);

const props = defineProps<{
  id: { type: String; required: true };
  name: { type: String; required: true };
  phone: { type: String; required: true };
  email: { type: String; required: true };
  isFavorite: Boolean
}>();

const emit=defineEmits<{
    (e: 'toggle-favorite', value: any): void
}>()
function toggleDetails(){
    detailAreVisible.value=!detailAreVisible.value
}

function toggleFavorite(){
    emit("toggle-favorite",props.id);
  
}
</script>

I have updated the props data in the parent component using emit event handling. However, the isFavorite value in my child component still cannot be changed. Did I miss something or how should I handle it? Sorry, I'm new to Vue.

Answer №1

To ensure that the state of friends is responsive to changes, it is recommended to declare it with the reactive function in Vue. Additionally, for a more concise code, consider using only v-bind with multiple attributes since the property names match the keys in the state:

<script setup lang="ts">
import {reactive} from 'vue'

const friends = reactive([
  {
    id: "emanuel",
    name: "Emanuella e",
    phone: "08788",
    email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f1949c909f84949d9d90b1969c90989ddf929e9c">[email protected]</a>",
    isFavorite: true,
  },
  {
    id: "denta",
    name: "Denta W",
    phone: "08789",
    email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d9bdbcb7adb899beb4b8b0b5f7bab6b4">[email protected]</a>",
    isFavorite: false,
  },
]);

function toggleFavorite(friendId:any){
  console.log(friendId);
  const identifiedFriend= friends.find(friend=>friend.id === friendId);
  if(identifiedFriend != undefined){
    identifiedFriend.isFavorite = !identifiedFriend.isFavorite
  }
  console.log(identifiedFriend);
}
</script>

<template>
  <section>
    <header><h1>Test Friends</h1></header>
    <ul>
      <friend-container
        v-for="friend in friends"
        :key="friend.id"
         v-bind="friend"
        @toggle-favorite="toggleFavorite"
      >
      </friend-container>
    </ul>
  </section>
</template>


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

Which is the better choice for simply invoking a service method - subscribe or toPromise?

When implementing the search method below, I simply assign the value of BehaviourSubject in the service. However, I am unsure whether it is possible to execute this operation without using either subscribe() or toPromise() after the .pipe() block in the ...

Can Mustache syntax {{}} be used to inject a Vue component?

I am dealing with a markdown file that includes YAML frontmatter. Within the frontmatter, I am trying to reference a component like so: --- title: Hello world component: <component-a></component-a> --- Lorem ipsum... My goal is to reference th ...

Using VueJS to dynamically hide or show elements based on the selection made in a form

I'm facing a challenge with displaying device information based on selection from a form select element in Vue.js. I have an array of devices that I render using a v-for loop, but I can't figure out how to filter and display them according to the ...

Exploring the directories: bundles, lib, lib-esm, and iife

As some libraries/frameworks prepare the application for publishing, they create a specific folder structure within the 'dist' directory including folders such as 'bundles', 'lib', 'lib-esm', and 'iife'. T ...

A guide on transforming a Firebase Snapshot child into a personalized object in a React Native environment

I'm looking for a way to retrieve data from Firebase Realtime Database and display it in FlatList format. What is the most efficient method for extracting the child value and converting it into a custom object? For example: class CustomObject { ...

Showing the state on a different page: A step-by-step guide

I'm currently in the process of creating a model for a real estate website. On the homepage, users can choose between 'rent' or 'purchase' using a select option and view the results on that page. I have successfully stored the sear ...

Ways to address a buffered data problem in Websocket Rxjs. When trying to send a message, it is not being received by the server and instead is being stored in a

Currently, I am utilizing Websocket Rxjs within my application. The connection is successfully established with the server, and upon subscribing to it, all data is received in an array format. However, when attempting to send data back to the server, it se ...

Twilio SMS Notification: The Class extension value provided is not a valid constructor or null

When attempting to utilize Twilio for sending SMS messages in a Vue.js project, I encountered an error while accessing Tools -> Developer Tools. <template> <div> <input type="text" v-model="to" placeholder="Ph ...

Conceal and reveal elements using v-if

Check out my fiddle: DEMO creating a new Vue instance: { el: '#app', data: { modules: ['abc', 'def'] } } I am looking for a way to hide or show elements using v-if based on the values in an array called modules[]. ...

Retrieving data from a nested JSON array using AngularJS

I am struggling to navigate the intricate nested tree view of child items within a JSON array. I have been grappling with this challenge for days, trying to figure out how to access multiple children from the complex JSON structure. Can someone provide g ...

Can Vue recognize array changes using the Spread syntax?

According to Vue documentation: Vue is unable to detect certain changes made to an array, such as: Directly setting an item using the index, for example vm.items[indexOfItem] = newValue Modifying the length of the array, like vm.items.length = newLength ...

Learn how to render a single element with multiple child elements within separate `<td>` tags in a table row using React

I'm just starting out with React and I have a code snippet that I'm using to render an HTML table in a component. Is there a more optimized way to achieve this? bodyItems = sorted.map((data) => [ data.employerName, data.sectors.map((sector ...

Creating React components dynamically using the number of objects passed as props

When attempting to create components based on the number specified in an object's files property, I keep encountering an error indicating that the parent component has too many children. If the files property is set to 5, does anyone have a solution ...

Leveraging 'v-for' to construct dropdown options in HTML and setting the key as the value for each option

Here is some HTML code using Vue syntax: <select id='select-id' > <option selected disabled value=''>Select Option</option> <option v-for="(value, key) in object">{{ key }} - {{ value}}</option> </s ...

Guide to aligning a component in the middle of the screen - Angular

As I delve into my project using Angular, I find myself unsure about the best approach to rendering a component within the main component. Check out the repository: https://github.com/jrsbaum/crud-angular See the demo here: Login credentials: Email: [e ...

What steps can be taken to resolve the TS5023 error that arises when including "allowImportingTsExtensions" in the tsconfig.json file?

While working on my React project, I've encountered a specific error that reads: Could not parse tsconfig.json. Please ensure it contains valid JSON syntax. Details: error TS5023: Unknown compiler option 'allowImportingTsExtensions'. I tr ...

How can aframe be integrated and utilized in Vue applications?

Trying to integrate aframe with vue-cli has been a challenge for me. I've experimented with adding aframe directly in the index.html file, as well as importing it in my top level main.js file, but I haven't had any success in getting Vue to recog ...

What is the process for incorporating a hyperlink into an object's property value?

I'm looking for a way to add a hyperlink to the value of an object's property in vue.js. Specifically, I want the word "London" in the desc property to be a hyperlink. As a newcomer to Vue, I have been unable to find a solution. Here is my templ ...

Custom Mui table sizes - personalized theme

By implementing custom sizes for the Table component in Material UI, I have extended the Table size prop with the following declaration: declare module '@mui/material' { interface TablePropsSizeOverrides { relaxed: true large: true } ...

Error: Observable<any> cannot be converted to type Observable<number> due to a piping issue

What causes the type error to be thrown when using interval(500) in the code snippet below? const source = timer(0, 5000); const example = source.pipe(switchMap(() => interval(500))); const subscribe = example.subscribe(val => console.log(val)); V ...