What is the best way to add an element from a parent component to an array within a child component in a Vue 3 application?

I am in the process of transitioning from Vue's Options API to the Composition API, and as part of this transition, I have built a small Todo App.

Within App.vue, my code looks like this:

<template>
  <div id="app">
    <div class="card">
      <Header />
      <List />
      <AddTodo @add-todo="addTodo" />
    </div>
  </div>
</template>

<script>
import { ref, onMounted, watch } from 'vue';
import Header from './components/Header.vue';
import List from './components/List.vue';
import AddTodo from './components/Add.vue';

export default {
  name: 'App',
  components: {
    Header,
    List,
    AddTodo,
  },

  methods: {
    addTodo: function (text) {
      let newTodo = {
        done: false,
        text: text,
      };

      if (text.length > 2) {
        console.log(newTodo);
        // this.todos.push(newTodo);
      }
    },
  },
};
</script>

In components/List.vue, you'll find:

<template>
  <ul>
    <Item
      v-for="(todo, index) in todos"
      @toggle-todo="toggleTodo(item, index)"
      @delete-todo="deleteTodo(item, index)"
      :item="todo"
      :key="index"
    />
  </ul>
</template>

<script>
import { ref, onMounted, watch } from 'vue';
import Item from './Item.vue';

export default {
  name: 'List',

  components: {
    Item,
  },

  setup() {
    const todos = ref([
      {
        text: 'Animi, odit facere.',
        done: true,
      },
      {
        text: 'Lorem ipsum dolor sit.',
        done: false,
      },
      {
        text: 'Dolor sit amet consectetur.',
        done: true,
      },
    ]);

    return { todos };
  },

  methods: {
    toggleTodo: function (item, index) {
      this.todos[index].done = !this.todos[index].done;
    },
    deleteTodo: function (item, index) {
      if (confirm('Are you sure?')) {
        this.todos.splice(index, 1);
      }
    },
  },
};
</script>

As shown above, I have defined the todos array within the list component, where it makes the most sense. The main purpose of App.vue is to act as a container for the other components.

Within components/Add.vue, I have created the form used to add an item to the list of todos.

<template>
  <form class="card-footer" @submit.prevent="$emit('add-todo', text)">
    <input type="text" v-model="text" />
    <button type="submit">Add</button>
  </form>
</template>

<script>
import { ref, onMounted, watch } from 'vue';
export default {
  name: 'AddTodo',

  setup() {
    const text = ref('');
    return { text };
  },
};
</script>

Since the todos array is not contained in App.vue, the line this.todos.push(newTodo), which I have commented out, will not work.

I am trying to figure out the best way to push the newTodo object into the todos array within the child component List.vue. Any suggestions on how to achieve this seamlessly?

Answer №1

Create a component List and define props named todos to bind it in the parent component:

<template>
  <div id="app">
    <div class="card">
      <Header />
      <List :todos="todos" @delete-todo="deleteTodo" @toggle-todo="toggleTodo" />
      <AddTodo @add-todo="addTodo" />
    </div>
  </div>
</template>

<script>
import { ref, onMounted, watch } from "vue";
import Header from "./components/Header.vue";
import List from "./components/List.vue";
import AddTodo from "./components/Add.vue";

export default {
  name: "App",
  components: {
    Header,
    List,
    AddTodo,
  },
  data() {
    return {
      isValid: false,
      todos: [
        {
          text: "Animi, odit facere.",
          done: true,
        },
        {
          text: "Lorem ipsum dolor sit.",
          done: false,
        },
        {
          text: "Dolor sit amet consectetur.",
          done: true,
        },
      ],
    };
  },
  methods: {
    toggleTodo: function ( index) {
      this.todos[index].done = !this.todos[index].done;
    },
    deleteTodo: function (index) {
      if (confirm("Are you sure?")) {
        this.todos.splice(index, 1);
      }
    },
    addTodo: function (text) {
      let newTodo = {
        done: false,
        text: text,
      };

      if (text.length > 2) {
        this.isValid = true;
        this.todos.push(newTodo);
      } else {
        this.isValid = false;
      }
    },
  },
};
</script>

In the List component, define todos props and emit events to modify the todos in the parent component:

<template>
  <ul>
    <Item
      v-for="(todo, index) in todos"
      @toggle-todo="toggleTodo( index)"
      @delete-todo="deleteTodo( index)"
      :item="todo"
      :key="index"
    />
  </ul>
</template>

<script>
import Item from './Item.vue';

export default {
  name: 'List',
  props:["todos"],
  components: {
    Item,
  },

  methods: {
    toggleTodo: function ( index) {
      this.$emit('toggle-todo',index);
    },
    deleteTodo: function ( index) {
      this.$emit('delete-todo', index);
    },
  },
};
</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

Use regular expressions and JavaScript to enclose a series of English letters within a wrapper

I am looking to enclose a series or cluster of consecutive English characters within a <span> tag. In simpler terms, I aim to alter the appearance of English language in my writing. Therefore, I need to identify English characters and surround them ...

The nightwatch.js script is halting operations once the test suite has been completed

Recently, I've implemented functional test automation using nightwatch.js. However, I encountered an issue where the test pauses after the test suite is completed, failing to end the process. Below is a snippet of the code: var afterSuite = function( ...

Send information to a different module

I've created a straightforward form component: <template> <div> <form @submit.prevent="addItem"> <input type="text" v-model="text"> <input type="hidden" v-model="id"> <i ...

Attempting to dispatch data from Vue.js event bus

I am attempting to increase the count of quotes by one and also add the text from a textarea to an array. While the text is successfully added to the array, the number of quotes always remains zero. I have tried combining the two actions in one method as w ...

Transform a REACT js Component into an HTML document

I'm working with a static React component that displays information from a database. My goal is to implement a function that enables users to download the React component as an HTML file when they click on a button. In essence, I want to give users ...

What steps should be taken to generate a successful pop-up window post registration in PHP?

beginning section continuation What is the best way to design an effective popup window? ...

Leveraging the useRef hook to adjust the CSS styling of a React component

Currently, I am working on changing the style of a react component by utilizing the useRef hook. So far, I have implemented the useRef hook to reference the specific component whose style I want to modify when clicking on two buttons. Despite my efforts, I ...

I could use some assistance with accessing the /results page on the OMDb API following a movie search by

Presented here is my app.js code. My objective is to develop a movie search feature that enables me to look up a movie in a database and retrieve results for 10 movies related to the entered keyword. For instance, if I input "ALABAMA", the system should re ...

Ways to display or conceal dual views within a single Marionette js region

In my LayoutView, I have set up two regions: the filter region and the main region (Content Region). The main region displays a view based on the selection made in the filter region. Currently, I have a view for the main region called Current Year view. H ...

Implementing Angular 4 to fetch information from a JSON file

As a beginner in Angular, my current task involves loading data from a JSON file upon click, which I have successfully achieved so far. However, I am facing an issue where I'm unable to load the first JSON object before clicking, meaning that I want ...

Modifying the background image of div elements with JQuery in a loop function is ineffective when using Google Chrome

I am facing an issue in my application where I have a for loop to change the background image of two divs. The code snippet is as follows: for (var i = 0; i < length; i++) { $("div_" + (i + 1)).css("background-image", "../imageFile.png"); ...

Importing TypeScript Modules from a Custom Path without Using Relative Paths

If we consider the following directory structure: - functions - functionOne - tsconfig.json - index.ts - package.json - node_modules - layers - layerOne - tsonfig.json - index.ts - index.js (compiled index.ts ...

jQuery image resizing for elements

I have successfully adjusted the images in the gallery to display one per row for horizontal orientation and two per row for vertical orientation. Now, I am facing a challenge in making the images scalable so they can resize dynamically with the window. A ...

What is the best method for combining numerous tiles within a level in Kaboom JS?

Creating a level in kaboomJS with a extensive tile map collisions can sometimes result in slower performance. I'm exploring options to optimize this process, such as potentially merging multiple tiles together so that a whole row of blocks could funct ...

What could be causing my Vue JS and Laravel download feature to produce corrupt files?

Currently, I'm working on a download feature that allows users to download files of all types that they have uploaded. Although the downloading feature is functioning properly - files are appearing in my downloads folder and the file type is recognize ...

Failing to retrieve data from Ajax response

When handling requests in a servlet, the following code snippet processes the request received: Gson gson = new Gson(); JsonObject myObj = new JsonObject(); LoginBean loginInfo = getInfo(userId,userPwd); JsonElement loginObj = gson.toJsonTree(loginInfo) ...

Icons in Semantic-UI: Facing Difficulty in Accessing ("CORS Request Not HTTP"

Here's an example I'm working on: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Understanding - Main</title> <link rel="stylesheet" type="text/css" href="../semantic/dist/semanti ...

Finding the correlation between SVG element IDs and JSON keysUnderstanding how to pair up

Currently, I have an SVG file that can be viewed here. My goal is to present specific data when elements within the SVG are clicked. The data is in JSON format and I am looking to match each ID of an SVG element with a key in the JSON data. If both the key ...

Unable to assign values to textarea and checkbox in MVC5

I am currently facing an issue with setting values in JavaScript + jQuery in MVC 5 for textareas and checkboxes. Here is the JavaScript code I am using: document.getElementById("UpdatetxtDescription").value = "abc"; document.getElementById("Upda ...

Ways to bypass a transition using JavaScript

Hello everyone, I would like to start by apologizing for any mistakes in my English. I have been working on a website, which is currently available here: As you scroll down, the height of the image below the menu decreases. I am trying to make the navig ...