1

I am trying something like this:

parent component

     <template v-else>
        <b-card class="d-flex card-shadow">
          <b-list-group-item
            class="d-flex justify-content-between border-0 pl-0"
            v-for="(userExperience, index) in userExperiences"
            :key="index"
          >
              <template>
                <p class="mb-0 fs--1 font-weight-600">
                  {{ userExperience.designation }}
                </p>
              </template>
              <template v-slot:action-buttons>
                <div class="d-flex mt-1">
                  <b-button
                    variant="link"
                    class="p-0 my-0 ml-0 no-underline fs--1 mr-3 text-blue font-weight-600"
                    v-b-modal.edit-experience-modal
                    @click="selectedExperience = userExperience"
                    >Edit or add details</b-button
                  >
                </div>
              </template>
            </summary-container>
          </b-list-group-item>
        </b-card>
        <edit-user-experience :experience="selectedExperience" />
      </template>

<script>
export default {
  data(){
    userExperiences: [],  // some data 
 }
}
</script>

EditUserExperience.vue

<b-modal
      id="edit-experience-modal"
      title="Edit Experience"
      cancelTitle="Discard"
      okTitle="Save"
      button-size="sm"
      hide-header-close
      return-focus="false"
      @ok="handleEditExperience"
      @hide="resetFormData"
    >
      <create-or-edit-experience-form
        v-model="userExperience"
        :experience="experience"
        :handle-submit="handleEditExperience"
        :loading="loading"
      />
</b-modal>

The problem is while changing the values in creatEorEditExperience it mutates the data in userExperience in parent component. To visualize the issue: Screenshot of problem

when I try to change data in 1, it automatically changes data in 2.

What's the point ?

Osman Rafi
  • 938
  • 1
  • 16
  • 37
  • 1
    That's what `v-model` does: two-way binding. If you have two (or more) children and you connect them all to the same property in parent, changing it from one child will change it in the others as well. To have them separated you have to connect each child to a different parent prop. The go-to solution in this case is to have the prop in parent as array, holding the values of all children props. When changing value of one child it only updates that position in the parent array, while the rest remain unchanged. – tao Mar 19 '21 at 03:06
  • but here I not not changing parent array directly. I am coping the element from the array into a new variable and than passing the variable as props to child component. however, how the child component mutating the array ? @tao – Osman Rafi Mar 23 '21 at 12:00
  • 1
    It looks like it's not yet clear to you what *"two-way binding"* means. The child doesn't get a copy of the parent property. It gets a reference to the parent property. When you change the child property, you are actually changing the parent property. And when you're changing the parent property, it changes everywhere it is being used. In your case, it changes in every single child instance, because, by using `v-model` you are passing it to every child. Not a copy of it. It. The very parent property "instance", shall we call it. – tao Mar 23 '21 at 13:45
  • Got it. Can you please make an answer with some demo code to solve this problem ? – Osman Rafi Mar 24 '21 at 11:26
  • 1
    The code you posted is not enough to create a *runnable* [mcve]. Create one using codesanbox.io or similar and I'll modify it for you. – tao Mar 24 '21 at 19:44
  • @tao Sorry for being late. Can you please check this snippet ? https://codesandbox.io/s/two-way-binding-j83vv?file=/src/App.vue. – Osman Rafi Mar 27 '21 at 12:08

1 Answers1

1

As I was expecting, you had more than one problem.

Take your time and compare your sandbox with the one I linked below. Also, if it's not too much to ask, leave yours in its current state (and fork it if you want to make further changes). A comparison between what you had and what I've done might be useful for future users having similar problems.

I removed bloat as much as I could. To fully understand it, read Custom events (particularly the .sync modifier). Also go through computed setters.

Important note: inside EditUserExperience.vue, you'll notice I'm spreading experience into a computed called userExperience. I'm doing it to break reactivity. If I pass experience directly to <user-experience-fields> the changes made in the modal would appear in UserExperience.vue in real time.
But we don't want that, as it would render the Cancel and OK buttons useless. We only want to apply the changes when the user presses OK, which is why I'm spreading the input object into primitives (effectively cloning it).

Here it is: https://codesandbox.io/s/two-way-binding-forked-9ewdc

tony19
  • 125,647
  • 18
  • 229
  • 307
tao
  • 82,996
  • 16
  • 114
  • 150
  • that helped me lot ! Well, in `UserExperience.vue`, should not I use something like this `` to enable conditional rendering for `EditUserExperience` ? Since I only trigger it into the DOM if user clicks the edit button. Does it make any positive impact on performance ? – Osman Rafi Mar 28 '21 at 02:24
  • 1
    @Osman, no you don't need it. `` does not render its contents until its opened, so it already has conditional rendering. Wrapping it into a `v-if` on the same logic is like wrapping content into the same `v-if` multiple times. It would work, but it's not necessary. You're making the browser do more work for no benefit so, in theory, it's bad. In practice, the difference between the two is insignificant. To see it working, look at markup in console: [Closed](https://i.stack.imgur.com/tGLFc.png). [Open](https://i.stack.imgur.com/3KuXg.png). – tao Mar 28 '21 at 15:00
  • 1
    That would be an interesting test: how many times you'd need to wrap some content into the same `v-if` wrapper until we start seeing a measurable performance decrease. I believe it would have to be at least thousands of times, if not more. And you're asking if there's a difference between once and twice. – tao Mar 28 '21 at 15:09
  • can you please answer this question ? https://stackoverflow.com/questions/67091419/how-to-set-up-vue-cors-for-different-domain-api @tao – Osman Rafi Apr 14 '21 at 22:22
  • 1
    @OsmanRafi, What I do know is that you have to configure the server properly (you can't fix it from client side). The server needs to allow requests from the domain you're calling from. But I don't know in detail how to do it (it's backend stuff) and it largely depends on what runs the server (specific for each type of server: apache, nginx, iis, etc...). For a proper understanding of CORS, I recommend [this resource](https://cors-errors.info/). It helped me understand the principle and solve my issue, every time I had a CORS problem. – tao Apr 15 '21 at 04:56
  • I know it against the terms, but sorry for my temptation, Can I get your email or LinkedIn Id ? @tao – Osman Rafi Apr 15 '21 at 08:50
  • @Osman, my email is made public in my github account, which is linked to this account (visible in my profile). – tao Apr 15 '21 at 09:17