Passing data to global component in vuejs

Viewed 311

It's my first question on stackoverflow. Please feel free to tell if I need to edit it.

I've created global component, that's called Popup.vue

<div class="popup-background" id="vue-popup" @click.self="$emit('close')">
    <div class="popup-info-box" :class="customClasses" :style="infoBoxPosition()">            
        <slot></slot>
    </div>
</div>

<script>
export default {
    props : {
        customClasses : {
            default : () => '',
        },
    },
    data() {
        return {
            hasMounted : false,
        }
    },
    methods : {
        infoBoxPosition() {
            if( !this.hasMounted ) {
                return { 'right' : '0px', 'top' : '0px' };
            }

            let parent = document.querySelector('#vue-popup').parentElement;
            let bounds = parent.getBoundingClientRect();

            return { 'right' : ( document.body.clientWidth - bounds.right ) + 'px', 'top' : bounds.bottom + 'px' };
        }
    },
    mounted() {
        this.hasMounted = true;
    },
}

Current behaviour

I'm passing html to my Popup.vue component directly from my filter component.

Example : Filter.vue

<div class="menu" v-for="( filter, key ) in filters">
        <div class="filter-button" @click="openMenu( key )">
            <span>
                {{ $t(`filters.${key}`) }}
            </span>
        </div>
        <transition name="fade">
            <Popup :customClasses="{ 'filter-menu' : filter.hide }" v-show="getActiveMenu == key" @close="toggleMenu( '' )">
                <div class="filter-menu-top">
                    <div>
                        {{ filter.values.min }}
                    </div>
                    <div>
                        {{ filter.values.max }}
                    </div>
                </div>
                <div class="filter-menu-bottom">
                    <div class="filter-action-button apply" @click="applyFilter( filter, key )">
                        {{ $t(`filters.actions.apply`) }}
                    </div>
                </div>
            </Popup>
        </transition>
    </div>

Problem

I have registered Popup.vue as global component, I can now use it in every other component without need to import it. That's great, but I have another problem.

I want to dynamically change content of Popup.vue. For example, when user clicks filter button, he's supposed to see filter menu inside a popup. When user clicks sing in, he sees signin form inside popup, and so on.

Popup.vue supposed to be quite generic and I'd like to use it everywhere I need that dropdown behaviour. How can I manage the content of the Popup, without using it in template of each component??

Desired solution

Some way to put Popup.vue component in my App.vue component and manage popup content from any component without putting my popup in every component I need.

Thoughts

I thought about using Vuex and binding some actions in each component to send template as string to Vuex state and read it in my Popup.vue component. But it seems like unreliable and unscalable solution.

Thanks in advance.

0 Answers
Related