jsonwordpressasynchronousnuxt.jsjquery-isotope

Make isotope wait till api data is loaded - nuxt js


I'm running a nuxtjs app which displays data from wordpress. On my project overview page I want to have the images of the different projects displayed as masonry with isotope and filtering. When I open the website on root and navigate to the project page (/project) everything is displayed correctly. When I reload the page or type in the URL manually, the layout is crashed. After some error handling I found out that on page reload isotope wants to layout the unloaded project data. On page enter - "projekte geladen." On reload / manually - "keine projekte".

Code:

<script>
/* eslint-disable */
let Isotope;
let imagesLoaded;
        if (process.client) {
            Isotope = require('isotope-layout');
            imagesLoaded = require('imagesloaded')
        }

export default {
    mounted() {
        this.isCaseStudy();
        this.isotope();
    },
   computed: {
       page(){
           //return this.$store.getters.filterProject;
           return this.pages.find(page => page.id === 110)
       },
       pages(){
           return this.$store.state.pages;
       },
       projects(){
           return this.$store.state.projects;
       },
   },
   created(){
       this.$store.dispatch("getPages");
       this.$store.dispatch("getProjects"); 
   },
   methods: {
       isCaseStudy(){
           $(".item").each(function(){
               $(this).has('img.case-studyImg').addClass('case-study');
           });
       },
       isotope() {
           console.log("isotope wird ausgeführt");
           
           if(this.projects.length != 0){
               console.log("projekte geladen!")
               let iso = new Isotope('.items', {
               itemSelector: '.item',
               masonry: {
                   columnWidth: '.grid-sizer'
               }
           });
            imagesLoaded(".items").on( 'progress', function() {
                // layout Isotope after each image loads
                console.log("each image loaded");
                iso.layout();
            });
                
           }else{
               console.log("keine projekte");
           }
            
               
       },
       filterItems(selector) {
           let oldActive = $(".filters .btn-primary").first();
            console.log(oldActive);
           if(oldActive.hasClass(selector)){
               return;
           }

           let currentActive = $(".filters a." + selector).first();

           console.log(currentActive);
           currentActive.removeClass("btn-default").addClass("btn-primary");
           oldActive.removeClass("btn-primary").addClass("btn-default");
           iso.arrange({filter: `.${selector}`});
       }
   }
}
</script>

So on reload the function this.isotope() is loaded before the projects() from computed loaded I believe. How can I accomplish that isotope loads when the projects are loaded if thats the real problem for this...


Solution

  • In your case when dispatching actions in the created() hook the actions just start, but you do not know when they finish, the rest of the code keeps executing. In other words, by the time this.isotope() is called, your projects are not in the store yet.

    Since you're using Nuxt, probably the best approach would be to use the asyncData hook. Using that, on first load (refreshing the page, or entering the url manually) the code inside asyncData will be executed on the server, so you're sure that the component will have the API data before rendering. It's also a faster approach, as you're leveraging the built-in nuxt SSR.

    Another option would be to use async/await. You can take a look here how that would look. You might end up with something like this:

    beforeMount() {
        this.$store.dispatch('getPages');
        this.$store.dispatch('getProjects');
    },
    

    where the getPages and getProjects functions in the store use async/await

    async getProjects(vuexContext) {
      const projects = await this.$axios.$get('http://yourapi.com/projects')
      commit('SET_PROJECTS', projects)
    }