0

I'm using this code to learn vuejs and to make a portfolio infinite scroll using the WordPress REST API. I'm able to render the first ten post but on scroll vue will stop working and give me this error that is related to the featured images url provided by the api:

[Vue warn]: Error in render: "TypeError: Cannot read property 'wp:featuredmedia' of undefined" (found in Root)

The code line that reference the error is this self.posts.push(data);

TypeError: Cannot read property 'wp:featuredmedia' of undefined

And this line for this other error:

$.getJSON( 'wp-json/wp/v2/posts?categories=3&page='+page+'&per_page=10&_embed', function(data){}

Here is the code:

<?php get_header(); ?>

<div class="container" id="app">
  <div class="row" style="padding:2em;margin:2em 0 0 0;" v-on:scroll="loadItems()">
    <div class="card-columns">
      <div class="card" v-for="post in posts">
        <img class="card-img-top" v-bind:src="post._embedded['wp:featuredmedia'][0].source_url" />
        <h4 class="" v-html="post.title.rendered"></h4>
      </div>
    </div>
  </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
(function($){
  $(document).ready(function(){

  var page = 1;
  var canBeLoaded = true;
  var app = new Vue({
    el: '#app',
    data: {
      posts: []
    },
    created: function() {
      window.addEventListener('scroll',this.loadItems);
    },
    destroyed: function() {
      window.removeEventListener('scroll', this.loadItems);
    },
    mounted: function(){
      console.log('mounted fired');
      var self = this;
      $.getJSON( 'wp-json/wp/v2/posts?categories=3&page=1&per_page=10&_embed', function(data){
        console.log(data);
        self.posts = data;
      });
    },
    methods: {
      loadItems: function(){
        var bottomOffset = 2000;
        var self = this;
          if( $(document).scrollTop() >= ( $(document).height() - $(window).height() - 10 ) && canBeLoaded == true ){
            console.log('loadItems method fired');
            console.log(page);
            canBeLoaded = false;
            $.getJSON( 'wp-json/wp/v2/posts?categories=3&page='+page+'&per_page=10&_embed', function(data){
              if( data.length > 0 ){
                self.posts.push(data);
                page++;
              }
            }).done(function(){
              canBeLoaded = true;
            });
          }
      }, // end loadItems
    } // end methods
  });

  // for debug and prototype only - remove in production

  // var root = $('html, body');
  //   $('#scroll-link').on('click', function(e){
  //     e.preventDefault();
  //       root.animate({
  //           scrollTop: $( $.attr(this, 'href') ).offset().top
  //       }, 500);
  //       return false;
  //   });
  //

  }); // doc ready
}(jQuery));
</script>

I'm sure that the images is returned but why I get this error?

4
  • That means some posts returned for the query do not have a featured image, hence you should check that the post._embedded['wp:featuredmedia'] is defined before you access it. But this is a more of a JS question that's better asked on Stack Overflow. – Sally CJ Feb 14 '20 at 1:29
  • The problem was with the array processed using .push, I found a solution that I will post soon – sialfa Feb 14 '20 at 9:03
  • Yes, I forgot the data might be empty or whatever. You can ignore that and this comment, as I'm deleting them soon. Cheers! – Sally CJ Feb 14 '20 at 9:35
  • 1
    @SallyCJ don't worry, thanks for the help. I'm learning vue.js to apply it's functionality on certain wordpress projects. – sialfa Feb 14 '20 at 12:31
0

I found a solution after I've read how vue works under the hood when the data are updated. My problem was that the Array.push() function was adding the new fetched data inside the original array as a nested array. This was causing the problem with the v-for loop that was not able to iterate over the nested array. Someone has suggested me to use the spread operator, but this solution was updating the original data correctly, but at the same the previous posts were replaced at all by the new data and this isn't the behaviour that I was expect from an infinite scroll loading. The code I have now works fine, the best approach I've found and tested is to use the server-side rendering to generate the initial posts and then at scroll use vue to load new items. In the code I'm using the load

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
(function($){
  $(document).ready(function(){

  var page = 1;
  var canBeLoaded = true;
  var app = new Vue({
    el: '#app',
    data: {
      posts: []
    },
    created: function() {
      window.addEventListener('scroll',this.loadItems);
    },
    destroyed: function() {
      window.removeEventListener('scroll', this.loadItems);
    },
    mounted: function(){
      console.log('mounted fired');
// this part works fine, but I've opted for a server-side rendering for the initial contents
      var self = this;
      $.getJSON( 'wp-json/wp/v2/posts?categories=3&page=1&per_page=10&_embed', function(data){
        console.log(data);
        self.posts = data;
      });
    },
    methods: {
      loadItems: function(){
        var bottomOffset = 2000;
        var self = this;
          if( $(document).scrollTop() >= ( $(document).height() - $(window).height() - 10 ) && canBeLoaded == true ){
            console.log('loadItems method fired');
            console.log(page);
            canBeLoaded = false;
            $.getJSON( 'wp-json/wp/v2/posts?categories=3&page='+page+'&per_page=10&_embed', function(data){
              if( data.length > 0 ){
                self.posts = self.posts.concat(data);
                page++;
              }
            }).done(function(){
              canBeLoaded = true;
            });
          }
      }, // end loadItems
    } // end methods
  });

  // for debug and prototype only - remove in production

  // var root = $('html, body');
  //   $('#scroll-link').on('click', function(e){
  //     e.preventDefault();
  //       root.animate({
  //           scrollTop: $( $.attr(this, 'href') ).offset().top
  //       }, 500);
  //       return false;
  //   });
  //

  }); // doc ready
}(jQuery));
</script>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.