1

I have two components - component A and component B that are siblings.

I need to change the boolean value inside of Component-A from the Watcher in Component-B.

Component A code:

<template>
  <div></div>
</template>

<script>
export default {
    data() {
        return {
            editIsClicked: false,
        }
    }
}
</script>

Component B code:

<template>
    <v-pagination
      v-model="currentPage"
      :length="lastPage"
      :total-visible="8"
    ></v-pagination>
  </template>
  
  <script>
  export default {
    props: ["store", "collection"],
  
    watch: {
      currentPage(newVal) {
        this.paginatePage(newVal);
        // NEED TO TOGGLE VALUE HERE - when i switch between pages
        
      },
    },
   },
 };
  </script>
Tolbxela
  • 4,767
  • 3
  • 21
  • 42
martin-den
  • 33
  • 8
  • Can you please add your component code where you are using the modal? – Neha Soni Jan 30 '23 at 12:41
  • @NehaSoni thanks for the fast reply. Below you can find codesandbox link, please let me know if you have troubles opening it. https://codesandbox.io/s/pensive-fog-mdc515?file=/src/components/HelloWorld.vue – martin-den Jan 30 '23 at 12:47
  • The modal starts from line 37. – martin-den Jan 30 '23 at 12:49
  • The sandbox is not working. – Neha Soni Jan 30 '23 at 12:54
  • Please try this one and also let me know if it works, I really apologize https://codepen.io/skyscode/pen/bGjjXbw I added the code in the HTML section – martin-den Jan 30 '23 at 12:57
  • 1
    These demos won't work because you have some dependencies, like Axios, vuex, etc. you have to set up everything to prepare a demo. That's why I asked you to provide the code of the component. – Neha Soni Jan 30 '23 at 13:04
  • My assumption is, each row is using the same variable `triggerModalStateArr` to toggle between the modals. You can try using different variables for each row. the second alternative could be to use a single common modal for all rows which will show the data according to the selected row. – Neha Soni Jan 30 '23 at 13:12
  • I added the code, I tried codesandbox and codepen because the code was huge. The modal starts from the second – martin-den Jan 30 '23 at 13:12
  • regarding your answer: I cannot use different variable for each row, because I render every row dynamically later and I have to use one variable. Everything worked when I had initialized value from inside of the component, bot it does not work now. – martin-den Jan 30 '23 at 13:16
  • *"I added the code, I tried codesandbox and codepen because the code was huge."* -- then shrink the code to reasonable size, just enough to function and to demonstrate your problem, a [mre]. Doing this requires effort on your part, but since you're asking for free effort on our part, it is a reasonable trade. – Hovercraft Full Of Eels Jan 30 '23 at 13:19
  • @HovercraftFullOfEels I completely agree with you and I am aware of this. But since everything is connected in the app, i should rewrite almost wholel app to simulate the issue. I tried to upload the code to github/gitlab but I do not have rights to do that because the app is internal and I am at practice currently and there is no senior to help me, I do not have the rights to share the code publically - everything is done on local server. In case to simplify the explanation I re-wrote the question, I hope it will be easier to answer this way, I apologize for all complications. – martin-den Jan 30 '23 at 14:41
  • 1
    @martin-den: there is no need to apologize or to post the code from the app at all, but instead it would be best to create a *new* small code base that is based on the app (all identifying information removed) and that reproduces the problem. Oftentimes this process of simplification, of paring down the problem to its essentials helps you to identify the cause of the problem, and often leads *you* the [MRE] creator to find a solution. Even if it doesn't do this, it certainly helps *us*. – Hovercraft Full Of Eels Jan 30 '23 at 15:11
  • 1
    But this whether or not you do this is entirely up to you. If you get a decent solution here without having to create a MRE, then great, but if no solution is posted in a few hours and your need is great, then I would strongly suggest that you do this. – Hovercraft Full Of Eels Jan 30 '23 at 15:12
  • But in general for sib-to-sib data transfer, you *could* use props and emits of both sibs to parent, and let the parent sort out what needs to go where, but probably better would be to use a global store, such as Pinia. – Hovercraft Full Of Eels Jan 30 '23 at 16:07

2 Answers2

1

The Vue Documentation proposes communicating between Vue Components using props and events in the following way

             *--------- Vue Component -------*
some data => | -> props -> logic -> event -> | => other components 
             *-------------------------------*

It's also important to understand how v-model works with components in Vue v3 (Component v-model).

const { createApp } = Vue;

const myComponent = {   
  props: ['modelValue'],
  emits: ['update:modelValue'],
  data() {
    return {
      childValue: this.modelValue
    }
  },
  watch: {
    childValue(newVal) {
      this.$emit('update:modelValue', newVal)    
    }      
  },
  template: '<label>Child Value:</label> {{childValue}} <input type="checkbox" v-model="childValue" />'
}

const App = {
  components: { 
    myComponent 
  },
  data() {
    return {
      parentValue: false
    }
  }
}

const app = createApp(App)
app.mount('#app')
<div id="app">  
  Parent Value: {{parentValue}}<br />
  <my-component v-model="parentValue"/>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
Tolbxela
  • 4,767
  • 3
  • 21
  • 42
  • 1
    Here is another answer [How to sync checkboxes between Vue 3 parent and child components](https://stackoverflow.com/a/75262093/2487565), that could help with more complicated cases. – Tolbxela Jan 30 '23 at 15:58
  • Thanks a lot! But I cannot try this out immediately, because I am out of office, but will this work if components are not in Parent->Child connection? My question was more for components that are the same level. Thanks in advance. – martin-den Jan 30 '23 at 16:09
  • 1
    Again, consider use of a data store, such as Pinia, for sib-to-sib data transfer. – Hovercraft Full Of Eels Jan 30 '23 at 16:10
  • I did not saw your answer above earlier Hovercraft, sorry for spamming.. thanks! – martin-den Jan 30 '23 at 16:15
  • 1
    @martin-den, parent/child does not matter. You can connect the same way sibling components. – Tolbxela Jan 30 '23 at 16:17
  • @HovercraftFullOfEels, using Pinia for such simple case would be overcomplicating, from my point of view. – Tolbxela Jan 30 '23 at 16:31
  • @Tolbxela I really apologize but unfortunately is not working for me completely (or I do not know how to implement your solution on my code), because as I see, You import the child component in the parent component and that's how you pass and change the value. Can you please advise how to change the boolean value without importing of the component? Because in my case I do not need to import the child component into parent component. – martin-den Jan 31 '23 at 09:13
0

I have made a new playground. Hope it helps you now to understand the logic.

You can store data in the main Vue App instance or use a Pinia store for it.

But I would suggest you to start without Pinia to make your app simpler. Using Pinia will make your App much more complicated and your knowledge of Vue seems to be not solid enough for that.

const { createApp } = Vue;

const myComponentA = {   
  props: ['editIsClicked', 'currentPage'],
  template: '#my-component-a'
}

const myComponentB = {   
  emits: ['editIsClicked'],
  data() {
      return {
          currentPage: 1,
      }
  },
  watch: {
    currentPage(newVal) {
      this.$emit('editIsClicked', newVal)    
    }      
  },
  template: '#my-component-b'
}

const App = {
  components: { 
    myComponentA, myComponentB
  },
  data() { 
    return {
      editIsClicked: false,
      currentPage: 1
    }
  },
  methods: {
    setEditIsClicked(val) {
      this.editIsClicked = true;
      this.currentPage = val;
    }
  }
}

const app = createApp(App)
app.mount('#app')
#app { line-height: 2; }
.comp-a { background-color: #f8f9e0; }
.comp-b { background-color: #d9eba7; }
<div id="app">  
  <my-component-a :edit-is-clicked="editIsClicked" :current-page="currentPage"></my-component-a>
  <my-component-b @edit-is-clicked="setEditIsClicked"></my-component-b>
  
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script type="text/x-template" id="my-component-a">
  <div class="comp-a">
    My Component A: <br />editIsClicked: <b>{{editIsClicked}}</b><br/>
    currentPage: <b>{{currentPage}}</b><br/>
  </div>
</script>
<script type="text/x-template" id="my-component-b">
  <div class="comp-b">
    My Component B: <br />
    <label>CurrentPage:</label> <input type="number" v-model="currentPage" />
  </div>
</script>
Tolbxela
  • 4,767
  • 3
  • 21
  • 42
  • I tried to apply your code to my app and without success, Also I reproduced the issue the in Codesandbox, I just need to hide the modal from the SiblingComponent2, whenever it is opened in SiblingComponent 1. Below you can find link: https://codesandbox.io/s/vue-router-forked-mrqqc2?file=/src/components/Sibling1.vue – martin-den Feb 02 '23 at 10:30