javascriptvue.jsvue-componentvue-propsvue-events

Data transfer problem between two siblings components (Vue js)


I have three components and one of those is the parent of the others I'm trying to pass an object called talk between siblings emiting it inside an event from FollowedBrowser to LeftBar and then passing it via prop from LeftBar to TalksList component, after that another event is emited by TalksList and listened one more time for LeftBar and finally this component redefine the talk object as an empty object.

This is my parent component LeftBar.

<template>
    <v-navigation-drawer width="25%" permanent clipped app light>
        <talks-list v-if="inRoute('messages')" :talk="talk" @talkAdded="talkAdded()"/>
        <template v-if="inRoute('messages')" v-slot:prepend>
            <followed-browser @newTalk="addTalk($event)"/>
        </template>
    </v-navigation-drawer>
</template>

<script>
    import FollowedBrowser from "./FollowedBrowser";
    import TalksList from "./TalksList";
    import { mapGetters } from "vuex";
    export default {
        data(){
            return {
                talk: {}
            }
        },
        components: {
            FollowedBrowser,
            TalksList
        },
        methods: {
            addTalk(talk){
                this.talk = talk;
            },
            talkAdded(){
                this.talk = {};
            }
        }
    }
</script>

And this is my two children:

TalksList.vue

<template>
    <v-container class="my-0 px-5">

        <v-list flat>
            <v-list-item-group class="my-0">
                <div class="ma-0 pa-0" v-for="(talk, index) in talks" :key="index">
                    <v-divider v-if="talk.divider"></v-divider>
                    <v-list-item v-else class="px-2" style="cursor: pointer">
                        <template>

                            <v-list-item-avatar>
                                <v-img :src="correctedImageUrl(talk.recipient)"></v-img>
                            </v-list-item-avatar>

                            <v-list-item-content>
                                <v-list-item-title>
                                    <span class="blue--text text--lighten-1">{{ completeName(talk.recipient) }}</span>
                                </v-list-item-title>
                                <v-list-item-subtitle>
                                    <span>{{ talk.recipient.username }}</span>
                                </v-list-item-subtitle>
                            </v-list-item-content>

                        </template>
                    </v-list-item>

                </div>
            </v-list-item-group>
        </v-list>
    </v-container>

</template>

<script>
    import axios from "axios";
    export default {
        data(){
            return {
                talks: []
            }
        },
        props: {
            talk: {
                type: Object,
                default: null,
                required: true
            }
        },
        watch: {
            talk(val){
                if(val){
                    this.talks.splice(0, 1, val);
                    this.$emit("talkAdded");
                }
            }
        }
    }
</script>

FollowedBrowsed.vue

<template>
    <div style="display: inline">
        <v-dialog scrollable v-model="dialog" max-width="400px" max-height="500px">

            <v-card :loading="loading">
                <v-text-field dense outlined color="blue lighten-1" label="Nombre de usuario" class="px-5" append-icon="mdi-magnify" v-model="browsedUsername"/>
                <v-divider></v-divider>
                <v-card-text style="height: 300px;" class="px-2">
                    <v-list>
                        <v-list-item class="px-2" style="cursor: pointer" v-for="listUser in filteredFollowed" :key="listUser.id" @click.prevent="newTalk(listUser)">
                            <v-list-item-content>
                                <v-list-item-title>
                                    <span class="blue--text text--lighten-1">{{ completeName(listUser) }}</span>
                                </v-list-item-title>
                                    <v-list-item-subtitle>
                                        <span>{{ listUser.username }}</span>
                                </v-list-item-subtitle>
                            </v-list-item-content>
                        </v-list-item>
                    </v-list>
                </v-card-text>
            </v-card>
        </v-dialog>
    </div>
</template>

<script>
    import { mapGetters } from "vuex";
    import axios from "axios";
    export default {
    data(){
        return {
            browsedUsername: "",
            loading: false,
            dialog: false,
            skeleton: true,
            followed: []
        }
    },
    watch: {
        dialog(dialog){
            if(!dialog){
                this.browsedUsername = "";
                this.item = null;
            }
        }
    },
    computed: {
        ...mapGetters({
            authenticated: "auth/authenticated",
            user: "auth/user"
        }),
        filteredFollowed(){
            return this.followed.filter((user) => {
                return user.username.toLowerCase().indexOf(this.browsedUsername.toLowerCase()) !== -1;
            })
        }
    },
    mounted(){
        axios.get("all_followers_followed/followed")
            .then((response) => {
                if(response.data){
                    this.followed = response.data;
                    this.skeleton = false;
                }
            })
            .catch((error) => {
                console.log(error)
            });
  },

  methods: {
     async newTalk(user){
        this.loading = "blue lighten-1";
        await axios.post("messages/new_talk", {recipient_id: user.id})
           .then((response) => {
              if(response.data){
                 this.dialog = false;
                 this.$emit("newTalk", {
                    messages_number: 0,
                    recipient: user,
                    sender: this.user
                 });
              }
           })
           .catch((error) => {
              console.log(error);
           });
     }
  }

}

When the newTalk method is called inside FollowedBrowser component newTalk event is emited but after that my screen freezes like the app was inside infinite loop and I don't know why. I omitted some code that I thought was irrelevant.

Can anybody help me.

Thanks in advance.


Solution

  • I solved... So simple, I just had to get a copy of talk prop inside TalksList, inside watch just put this:

    watch: {
        talk(val){
    
            if(val){
    
                if(this.talks.length){
                    this.talks.unshift({ divider: true });
                }
    
                let buffer = new Object();
                let talk = new Object();
    
                buffer.data = val;
                talk = buffer.data;
    
                this.talks.unshift(talk);
            }
        }
    },