0

I am creating a poetry app where poetry is fetched using an API call.

I fetch data using axios library and do v-for to populate data. I use the index from v-for to populate the image for each poem respectively.

I display 10 results per page using my own custom pagination. Currently, it's only for next button though.

The problem I am facing is when I navigate to Page 2! As I said earlier, that I use v-for's index to display images, it doesn't actually update the index when I move to the next page. As a result, the images are shown same as of page 1.

Code:

new Vue({
  el: '#app',
  data: {
    proxy: 'https://cors-anywhere.herokuapp.com/',
    imageIndex: 0,
    pagination: {
      start: 0,
      end: 10,
      resPerPage: 10
    },
    fetchData: [],
    fetchImages: []
  },
  methods: {
    paginate() {
      this.pagination.start = this.pagination.start + this.pagination.resPerPage;
      this.pagination.end = this.pagination.end + this.pagination.resPerPage;
    },
    async fetchDatas() {
      try {
        const res = await axios(`${this.proxy}http://poetrydb.org/author,title/Shakespeare;Sonnet`);
        if (res) {
          this.fetchData = res.data;
        }
      } catch (error) {
        console.log(error);
      }
    },
    async fetchImagess() {
      const key = '9520054-7cf775cfe7a0d903224a0f896';
      const perPage = 154;
      const proxy = ''
      const res = await axios(`${this.proxy}https://pixabay.com/api/?key=${key}&per_page=${perPage}`);
      this.fetchImages = res.data.hits;
    }
  },
  mounted() {
    this.fetchDatas();
    this.fetchImagess();
  }
});
<div id="app">
  <div v-for="(poetry, index) in fetchData.slice(this.pagination.start, this.pagination.end)">
    <div>
      <img :src="fetchImages[index].largeImageURL.toLowerCase()" style="max-width: 100%;height: auto;max-height: 320px;">
      <div>
        <h5>{{ poetry.title }}</h5>
        <span v-for="(poetryBody, i) in poetry.lines.slice(0, 5)">
              {{ i === 4 ? poetryBody.split(',').join('') + '...' : poetryBody  }}
            </span>
        <br>
        <a href="#">Read More</a>
      </div>
    </div>
  </div>
  <nav style="padding-top: 3em;">
    <button @click="paginate()">Next</button>
  </nav>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>

JSFiddle: http://jsfiddle.net/sanjaybanjade/vnu654gk/9/

As you can see the images doesn't get updated when I goto Page 2! Please help me fix this!

And please ignore the console errors. I am gonna fix them later.

4 Answers 4

1

The quick fix would be to calculate the offset in line 4 to update on pagination:

<img v-bind:src="fetchImages[index + pagination.start].largeImageURL.toLowerCase()" style="max-width: 100%;height: auto;max-height: 320px;">

Sign up to request clarification or add additional context in comments.

Comments

0

wrong at this line fetchImages[index].largeImageURL.toLowerCase().

Since you are iterating a sliced array of fetchData, it's index is related to sliced array, not original array. So, you should apply pagination slice to your fetchImages too.

2 Comments

Will you please help me with that line? I am still confused about applying the pagination slice to fetchImages.
I suggest you to use computed properties in this case.@Sanjay That is, you should just need to update your pagination information whenever user click prev/next button. And computed properties will react to pagination change. Like this: computed: { currentImages() { return this.fetchImages.slice(this.pagination.start, this.pagination.end); }, currentData() { return this.fetchData.slice(this.pagination.start, this.pagination.end); }, } use these computed properties in your v-for directives instead.
0

When you run fetchData.slice(), it returns a new object. So if you slice out 10 new pieces of poetry, their indexes are still going to be 0-9, since the returned object only has that many items each time.

Comments

0

Why it's not working is because you only slice fetchData on this line fetchData.slice(this.pagination.start, this.pagination.end) but you don't slice the fetchImages what means fetchImages still is the same array it didn't change, meaning that index 0 is still the same image. Best is if you keep them in sync so I would add a pageData and pageImages array's and every time you change the paging you update both of them. like in a updatePageData method

new Vue ({
  el: '#app',
  data: {
      proxy: 'https://cors-anywhere.herokuapp.com/',
      imageIndex: 0,
      pagination: {
        start: 0,
        end: 10,
        resPerPage: 10
      },
      fetchData: [],
      fetchImages: [],
      pageData: [],
      pageImages: []
  },
  methods: {
    paginateNext() {
      this.pagination.start = this.pagination.start + this.pagination.resPerPage;
      this.pagination.end = this.pagination.end + this.pagination.resPerPage;
      this.updatePageData()
    },
    updatePageData () {
    	this.pageData = this.fetchData.slice(this.pagination.start, this.pagination.end)
      this.pageImages = this.fetchImages.slice(this.pagination.start, this.pagination.end)
    },
    async fetchDatas() {
      try {       
        const res = await axios(`${this.proxy}http://poetrydb.org/author,title/Shakespeare;Sonnet`);
        if(res) {
          this.fetchData = res.data;
        }
      } catch(error) {
        console.log(error);
      }
    },
    async fetchImagess() {
      const key = '9520054-7cf775cfe7a0d903224a0f896';
      const perPage = 154;
      const proxy = ''
      const res = await axios(`${this.proxy}https://pixabay.com/api/?key=${key}&per_page=${perPage}`);
      this.fetchImages = res.data.hits;
    }
  },
  mounted() {
  	Promise.all([
    	this.fetchDatas(),
      this.fetchImagess()
    ])
    .then(() => this.updatePageData())
  }
});
<div id="app">
  <div v-for="(poetry, index) in pageData">
    <div>
      <img :src="pageImages[index].largeImageURL.toLowerCase()" style="max-width: 100%;height: auto;max-height: 320px;">
      <div>
        <h5>{{ poetry.title }}</h5>
        <span v-for="(poetryBody, i) in poetry.lines.slice(0, 5)">
              {{ i === 4 ? poetryBody.split(',').join('') + '...' : poetryBody  }}
            </span>
        <br>
        <a href="#">Read More</a>
      </div>
    </div>
  </div>
  <nav style="padding-top: 3em;">
    <button @click="paginateNext()">Next</button>
  </nav>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.