Vue don't give #click to a single element when using v-for to create them - vue.js

I'm trying to make every single element created with the v-for the ability to toggle between 'face' class, but it happens that it toggles everything created with the v-for.
<div class="deckPairs">
<div class="deckBoxOne" v-for="base in cards" :key="base.id" >
<div class="deckBoxBlanc" :class="{face : face}" #click="face = !face">
<img class="deckPairsImage" style="z-index: 3" alt="Vue logo" :src="require('../assets/rightCardSide.png')">
</div>
<div class="deckBoxImg" :class="{face : !face}" #click="face = !face">
<img class="deckPairsImages" style="z-index: 2" :src="require(`../assets/images/${base.url}`)">
</div>
</div>
</div>
Script:
export default {
setup() {
const face = ref(false)
return { face }
},
data(){
return {
face: false,
}
},
methods: {
}
}

Create a component to encapsulate the v-for content.
// new-component.vue
<template>
<div>
<div class="deckBoxBlanc" :class="{face : face}" #click="face = !face">
<img class="deckPairsImage" style="z-index: 3" alt="Vue logo" :src="require('../assets/rightCardSide.png')">
</div>
<div class="deckBoxImg" :class="{face : !face}" #click="face = !face">
<img class="deckPairsImages" style="z-index: 2" :src="require(`../assets/images/${base.url}`)">
</div>
</div>
</template>
export default {
data(){
return {
face: false
}
}
}
Now update v-for to use the new component.
<div class="deckPairs">
<div class="deckBoxOne" v-for="base in cards" >
<new-component :key="base.id"/>
</div>
</div>

You can use base.id instead boolean and v-show directive:
const { ref } = Vue
const app = Vue.createApp({
el: "#demo",
setup() {
const face = ref(false)
const cards = ref([{id: 1, url: "https://picsum.photos/100"}, {id: 2, url: "https://picsum.photos/101"}, {id: 3, url: "https://picsum.photos/102"}])
const rightCardSide = ref("https://picsum.photos/103")
const setFace = (val) => {
face.value = val
}
return { cards, face, rightCardSide, setFace }
},
})
app.mount('#demo')
.deckPairs {
display: flex;
}
.deckBoxOne {
cursor: pointer;
}
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<div class="deckPairs">
<div class="deckBoxOne" v-for="base in cards" :key="base.id" >
<div class="deckBoxBlanc" v-show=" face !== base.id" #click="setFace(base.id)">
<img class="deckPairsImage" alt="Vue logo" :src="rightCardSide">
</div>
<div class="deckBoxImg" v-show="face === base.id" #click="setFace(false)">
<img class="deckPairsImages" :src="base.url">
</div>
</div>
</div>
</div>

Related

I am converting my code snippet from pure html to Vue2 but facing some difficulty

This is pure html code with javascript.
filter.js
var group_filter=document.getElementById("group-filter");
var btn_show_filter=document.getElementById("icon-filter");
var btn_close_filter=document.getElementById("icon-close-filter");
function showfilter(){
group_filter.style.display='block';
btn_show_filter.style.display='none';
btn_close_filter.style.display='inline';
}
function closefilter(){
group_filter.style.display='none';
btn_show_filter.style.display='inline';
btn_close_filter.style.display='none';
}
And here is the code that I'm trying to process but it doesn't look right.
<div class="job-filter">
<h3>Filter <img id="icon-filter" #click="showfilter" :class="{ 'display-none': this.display }" src="../assets/recruit/angle-down-svgrepo-com.svg" alt=""> <img id="icon-close-filter" :class="{ 'display-inline': this.display }" #click="showfilter" src="../assets/recruit/close-svgrepo-com.svg" alt=""></h3>
<div class="radio-group" id="group-filter" :class="{ 'display-block': this.display}" >
</div>
</div>
Thank you everyone, and I look forward to your help.
You can simply achieve this by creating an object in the data method like this :
data() {
return {
display: {
group_filter: '',
btn_show_filter: '',
btn_close_filter: ''
}
}
}
And in methods object, you can assign the values :
methods: {
showfilter() {
this.display.group_filter = 'block';
this.display.btn_show_filter = 'none';
this.display.btn_close_filter = 'inline';
},
closefilter() {
this.display.group_filter = 'none';
this.display.btn_show_filter = 'inline';
this.display.btn_close_filter = 'none';
}
}
And then in the template, you can assign like this :
<div class="job-filter">
<h3>Filter <img id="icon-filter" #click="showfilter" :style="{ 'display': display.btn_show_filter }" src="../assets/recruit/angle-down-svgrepo-com.svg" alt=""> <img id="icon-close-filter" :style="{ 'display': display.btn_close_filter }" #click="closefilter" src="../assets/recruit/close-svgrepo-com.svg" alt=""></h3>
<div class="radio-group" id="group-filter" :style="{ 'display': display.group_filter }"></div>
</div>
I hope this is what you want to achieve.
I have create one demo on stackblitz.
link - https://vue-etrbkr.stackblitz.io
I have attached source code here.
<template>
<div id="app">
<div class="job-filter">
<h3>
Filter
<img
#click="toggleFilter"
class="filterIcon"
:src="
isFilterOpen
? 'https://cdn-icons-png.flaticon.com/512/61/61155.png'
: 'https://iaeste.org/assets/icons/arrow_dropdown-
8e096a444299e295fa03bc919f3cea625987792e13aaf64ec6b0be881a8f7c0a.svg'
"
width="20"
height="20"
/>
</h3>
<div class="radio-group" id="group-filter" v-if="isFilterOpen">
Filter Content
</div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
isFilterOpen: false,
};
},
methods: {
toggleFilter() {
this.isFilterOpen = !this.isFilterOpen;
},
},
};
</script>
<style>
.filterIcon {
vertical-align: bottom;
cursor: pointer;
}
</style>

VueJs | How to combine a In and out animation with library Animate.css?

I'm starting with VueJs.
I would like to combine animation in and out in a modal.
I think I should do a function but can't find how to.
Here my code:
<template>
<div class="backgroundImage" :style="{'background-image': 'url(' + require('../../assets/bkg.jpg') + ')'}">
<div v-if="showModal" #click="showModal = false"></div>
<div class="modal" v-if="showModal">
<div class="animate__animated animate__bounceIn animate__slow">
<img id="synthesisFt" src="../../assets/popup-ftt.jpg" alt="Logo FunkTheTown" title="FunkTheTown" #click="showModal = false"/>
</div>
</div>
<div>
<img class="logo-img" src="../../assets/logo.png" alt="Logo FunkTheTown" title="FunkTheTown" />
</div>
</div>
</template>
<script>
export default {
data () {
return {
showModal: false
}
},
mounted:function(){
this.popup()
},
methods: {
popup : function () {
setTimeout(() => {
this.showModal = true;
}, 3000);
},
// classChange : function () {
// showmodal = false;
// }
}
}
for the off I would like to use animate__animated animate__bounceOut when I click on the modal.
I've resolved the issue, here the code :
<template>
<div class="backgroundImage" :style="{'background-image': 'url(' + require('../../assets/bkg.jpg') + ')'}">
<div v-if="showModal" #click="showModal = false"></div>
<div class="modal" v-if="showModal">
<div class="animate__animated animate__bounceIn animate__slow">
<img id="synthesisFt" src="../../assets/popup-ftt.jpg" alt="Logo FunkTheTown" title="FunkTheTown" #click="anim2()"/>
</div>
</div>
<div class="animate__animated animate__backInDown animate__slow" v-if="showModalLogin">
<div class="modalLogin">
<label>Login</label>
<input class="loginInput" type="text" placeholder="email...">
<label>Password</label>
<input class="loginPassword" type="password" placeholder="password...">
<button class="connexion">Connexion</button>
<button class="join">Join</button>
</div>
</div>
<div>
<img class="logo-img" src="../../assets/logo.png" alt="Logo FunkTheTown" title="FunkTheTown" />
</div>
<div class="animate__animated animate__rotateIn" v-if="showModalLogo" >
<img class="full_logo" src="../../assets/F2T_logo_color.png" >
</div>
<div class="animate__animated animate__rotateIn" v-if="showModalLogo">
<img class="full_logo_right" src="../../assets/F2T_logo_coloreverse.png" >
</div>
</div>
</template>
<script>
export default {
data () {
return {
showModal: false,
showModalLogin: false,
showModalLogo:false,
}
},
mounted:function(){
this.popup()
},
methods: {
popup : function () {
setTimeout(() => {
this.showModal = true;
}, 3000);
},
anim2 : function () {
this.showModal= false;
this.showModalLogin= true;
this.showModalLogo =true;
const element = document.querySelector('.logo-img');
element.classList.add('animate__animated','animate__bounceOut');
}
// classChange : function () {
// showmodal = false;
// }
}
}

How to use "this" in Vue 3

I'm working on a component in Vue3/TypeScript. I'm relatively new to Vue.
I'm dynamically creating a div. I want to be able to delete it when a user clicks on the "x" button. This is the "closeStatus" method.
In JavaScript I can pass this, but Vue hates it.
If anyone can help.
Thanks.
Here is the code:
<template>
<div>
<button #click="addStatus()" >Add Status</button>
<div id="slide" class="slide-modal">
<div class="clear-notifications" #click='clearAllNotifications()'>Clear all notifications</div>
<div class="status-div">
<div>11:00 Booking requested</div>
<div #click="closeStatus(this)"><img src="../assets/cross.svg" /></div>
</div>
<div class="status-div">
<div>11:30 Booking requested</div>
<div #click="closeStatus(this)"><img src="../assets/cross.svg" /></div>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'SlideModal',
methods: {
clearAllNotifications() {
const allNotifications = document.querySelectorAll(".status-div");
for(let x=0;x<allNotifications.length;x++) {
allNotifications[x].remove(); //removes all the child elements.
}
document.getElementById('slide').style.visibility='hidden'; //This should be Vue reactive.
},
addStatus() {
document.getElementById('slide').style.visibility='visible'; //This should be Vue reactive.
const statusMessage = "Another Message"
var div = document.createElement('div');
div.setAttribute('class', 'status-div');
div.innerHTML = '<div>' + statusMessage + '</div><div onclick="closeStatus(this)"><img src="/src/assets/cross.svg" /></div>'
document.getElementById('slide').appendChild(div);
},
closeStatus(elm: any) {
elm.parentNode.remove();
const allNotifications = document.querySelectorAll(".status-div");
if(allNotifications.length == 0 ) {
document.getElementById('slide').style.visibility='hidden'; //This should be Vue reactive.
}
}
}
}
</script>
Code is javascript DOM management stuff and far from Vue style.
Vue manages DOM with variables and that is what makes javascript frameworks awesome.
Let me first share the modified code.
<template>
<div>
<button #click="addStatus()" >Add Status</button>
<div id="slide" class="slide-modal" v-show="visibleSlide">
<div class="clear-notifications" #click='clearAllNotifications()'>Clear all notifications</div>
<div class="status-div">
<div>11:00 Booking requested</div>
<div #click="closeStatus(this)"><img src="../assets/cross.svg" /></div>
</div>
<div class="status-div">
<div>11:30 Booking requested</div>
<div #click="closeStatus(this)"><img src="../assets/cross.svg" /></div>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'SlideModal',
data() {
return {
visibleSlide: true
}
},
methods: {
clearAllNotifications() {
const allNotifications = document.querySelectorAll(".status-div");
for(let x = 0; x < allNotifications.length; x++) {
allNotifications[x].remove(); //removes all the child elements.
}
this.visibleSlide = false
},
addStatus() {
this.visibleSlide = true;
const statusMessage = "Another Message";
var div = document.createElement('div');
div.setAttribute('class', 'status-div');
div.innerHTML = '<div>' + statusMessage + '</div><div onclick="closeStatus(this)"><img src="/src/assets/cross.svg" /></div>'
document.getElementById('slide').appendChild(div);
},
closeStatus(elm: any) {
elm.parentNode.remove();
const allNotifications = document.querySelectorAll(".status-div");
if(allNotifications.length == 0 ) {
this.visibleSlide = false
}
}
}
}
</script>
I have just updated what is commented: "//This should be Vue reactive."
But it is still not benefiting from Vue framework.
Here is my whole idea of Vue code
<template>
<div>
<button #click="addStatus()" >Add Status</button>
<div id="slide" class="slide-modal" v-if="statuses.length">
<div class="clear-notifications" #click='clearAllNotifications()'>Clear all notifications</div>
<div v-for="status in statuses" :key="status.id" class="status-div">
<div>{{ status.text }}</div>
<div #click="closeStatus(status)"><img src="../assets/cross.svg" /></div>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'SlideModal',
data() {
return {
statuses: [
{
id: 1,
text: '11:00 Booking requested'
}, {
id: 2,
text: '11:30 Booking requested'
}
]
}
},
methods: {
clearAllNotifications() {
this.statuses = []
},
addStatus() {
const statusMessage = "Another Message";
this.statuses.push({
id: this.statuses.length + 1,
text: statusMessage
})
},
closeStatus(elm: any) {
const index = this.statuses.map((status) => status.id).indexOf(elm.id);
this.statuses.splice(index, 1);
}
}
}
</script>
As you can see, DOM elements are managed by variables and their operations instead of DOM management methods.
Hope this is helpful

Vuex State data is not persisting?

I'm working on admin panel in vuejs and using vuex for state management.
store/module/home/home.js:
import instance from "../../../services/Http";
const state = {
usersCount: 0,
customersCount: 0,
chefsCount: 0,
driversCount: 0,
Users: [],
};
const getters = {
Userscount: state => state.usersCount,
Customerscount: state => state.customersCount,
Chefscount: state => state.chefsCount,
Driverscount: state => state.driversCount,
users: state => state.Users,
};
const actions = {
getStats({commit})
{
instance.get('admin/stats').then(res => commit('setStats', res.data));
},
getUsers({commit})
{
instance.get('admin/users').then(res => commit('setUsers', res.data));
}
};
const mutations = {
setStats:(state, data) => {
state.usersCount = data.usersCount;
state.customersCount = data.customersCount;
state.chefsCount = data.chefsCount;
state.driversCount = data.driversCount;
},
setUsers:(state, data) => { state.Users = data.users}
};
export default {
state,
getters,
actions,
mutations
}
and then i'm calling getStats and getUsers actions in two different components in created method of respective components.
The issue is that getStats and setStats is executed but it does not set the data, but getUsers and setUsers is working as expected.
src/components/layouts/Widgets.vue:
<template>
<!-- Widgets -->
<div class="row">
<div class="col-lg-3 col-md-6">
<div class="card">
<div class="card-body">
<div class="stat-widget-five">
<div class="stat-icon dib flat-color-1">
<!-- <i class="pe-7s-cash"></i>-->
<i class="pe-7s-users"></i>
</div>
<div class="stat-content">
<div class="text-left dib">
<div class="stat-text"><span class="count">{{ Userscount }}</span></div>
<div class="stat-heading">Total Users</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card">
<div class="card-body">
<div class="stat-widget-five">
<div class="stat-icon dib flat-color-2">
<!-- <i class="pe-7s-cart"></i>-->
<i class="pe-7s-users"></i>
</div>
<div class="stat-content">
<div class="text-left dib">
<div class="stat-text"><span class="count">{{ Chefscount }}</span></div>
<div class="stat-heading">Total Chefs</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card">
<div class="card-body">
<div class="stat-widget-five">
<div class="stat-icon dib flat-color-8">
<!-- <i class="pe-7s-browser"></i>-->
<i class="pe-7s-users"></i>
</div>
<div class="stat-content">
<div class="text-left dib">
<div class="stat-text"><span class="count">{{ Customerscount }}</span></div>
<div class="stat-heading">Total Customers</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card">
<div class="card-body">
<div class="stat-widget-five">
<div class="stat-icon dib flat-color-4">
<i class="pe-7s-users"></i>
</div>
<div class="stat-content">
<div class="text-left dib">
<div class="stat-text"><span class="count">{{ Driverscount }}</span></div>
<div class="stat-heading">Total Drivers</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /Widgets -->
</template>
<script>
import {mapActions,mapGetters} from 'vuex';
export default {
name: "Widgets",
created() {
this.getStats();
},
computed: mapGetters(['Userscount','Customerscount','Chefscount','Driverscount']),
methods:{
...mapActions(['getStats'])
},
}
</script>
i'have also attached images showing of vue js dev tools for vuex that data is stored in state but it is not being displayed.
edit-1:
setStats-after console.log
{usersCount: 12, customersCount: 4, chefsCount: 7, driversCount: 0, postsCount: 22}chefsCount: 7customersCount: 4driversCount: 0postsCount: 22usersCount: 12__proto__: Object
Edit-2:
vuex binding widgets components
Edit-3:
Store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import auth from "./modules/auth/auth";
import home from "./modules/home/home";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
auth,
home
}
});
sr/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false;
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.isLoggedIn)
{
next({
name: 'login',
})
}
else
{
next();
}
}
else if(to.matched.some(record => record.meta.Visitor)) {
if (store.getters.isLoggedIn)
{
next({
name: 'home',
})
}
else
{
next();
}
}
else
{
next()
}
});
new Vue({
store,
router,
render: h => h(App)
}).$mount('#app');
src/components/layout/Main.vue:
<template>
<div class="Main">
<SideBar/>
<div id="right-panel" class="right-panel">
<Header/>
<!-- Content -->
<div class="content">
<div class="animated fadeIn">
<Widgets/>
<div class="clearfix"></div>
<Users/>
<div class="clearfix"></div>
<Footer/>
</div>
</div>
</template>
<script>
import SideBar from "./SideBar";
import Header from "./Header";
import Footer from "./Footer";
import Widgets from "./Widgets";
import Users from "../users/Users";
export default {
name: "Main",
components: {Users, Widgets, Footer, Header, SideBar}
}
</script>
<style scoped>
#weatherWidget .currentDesc {
color: #ffffff!important;
}
.traffic-chart {
min-height: 335px;
}
#flotPie1 {
height: 150px;
}
#flotPie1 td {
padding:3px;
}
#flotPie1 table {
top: 20px!important;
right: -10px!important;
}
.chart-container {
display: table;
min-width: 270px ;
text-align: left;
padding-top: 10px;
padding-bottom: 10px;
}
#flotLine5 {
height: 105px;
}
#flotBarChart {
height: 150px;
}
#cellPaiChart{
height: 160px;
}
</style>
Any help will be appreciated.
Thanks.
you forgot to add "..." before the 'mapGetters', "...mapGetters"
I think your problem would be solved by implementing the strict-mode in Vuex, by the way, it's turned off by default.
take a look here: https://vuex.vuejs.org/guide/strict.html
Have you tried using mapState instead of mapGetters? As your values are just being updated, but your getters aren't computed values, they just map to your state.
Instead of:
<script>
import {mapActions,mapGetters} from 'vuex';
export default {
name: "Widgets",
created() {
this.getStats();
},
computed: mapGetters(['Userscount','Customerscount','Chefscount','Driverscount']),
methods:{
...mapActions(['getStats'])
},
}
</script>
Maybe try:
<script>
import {mapActions,mapGetters} from 'vuex';
export default {
name: "Widgets",
created() {
this.getStats();
},
computed: mapState({
Userscount: state => state.home.Userscount,
Customerscount: state => state.home.Customerscount,
Chefscount: state => state.home.Chefscount,
Driverscount: state => state.home.Drivers.count
}),
methods:{
...mapActions(['getStats'])
},
}
</script>

Is it possible to sync Vuejs components displayed multiple times on the same page?

I have a web page that displays items. For each items there is a button (vuejs component) which allow user to toggle (add/remove) this item to his collection.
Here is the component:
<template lang="html">
<button type="button" #click="toggle" name="button" class="btn" :class="{'btn-danger': dAdded, 'btn-primary': !dAdded}">{{ dText }}</button>
</template>
<script>
export default {
props: {
added: Boolean,
text: String,
id: Number,
},
data() {
return {
dAdded: this.added,
dText: this.text,
dId: this.id
}
},
watch: {
added: function(newVal, oldVal) { // watch it
this.dAdded = this.added
},
text: function(newVal, oldVal) { // watch it
this.dText = this.text
},
id: function(newVal, oldVal) { // watch it
this.dId = this.id
}
},
methods: {
toggle: function(event) {
axios.post(route('frontend.user.profile.pop.toggle', {
pop_id: this.dId
}))
.then(response => {
this.dText = response.data.message
let success = response.data.success
this.dText = response.data.new_text
if (success) {
this.dAdded = success.attached.length
let cardPop = document.getElementById('card-pop-'+this.dId);
if(cardPop)
cardPop.classList.toggle('owned')
}
})
.catch(e => {
console.log(e)
})
}
}
}
</script>
For each item, the user can also open a modal, loaded by a click on this link:
<a href="#" data-toggle="modal" data-target="#popModal" #click="id = {{$pop->id}}">
<figure>
<img class="card-img-top" src="{{ URL::asset($pop->img_path) }}" alt="Card image cap">
</figure>
</a>
The modal is also a Vuejs component:
<template>
<section id="pop" class="h-100">
<div class="card">
<div class="container-fluid">
<div class="row">
<div class="col-12 col-lg-1 flex-column others d-none d-xl-block">
<div class="row flex-column h-100">
<div v-for="other_pop in pop.other_pops" class="col">
<a :href="route('frontend.pop.collection.detail', {collection: pop.collection.slug, pop: other_pop.slug})">
<img :src="other_pop.img_path" :alt="'{{ other_pop.name }}'" class="img-fluid">
</a>
</div>
<div class="col active order-3">
<img :src="pop.img_path" :alt="pop.name" class="img-fluid">
</div>
</div>
</div>
<div class="col-12 col-lg-6 content text-center">
<div class="row">
<div class="col-12">
<img :src="pop.img_path" :alt="pop.name" class="img-fluid">
</div>
<div class="col-6 text-right">
<toggle-pop :id="pop.id" :added="pop.in_user_collection" :text="pop.in_user_collection ? 'Supprimer' : 'Ajouter'"></toggle-pop>
</div>
<div class="col-6 text-left">
<!-- <btnaddpopwhishlist :pop_id="propid" :added="pop.in_user_whishlist" :text="pop.in_user_whishlist ? 'Supprimer' : 'Ajouter'"></btnaddpopwhishlist> -->
</div>
</div>
</div>
<div class="col-12 col-lg-5 infos">
<div class="header">
<h1 class="h-100">{{ pop.name }}</h1>
</div>
<div class="card yellow">
<div class="card p-0">
<div class="container-fluid">
<div class="row">
<div class="col-3 py-2">
</div>
<div class="col-6 py-2 bg-lightgray">
<h4>Collection:</h4>
<h3>{{ pop.collection ? pop.collection.name : '' }}</h3>
</div>
<div class="col-3 py-2 bg-lightgray text-center">
<a :href="route('frontend.index') + 'collections/' + pop.collection.slug" class="btn-round right white"></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
export default {
props: {
id: Number
},
data() {
return {
pop: {
collection: {
}
}
}
},
ready: function() {
if (this.propid != -1)
this.fetchData()
},
watch: {
id: function(newVal, oldVal) { // watch it
// console.log('Prop changed: ', newVal, ' | was: ', oldVal)
this.fetchData()
}
},
computed: {
imgSrc: function() {
if (this.pop.img_path)
return 'storage/images/pops/' + this.pop.img_path
else
return ''
}
},
methods: {
fetchData() {
axios.get(route('frontend.api.v1.pops.show', this.id))
.then(response => {
// JSON responses are automatically parsed.
// console.log(response.data.data.collection)
this.pop = response.data.data
})
.catch(e => {
this.errors.push(e)
})
// console.log('fetchData')
}
}
}
</script>
Here is my app.js script :
window.Vue = require('vue');
Vue.component('pop-modal', require('./components/PopModal.vue'));
Vue.component('toggle-pop', require('./components/TogglePop.vue'));
const app = new Vue({
el: '#app',
props: {
id: Number
}
});
I would like to sync the states of the component named toggle-pop, how can I achieve this ? One is rendered by Blade template (laravel) and the other one by pop-modal component. But they are just the same, displayed at different places.
Thanks.
You could pass a state object as a property to the toggle-pop components. They could use this property to store/modify their state. In this way you can have multiple sets of components sharing state.
Your component could become:
<template lang="html">
<button type="button" #click="toggle" name="button" class="btn" :class="{'btn-danger': sstate.added, 'btn-primary': !sstate.added}">{{ sstate.text }}</button>
</template>
<script>
export default {
props: {
sstate: {
type: Object,
default: function() {
return { added: false, text: "", id: -1 };
}
}
},
data() {
return {};
},
methods: {
toggle: function(event) {
axios.post(route('frontend.user.profile.pop.toggle', {
pop_id: this.sstate.id
}))
.then(response => {
this.sstate.text = response.data.message
let success = response.data.success
this.sstate.text = response.data.new_text
if (success) {
this.sstate.ddded = success.attached.length
let cardPop = document.getElementById('card-pop-'+this.sstate.id);
if(cardPop)
cardPop.classList.toggle('owned')
}
})
.catch(e => {
console.log(e)
})
}
};
</script>
Live demo
https://codesandbox.io/s/vq8r33o1w7
If you are 100% sure that all toggle-pop components should always have the same state, you can choose to not define data as a function. Just declare it as an object.
data: {
dAdded: this.added,
dText: this.text,
dId: this.id
}
In https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function, it mentions
a component’s data option must be a function, so that each instance
can maintain an independent copy of the returned data object
If Vue didn’t have this rule, clicking on one button would affect the
data of all other instances
Since you want to sync the data of all toggle-pop component instances, you don't have to follow the data option must be a function rule.