hjortur17
167
1
Vue

Pass data from one component to another

Posted 1 month ago by hjortur17

Hi, I have one component which needs to know of what's happening in another component. So I have Thread.vue which​ is the parent and then I have LockButton.vue and Replies.vue. In Replies.vue I'm using a component called NewReply.vue and NewReply.vue needs to know if LockButton.vue has locked set to true or false.

So for short: I'm trying to use data from LockButton in NewReply.vue

And I have tried to do this on NewReply.vue = v-if="! $parent.locked"

So here is the components and a view, (Thread.vue is an​ inline-template in show.blade.php)

Thread.vue

<script>
    import Replies from '../components/Replies.vue';
    import SubscribeButton from '../components/SubscribeButton.vue';
    import LockButton from '../components/LockButton.vue';

    export default {
        props: ['initalRepliesCount'],

        components: { Replies, SubscribeButton, LockButton },

        data() {
            return {
                repliesCount: this.initalRepliesCount
            }
        }
    }
</script>

Replies.vue

<template>
    <div>
        <div v-for="(reply, index) in items" :key="reply.id">
            <reply :attributes="reply" @deleted="remove(index)"></reply>
        </div>

        <paginator :dataSet="dataSet" @changed="fetch"></paginator>

        <new-reply @created="add" v-if="! $parent.locked"></new-reply>
    </div>
</template>

<script>
    import Reply from './Reply.vue';
    import NewReply from './NewReply.vue';
    import collection from '../mixins/collection.js';

    export default {
        components: { Reply, NewReply },

        mixins: [collection],

        data() {
            return { dataSet: false };
        },

        created() {
            this.fetch();
        },

        methods: {
            fetch(page) {
                axios.get(this.url(page)).then(this.refresh);
            },

            url(page) {
                if (! page) {
                    let query = location.search.match(/page=(\d)/);

                    page = query ? query[1] : 1;
                }
                return location.pathname + '/athugasemdir?page=' + page;
            },

            refresh({data}) {
                this.dataSet = data;
                this.items = data.data;

                window.scrollTo(0,0);
            }
        }
    }
</script>

NewReply.vue

<template>
    <div id="reply-form" class="pt-8">
        <div class="flex" v-if="signedIn">
            <div class="w-10 item-start">
                <img :src="image" class="rounded-full w-10 h-10" style="object-fit: cover;">
            </div>
            <div class="w-full pl-3 self-center">
                <div class="flex items-center bg-grey-lighter rounded-full text-grey-darker focus:text-black resize-none outline-none text-sm">
                    <input class="appearance-none bg-transparent rounded-full text-grey-dark w-full pl-4 leading-tight focus:outline-none focus:text-grey-darkest transition" type="text" placeholder="Vitlu leggja orð í belg?" name="body" id="replyInput" v-model="body" required>
                    <button class="flex-no-shrink bg-blue p-2 px-4 rounded-full" type="submit" @click="addReply">
                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="15px" height="15px"><path d="M476 fill="#fff"/></svg>
                    </button>
                </div>
            </div>
        </div>
        <p class="text-sm text-grey-dark" v-else>Þú þarft að vera <a href="/login" class="text-blue-light no-underline hover:text-blue transition">skráð/ur inn</a> til þess að taka þátt í umræðuni</p>
    </div>
</template>

<script>
    import 'jquery.caret';
    import 'at.js';

    export default {
        data() {
            return {
                body: ''
            };
        },

        computed: {
            image() {
                return window.App.user.avatar_path;
            }
        },

        mounted() {
            $('#replyInput').atwho({
                at: "@",
                delay: 750,
                callbacks: {
                    remoteFilter: function(query, callback) {
                        $.getJSON("/api/users", {name: query}, function (usernames) {
                            callback(usernames)
                        });
                    }
                }
            })
        },

        methods: {
            addReply() {
                axios.post(location.pathname + '/athugasemdir', { body: this.body })
                    .catch(error => {
                        flash(error.response.data, 'danger');
                    })
                    .then(({data}) => {
                        this.body = '';
                        
                        flash('Kommentið þitt hefur verið póstað');
                        
                        this.$emit('created', data);
                    });
            }
        }
    }
</script>

LockButton.vue

<template>
    <a class="cursor-pointer mr-4" @click="locked=true">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" height="16px"><path :d="paths" :fill="fills"/></svg>
    </a>
</template>

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

        computed: {
            paths() {
                return [this.locked ? 'M400 2z' : 'M400'];
            },

            fills() {
                return [this.locked ? '#f2d024' : '#3d4852'];
            }
        }
    }
</script>

show.blade.php

@extends ('layouts.master')

@section ('include-css-head')
    <link rel="stylesheet" type="text/css" href="/css/vendor/jquery.atwho.css">
@endsection

@section ('section-1')
    <thread-view :inital-replies-count="{{ $thread->replies_count }}" inline-template>
        <div>
            <nav class="py-12">
                <div class="flex">
                    <div class="flex-1 text-left">
                        <a href="{{ route('home') }}">
                            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" height="16px"><path d="M231.536 475.535l7.071-7.07c4.686-4.686 4.686-12.284 0-16.971L60.113 273H436c6.627 0 12-5.373 12-12v-10c0-6.627-5.373-12-12-12H60.113L238.607 60.506c4.686-4.686 4.686-12.284 0-16.971l-7.071-7.07c-4.686-4.686-12.284-4.686-16.97 0L3.515 247.515c-4.686 4.686-4.686 12.284 0 16.971l211.051 211.05c4.686 4.686 12.284 4.686 16.97-.001z" fill="#3d4852"/></svg>
                        </a>
                    </div>

                    @if (Auth::check())
                        <div class="flex-1 text-right">
                            <lock-button></lock-button>
                            <subscribe-button :active="{{ json_encode($thread->isSubscribedTo) }}"></subscribe-button>
                        </div>
                    @endif
                </div>
            </nav>

            <article>
                <img src="/images/news.jpg" class="h-72 w-full rounded object-cover shadow">

                <div class="flex flex-row py-4">
                    <div class="flex-1 text-left">
                        <a href="{{ route('profile', $thread->creator) }}" class="no-underline text-grey-darkest hover:text-blue transition"><p class="text-sm">{{ $thread->creator->name }}</p></a>
                    </div>
                    <div class="flex-1 text-right">
                        <p class="text-sm text-grey-darkest">{{ $thread->updated_at->diffForHumans() }}</p>
                    </div>
                </div>

                <h1 class="py-4 text-black">{{ $thread->title }}</h1>
                <p class="leading-normal">{{ $thread->body }}</p>


                <div class="pt-12 pb-6">
                    <ul class="list-reset flex">
                        <li class="pr-4">
                            <p class="text-grey-dark text-sm">
                                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" height="13px" width="13px" class="inline-flex"><path d="M288 288a64 64 0 0 0 0-128c-1 0-1.88.24-2.85.29a47.5 47.5 0 0 1-60.86 60.86c0 1-.29 1.88-.29 2.85a64 64 0 0 0 64 64zm284.52-46.6C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 96a128 128 0 1 1-128 128A128.14 128.14 0 0 1 288 96zm0 320c-107.36 0-205.46-61.31-256-160a294.78 294.78 0 0 1 129.78-129.33C140.91 153.69 128 187.17 128 224a160 160 0 0 0 320 0c0-36.83-12.91-70.31-33.78-97.33A294.78 294.78 0 0 1 544 256c-50.53 98.69-148.64 160-256 160z" fill="#8795a1"/></svg>
                                <span class="self-center">{{ $thread->visits }}</span>
                            </p>
                        </li>
                        <li>
                            <p class="text-grey-dark text-sm">
                                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" height="13px" width="13px" class="inline-flex"><path d="M569.9 441.1c-.5-.4-22.6-24.2-37.9-54.9 27.5-27.1 44-61.1 44-98.2 0-80-76.5-146.1-176.2-157.9C368.4 72.5 294.3 32 208 32 93.1 32 0 103.6 0 192c0 37 16.5 71 44 98.2-15.3 30.7-37.3 54.5-37.7 54.9-6.3 6.7-8.1 16.5-4.4 25 3.6 8.5 12 14 21.2 14 53.5 0 96.7-20.2 125.2-38.8 9.1 2.1 18.4 3.7 28 4.8 31.5 57.5 105.5 98 191.8 98 20.8 0 40.8-2.4 59.8-6.8 28.5 18.5 71.6 38.8 125.2 38.8 9.2 0 17.5-5.5 21.2-14 3.6-8.5 1.9-18.3-4.4-25zM155.4 314l-13.2-3-11.4 7.4c-20.1 13.1-50.5 28.2-87.7 32.5 8.8-11.3 20.2-27.6 29.5-46.4L83 283.7l-16.5-16.3C50.7 251.9 32 226.2 32 192c0-70.6 79-128 176-128s176 57.4 176 128-79 128-176 128c-17.7 0-35.4-2-52.6-6zm289.8 100.4l-11.4-7.4-13.2 3.1c-17.2 4-34.9 6-52.6 6-65.1 0-122-25.9-152.4-64.3C326.9 348.6 416 278.4 416 192c0-9.5-1.3-18.7-3.3-27.7C488.1 178.8 544 228.7 544 288c0 34.2-18.7 59.9-34.5 75.4L493 379.7l10.3 20.7c9.4 18.9 20.8 35.2 29.5 46.4-37.1-4.2-67.5-19.4-87.6-32.4z" fill="#8795a1"/></svg>
                                <span v-text="repliesCount" class="self-center"></span>
                            </p>
                        </li>
                    </ul>
                </div>
            </article>
            
            <section id="replies">
                <div class="bg-white rounded-t-lg shadow-md px-6 pb-8">
                    <replies @added="repliesCount++" @removed="repliesCount--"></replies>
                </div>
            </section>
        </div>
    </thread-view>
@endsection

Please sign in or create an account to participate in this conversation.