Vue.js and masonry - different behavior on local and remote

772 views Asked by At

I am creating a page with images masonry, although that images will be fetched asynchronously. Also, you can filter images, so it should be re-rendered after each change.

My vue component:

<template>
    <div>
        <div class="fixed-panel">
            <h4 class="site-name">Smart Math Puzzles</h4>
            <a class="btn btn-sm btn-success" @click="difficulty = 1">easy</a>
            <a class="btn btn-sm btn-info" @click="difficulty = 2">medium</a>
            <a class="btn btn-sm btn-warning" @click="difficulty = 3">hard</a>
            <a class="btn btn-sm btn-primary" @click="difficulty = 0">all</a>
        </div>
        <div id="grid">
            <div class="grid-sizer"></div>
            <div class="grid-item" v-for="puzzle in puzzles" @click="openModal(puzzle)">
                <img :src="puzzle.imageAddress">
                <div class="overlay">
                    <span class="title">{{ puzzle.name }}</span>
                </div>
            </div>
        </div>

        <puzzle-modal></puzzle-modal>
    </div>
</template>
<script>
    import Masonry from 'masonry-layout';
    import ImagesLoaded from 'imagesloaded';
    import PuzzleModal from './PuzzleModal.vue';
    export default {
        data: function() {
            return {
                difficulty: 0,
                allPuzzles: []
            }
        },

        computed: {
            puzzles: function() {
                return this.filterPuzzlesByDifficulty(this.difficulty);
            }
        },

        watch: {
            puzzles: function() {
                this.createGrid();
            }
        },

        mounted: function() {
            this.fetchPuzzlesData();
        },

        methods: {
            fetchPuzzlesData: function() {
                this.$http.get('api/puzzles')
                    .then((response) => {
                        this.allPuzzles = response.data;
                    });
            },

            openModal: function(puzzle) {
                this.$eventHub.$emit('openModal', puzzle);
            },

            filterPuzzlesByDifficulty: function(diff) {
                if (diff === 0)
                    return this.allPuzzles;
                else
                    return this.allPuzzles.filter((puzzle) => puzzle.difficulty === diff);
            },

            imagesLoaded: function() {
                const grid = document.querySelector('#grid');
                return new ImagesLoaded(grid, () => {
                    setTimeout(() => {
                        this.masonry();
                    }, 100);
                });
            },

            masonry: function() {
                const grid = document.querySelector('#grid');
                return new Masonry(grid, {
                    percentPosition: true,
                    itemSelector: '.grid-item',
                    columnWidth: '.grid-sizer',
                });
            },

            createGrid: function() {
                if (!this.allPuzzles.length > 0)
                    return;

                this.imagesLoaded();
            }
        },

        components: {
            'puzzle-modal': PuzzleModal,
        }
    }
</script>

The problem is: On local server (where images are loaded almost instantly) everything works fine, and by everything I mean: you can filter images using computed value and they are rendered with masonry.

But on remote server this starts to break. Masonry doesn't wait for images to load and moreover, something that is very strange to me, computed value does not work. If I want to show all, and I click "all" filter it is fine, all elements are added from allPuzzles to puzzles. But any other filter (easy, medium, hard) results in computed puzzles having no elements at all.

1

There are 1 answers

0
Łukasz Szcześniak On BEST ANSWER

Okay. I've solved problem wrapping this.imagesLoaded() in this.$nextTick, so createGrid method looks like this:

this.$nextTick(() => this.imagesLoaded());

Also, problem with filtering was caused by different data types. I don't know why on local development it was overlooked.