chrisgrim's avatar

How to load content in Vue after everything has loaded?

Hi, I have a nav search on my site that when you first click on it I return a list of the most popular event names. Then as they search it searches through all event names. I have it setup now so that whenever they click on the nav search it does the first axios call then and returns the most popular event names.

I was hoping to preload those names but I can't seem to find a way to do an axios call when everything has loaded and the user can start to move around. I was thinking of doing something like

setTimeout()

but this seems like the wrong way to do it. Is there anyway to know everything has loaded and it is safe to load background data without slowing user experience? Thanks!

0 likes
6 replies
piljac1's avatar

Normally, the parent component will be mounted last (after its children), but it is not guaranteed. You can use this.$nextTick in the top level component to only apply some logic after the entire view has been rendered. Here's an example from the Vue doc:

mounted: function () {
  this.$nextTick(function () {
    // Code that will run only after the
    // entire view has been rendered
  })
}
chrisgrim's avatar

Hi @piljac1 Sorry for the late reply! I tried doing

    mounted: function () {
        this.$nextTick(function () {
            alert('test');
        })
    }

and it popped up the alert before the search menu had loaded on the page.

chrisgrim's avatar

Here is my full vue template. I realized that this component loaded inside another vue component vue-main-page has vue-nav-search inside of it.

<template>
    <div class="nav-search__content">
        <div class="icon">
            <svg aria-hidden="true" role="presentation" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" style="display: block; fill: none; height: 16px; width: 16px; stroke: currentcolor; stroke-width: 4; overflow: visible;"><g fill="none"><path d="m13 24c6.0751322 0 11-4.9248678 11-11 0-6.07513225-4.9248678-11-11-11-6.07513225 0-11 4.92486775-11 11 0 6.0751322 4.92486775 11 11 11zm8-3 9 9"></path></g></svg>
        </div>
        <multiselect 
        v-model="searchBoxInput" 
        :options="searchBoxOptions" 
        open-direction="bottom"
        :placeholder="placeholder"
        label="name"
        :loading="isLoading"
        :show-labels="false"
        :internal-search="false"
        :options-limit="30" 
        :limit="5"  
        track-by="name"
        @open="generateSearchList"
        @search-change="generateSearchList"
        @input="searchInput"
        :show-no-results="false"
        :allow-empty="false">
            <template slot="singleLabel" slot-scope="props">
                <span class="option__desc">
                <span class="option__title">
                    {{ props.option.name }}</span>
                </span>
            </template>
             <template slot="option" slot-scope="props">
                <div class="option__desc">
                    <div class="option__title" style="padding-bottom:1rem;height:2.4rem;">
                        <div style="display:inline-block;float: left;">
                            <svg v-if="props.option.type == 'c' || props.option.type == 'r' || props.option.type == 't'" viewBox="0 0 24 24" fill="currentColor" fill-opacity="0" stroke="currentColor" stroke-width="1.5" focusable="false" aria-hidden="true" role="presentation" stroke-linecap="round" stroke-linejoin="round" style="height: 24px; width: 24px; display: inline-block; overflow: visible;">
                                <path d="M7.6,19.4h8.9c2.2,0,4-1.8,4-4V6.5c0-2.2-1.8-4-4-4H7.6c-2.2,0-4,1.8-4,4v8.9C3.6,17.7,5.4,19.4,7.6,19.4z"/>
                                <path d="M20.5,7.5"/>
                                <line x1="16.3" y1="11" x2="6.8" y2="11"/>
                                <line x1="16.4" y1="11.2" x2="11.2" y2="7.5"/>
                                <line x1="16.4" y1="10.7" x2="11.3" y2="14.5"/>
                            </svg>
                            <svg v-if="props.option.type == 'o'" viewBox="0 0 24 24" fill="currentColor" fill-opacity="0" stroke="currentColor" stroke-width="1.5" focusable="false" aria-hidden="true" role="presentation" stroke-linecap="round" stroke-linejoin="round" style="height: 24px; width: 24px; display: inline-block; overflow: visible;">
                                <path d="M20.5,11c0-5-4.3-9-9.5-8.4C7.3,3,4.2,6,3.7,9.8c-0.4,2.9,0.7,5.5,2.6,7.3c0.1,0.1,0.3,0,0.2-0.1 c-0.2-0.9-0.2-1.9,0.1-3c0.6-2,2.4-3.6,4.4-3.9c3.7-0.7,6.9,2.1,6.9,5.7c0,0.5-0.6,1.3-0.2,1.4C19.5,15.7,20.5,13.4,20.5,11z"/>
                                <path class="st0" d="M12.2,10c-3.2,0-5.8,2.6-5.8,5.8c0,0.6,0.1,1.1,0.2,1.7c1.5,1.2,3.4,2,5.5,2c2.2,0,4.2-0.9,5.7-2.2 c0.1-0.5,0.2-0.9,0.2-1.4C18,12.6,15.4,10,12.2,10z"/>
                                <path class="st0" d="M20.5,7.5"/>
                                <circle class="st0" cx="12.1" cy="7.2" r="2.4"/>
                            </svg>
                            <svg v-if="props.option.call_to_action" viewBox="0 0 24 24" fill="currentColor" fill-opacity="0" stroke="currentColor" stroke-width="1.5" focusable="false" aria-hidden="true" role="presentation" stroke-linecap="round" stroke-linejoin="round" style="height: 24px; width: 24px; display: inline-block; overflow: visible;">
                               <path d="M8.6,19.4h6.9c2.8,0,5-2.2,5-5V7.5c0-2.8-2.2-5-5-5H8.6c-2.8,0-5,2.2-5,5v6.9C3.6,17.2,5.8,19.4,8.6,19.4z"/>
                                <line x1="3.6" y1="7.5" x2="20.5" y2="7.5"/>
                                <line x1="8.6" y1="2.5" x2="8.6" y2="1.2"/>
                                <line x1="15.3" y1="2.5" x2="15.3" y2="1.2"/>
                            </svg>
                            <svg v-if="props.option.latitude" viewBox="0 0 24 24" fill="currentColor" fill-opacity="0" stroke="currentColor" stroke-width="1.5" focusable="false" aria-hidden="true" role="presentation" stroke-linecap="round" stroke-linejoin="round" style="height: 24px; width: 24px; display: inline-block; overflow: visible;"><path d="M12.2,2.2c-3.9,0-7.1,3.2-7.1,7.1c0,5.7,6.4,10.9,6.4,10.9c0.4,0.3,1,0.3,1.4,0c0,0,6.4-5.2,6.4-10.9
                            C19.2,5.4,16.1,2.2,12.2,2.2z M12.1,11.6c-1.5,0-2.7-1.2-2.7-2.7s1.2-2.7,2.7-2.7s2.7,1.2,2.7,2.7S13.6,11.6,12.1,11.6z"/></svg>
                        </div>
                        <div style="display:inline-block;float: left;margin-top:.5rem;padding-left:1rem;width: 90%;white-space: nowrap;">
                            {{ props.option.name }}
                        </div>
                    </div>
                </div>
            </template>
        </multiselect>      
    </div>
</template>

<script>
import Multiselect from 'vue-multiselect'
import _ from 'lodash'


export default {

    components: { Multiselect },

    computed: {
    },


    data() {
        return {
            searchBoxInput: [],
            searchBoxOptions: [
                {name: 'Loading List...'}
            ],
            isLoading: false,
            search: this.initializeSearchObject(),
            placeholder: new URL(window.location.href).searchParams.get("name") ? new URL(window.location.href).searchParams.get("name") : window.innerWidth < 768 ? 'Search' : 'Search by event name, category, location, or tag',
            type: '',
        }
    },

    methods: {

        generateSearchList (query) {
            axios.get('/api/search/navbar/content', { params: { keywords: query } })
            .then(res => {
                console.log(res.data);
                this.searchBoxOptions = res.data.data;
            });
        },

        initializeSearchObject() {
            return {
                name: '',
                latitude: '',
                longitude: '',
            }
        },

        searchInput() {
            this.searchBoxInput.type == 'c' ? window.location.href = `/index/search-online?category=${this.searchBoxInput.name}&id=${this.searchBoxInput.id}` : '';
            this.searchBoxInput.type == 'r' ? window.location.href = `/index/search-online?remote=${this.searchBoxInput.name}&id=${this.searchBoxInput.id}` : '';
            this.searchBoxInput.type == 't' ? window.location.href = `/index/search-online?tag=${this.searchBoxInput.name}&id=${this.searchBoxInput.id}` : '';
            this.searchBoxInput.type == 'o' ? window.location.href = `/organizer/${this.searchBoxInput.slug}` : '';
            this.searchBoxInput.call_to_action ? window.location.href = `/events/${this.searchBoxInput.slug}` : '';
            this.searchBoxInput.latitude ? this.globalSearch() : '';

        },

        globalSearch() {
            window.location.href = `/index/search?name=${this.searchBoxInput.name}&lat=${this.searchBoxInput.latitude}&lng=${this.searchBoxInput.longitude}`;
        },

    },

    mounted: function () {
        this.$nextTick(function () {
            alert('test');
        })
    }

};
</script>
piljac1's avatar

Have you tried placing your this.$nextTick in the top level component as suggested in Vue's doc ? You placed it in a child component.

chrisgrim's avatar

Ok I tried adding it to my main component and it shows the alert before anything on my page loads.

<template>
    <div class="event-index-container">
        <div class="event-index">
            <header class="padded">
                <div class="header-title">
                    <h3>Discover immersive experiences...</h3>
                </div>
                <div class="index-nav-search">
                    <nav-search></nav-search>
                </div>
            </header>

            <section id="latestevents" class="padded staffpicks__banner" v-if="staffpicks">
                <div class="banner-title__staffpicks">
                    <h3>This Week's Staff Picks</h3>
                </div>
                <div class="staffpicks__selection">
                    <a :href="`/events/${staffpicks.event.slug}`">
                        <div class="staffpicks__selection--main">
                            <div class="staffpicks__image">
                                <picture>
                                    <source type="image/webp" :srcset="`/storage/${staffpicks.event.thumbImagePath}`"> 
                                    <img :src="`/storage/${staffpicks.event.thumbImagePath.slice(0, -4)}jpg`" :alt="`${staffpicks.event.name} Immersive Event`">
                                </picture>
                            </div>
                            <div>
                                <div class="staffpicks__title">
                                    <h4>{{staffpicks.event.name}}</h4>
                                    <p>{{staffpicks.event.organizer.name}}</p>
                                </div>
                                <div class="staffpicks__user">
                                    <picture>
                                        <source type="image/webp" :srcset="`/storage/${staffpicks.user.thumbImagePath}`"> 
                                        <img :src="`/storage/${staffpicks.user.thumbImagePath.slice(0, -4)}jpg`" :alt="`${staffpicks.user.name} Immersive Event`">
                                    </picture>
                                    <div class="staffpicks__user--name">
                                        <p>{{staffpicks.user.name}}</p>
                                    </div>
                                </div>
                                <div class="staffpicks__summary">
                                    <p>" {{staffpicks.comments}} "</p>
                                </div>
                            </div>
                        </div>
                    </a>
                    <a href="/staffpicks/current">
                        <div class="staffpicks__selection--loadmore">
                            <h3>Check out the rest of the picks here.</h3>
                        </div>
                    </a>
                </div>
            </section>
            
            <section id="latestevents" class="padded event-list">
                <div class="header-title">
                    <h3>Latest events</h3>
                </div>   
                <div class="event-index-eventlist grid">
                    <div v-for="(event, index) in eventList" class="eventlist__element">
                        <vue-event-index :event="event"></vue-event-index>
                    </div>
                </div>
                <div class="see-more-events">
                    <a href="/index/search-online">
                        <button class="default"> See More Events</button>
                    </a>
                </div>
            </section>

            <section class="announcement padded">
                <div class="header-title__announcement">
                    <h3>Read The 2020 Immersive Entertainment Industry Annual Report</h3>
                    <p>Discover The Strength of Immersive Entertainment!</p>
                    <br>
                    <p><a href="/storage/website-files/documents/2020 Immersive Entertainment Industry Annual Report.pdf"><button class="black">Check out the report here</button></a></p>
                </div>
            </section>

            <section>
                <div class="index-contributers">
                    <h3>Check out our partners</h3>
                    <div class="contributer-content grid">
                        <div class="contributer__element" >
                            <a target="_blank" rel="noopener noreferrer" href="https://www.argn.com/">
                                <button style="background: url('/storage/website-files/argn-logo.jpg') center center / cover no-repeat;" class="contributer--button"></button>
                            </a>
                        </div>
                        <div class="contributer__element" >
                            <a target="_blank" rel="noopener noreferrer" href="https://roomescapeartist.com/">
                                <button style="background: url('/storage/website-files/rea-logo.png') center center / cover no-repeat;" class="contributer--button"></button>
                            </a>
                        </div>
                        <div class="contributer__element" >
                             <a target="_blank" rel="noopener noreferrer" href="https://noproscenium.com/">
                                <button style="background: url('/storage/website-files/nopro-logo.jpg') center center / cover no-repeat;" class="contributer--button"></button>
                            </a>
                        </div>
                        <div class="contributer__element" >
                             <a target="_blank" rel="noopener noreferrer" href="https://www.herefest.com/">
                                <button style="background: url('/storage/website-files/here-logo.png') center center / cover no-repeat;" class="contributer--button"></button>
                            </a>
                        </div>
                    </div>
                </div>
            </section>
            
            


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

<script>
    import _ from 'lodash';
    import Multiselect from 'vue-multiselect';
    import format from 'date-fns/format';
    import catitem  from '../events/components/cat-item.vue';
    import SearchFilter  from './components/filter-remote.vue'
    import LoadMore  from '../../components/LoadMore.js'


    export default {

        components: { Multiselect, catitem, SearchFilter, LoadMore },

        props:['events', 'categories', 'staffpicks'],

        computed: {
            user () {
                return this.$store.state.user ? this.$store.state.user : ''
            }
        },

        data() {
            return {
                eventList: this.events ? this.events : [],
                value: '',
                list: [],
                price: '',
                eventName: '',
                location: [],

            }
        },

        methods: {

            

        },

        mounted: function () {
            this.$nextTick(function () {
                alert('test');
            })
        }

    };
</script>

Please or to participate in this conversation.