programmer
programmer

Reputation: 13

Props passed to child component do not render well

I am attempting to pass user id's fetched from an API trough props from parent (App) to child (Modal). The problem is that when I pass the props down to the modal they don't render as they should in the div with the modal-body class, in fact all of them display an id of 1.

App.vue:

<template>
  <div class="container mt-3">
    <table class="table">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">Name</th>
          <th scope="col">Username</th>
        </tr>
      </thead>
      <tbody v-for="user in users" :key="user.id">
        <tr>
          <th scope="row">{{ user.id }}</th>
          <td>{{ user.name }}</td>
          <td>{{ user.username }}</td>
          <td>
            <Modal :id="user.id" />
          </td>
        </tr>
      </tbody>
    </table>
  </div>
  <pre>{{ user }}</pre>
</template>

<script>
import axios from "axios";
import Modal from "@/components/Modal.vue";

export default {
  name: "App",
  components: {
    Modal,
  },
  data() {
    return {
      users: null,
    };
  },
  methods: {
    async load_users() {
      try {
        const { data } = await axios.get(
          "https://jsonplaceholder.typicode.com/users"
        );
        this.users = data;
      } catch (error) {
        console.log("error");
      }
    },
  },
  mounted() {
    this.load_users();
  },
};
</script>

Modal.vue:

<template>
  <!-- Button trigger modal -->
  <button
    type="button"
    class="btn btn-danger"
    data-bs-toggle="modal"
    data-bs-target="#exampleModal"
  >
    Delete
  </button>

  <!-- Modal -->
  <div
    class="modal fade"
    id="exampleModal"
    tabindex="-1"
    aria-labelledby="exampleModalLabel"
    aria-hidden="true"
  >
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
          <button
            type="button"
            class="btn-close"
            data-bs-dismiss="modal"
            aria-label="Close"
          ></button>
        </div>
        <div class="modal-body">
          Are you sure you want to delete user: {{ id }}
        </div>
        <div class="modal-footer">
          <button
            type="button"
            class="btn btn-secondary"
            data-bs-dismiss="modal"
          >
            Close
          </button>
          <button type="button" class="btn btn-primary">Save changes</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "Modal",
  props: ["id"],
};
</script>

The page preview is the following:

Page preview

It does not matter on which Delete button I click the id is always 1.

But when I inspect the props in the Vue Devtools they are different, for the second for example it appears 2 as it should:

Vue Devtools

Any help is appreciated.

Thank you.

Upvotes: 0

Views: 157

Answers (1)

Daniel Storey
Daniel Storey

Reputation: 943

You are rendering 10 modals each with the same id - exampleModal, so it's always the first one which is opened. This is why you are experiencing the behaviour you describe.

However - the real problem is with your structure.

Why are you rendering 10 modals? Why not render one and pass in the respective props?

Something like this:

<template>
  <Modal v-if="modal.isActive" :id="modal.userId" />
  <tbody v-for="user in users" :key="user.id">
    <tr>
      <th scope="row">{{ user.id }}</th>
      <td>{{ user.name }}</td>
      <td>{{ user.username }}</td>
      <td>
        <button
          type="button"
          class="btn btn-danger"
          @click="onClick(user.id)"
        >
          Delete
        </button>
      </td>
    </tr>
  </tbody>
</template>

<script>
import Modal from '@/components/Modal.vue'

export default {
  name: 'App',
  components: {
    Modal,
  },
  data() {
    return {
      users: null,
      modal: {
        isActive: false,
        userId: null,
      },
    }
  },
  methods: {
    onClick(userId) {
      Object.assign(this.modal, { isActive: true, userId })
    },
  },
}
</script>

Upvotes: 1

Related Questions