Bootstrap-Vue pagination not displaying the updated sliced array content on screen - vue.js

Im using bootstrap vue's pagination component to break up and display content from a v-for loop. I am slicing the array perPage. Everything seems to be working. the correct number of perPage is displayed. The correct number of rows. The only problem is that when I select a new page, the content is never updated on the screen. It shows the same data on every page.
I have console logged the sliced array depending on what page and the slice is happening and working on everyPage click, I just cant get that new array to display on screen.
<b-paggination v-model="currentPage" :total-rows="rows" :per-
page="perPage" aria-controls="my-table" </b-pagination>
<b-col v-if="!showLoad" class="mb-4" v-for="(data,index) in
listOfData" id="my-table" :key="index" cols="12>
<app-card v-bind:data="Data[index]></app-card>
</b-col>
computed: {
rows() {
return this.data.length;
}
listOfData() {
const items = this.Data
return items.slice((this.currentPage - 1) * this.perPage,
this.currentPage * this.perPage);
}
}

Update: I discovered that injecting the content from the v-for into the imported card component (app-card) was somehow stoping the content from updating from page to page. I just removed the app-card component and hard coded a card in its place.. Now for some reason the content is changing from page to page.
```
//This Works:
<div v-for="(data, index) in listOfData" :key="index">
<b-card
overlay
img-src="https://picsum.photos/900/250/?image=3"
img-alt="Card Image"
text-variant="white"
title="Image Overlay"
sub-title="Subtitle"
>
<b-card-text>
{{ data.Data }}
</b-card-text>
</b-card>
</div>
//This Doesnt Work:
<div v-for="(data, index) in listOfData" :key="index">
<app-card v-bind:Dataprop="Data"></app-card>
</div>```

Related

Vue Bootstrap, how to interact with plus/minus icon on dynamic generated collapse content separately

I have a VueJS view that creates collapsed contents using Bootstrap Vue Collapse Component.
The data is dynamic and can contains hundreds of items, which is why you see in the code below it was created via a v-for loop in Vue.
<div class="inventory-detail" v-for="(partNumberGroup,index) in inventory" :key="index" >
<b-button block v-b-toggle="partNumberGroup.partNumber" v-bind:id="partNumberGroup.partNumber" variant="primary"
#click="(evt) =>{isActive = !isActive && evt.target.id == partNumberGroup.partNumber}">
<i v-bind:id="partNumberGroup.partNumber" class="float-right fa" :class="{ 'fa-plus': !isActive, 'fa-minus': isActive }"></i>
{{ partNumberGroup.partNumber }}
</b-button>
<div class="inventory-detail__card" v-for="item in partNumberGroup.items">
<b-collapse v-bind:id="partNumberGroup.partNumber" >
<b-card>
<!--Accordion/Collapse content -->
</b-card>
</b-collapse>
</div>
</div>
This works fairly well in that I can individually expand and collapse each content separately. However, the one issue I'm facing is each time I click the icon fa-minus (-) orfa-plus (+), all of them changed as per the images below.
Any tips on how I should implementing this? in my code I tried the dynamic CSS class switching but I still lack the ability to switch on specific element.
I feel like the solution to this is to somehow conditionally apply dynamic CSS class or somehow able to use the attribute 'aria-expanded'.
You can try something like this. Whenever somebody clicks on the icon, set its index as activeIndex (using the setActiveIndex method). Then you can set the class accordingly by comparing the activeIndex with current index
<i
#click="setActiveIndex(index)"
v-bind:id="partNumberGroup.partNumber"
class="float-right fa"
:class="{ 'fa-plus': !isActive(index), 'fa-minus': isActive(index) }">.
</i>
then in the script part:
...
data() {
return {
activeIndex: -1
}
},
methods: {
/* set active index on click */
setActiveIndex(index) {
this.activeIndex = index;
},
/* check if index is active or not */
isActive(index) {
return index === this.activeIndex;
}
}

Vue: Why only the last object is only associated to every modal which is in for loop

This is the first time I am using modal component. Inside a for loop of an array of objects, I also added a modal component, "Add Item". The v:onClick="showSectionID" function in the SHOW button within the modal should just consolelog the id of the object who's associated modal was opened and click it's respective SHOW button. But instead it is giving the id of the last object wherever I click the SHOW button from any of associated modals.
Just to test, I removed the whole modal and only kept the SHOW button and in this case it gives me the correct id. I really cannot figure out what s is wrong in the modal and searched several sources in the internet to see a similar solution but couldn't find. See code:
<div v-for="(section) in allDataObject['Section']" :key="section['uuid']">
<h4>Section Name: {{ section["sectionName"] }}</h4>
<h4>Section Description: {{ section["sectionDescription"] }}</h4>
<template>
<div>
<b-button #click="modalShow = !modalShow">Add Item</b-button>
<b-modal v-model="modalShow">Fill form to add an item !
<button v-on:click="showSectionID (section['uuid'])">SHOW</button>
</b-modal>
</div>
</template>
</div>
In your code, you are creating a modal component for each section within the for loop.
I wouldn't be surprised if actually all your modals show up on the screen, but you see the last one because it's on top of all the other ones. But it also depends on how the modal is implemented.
I suggest you to move the modal template outside your for loop and change what you store in your component data so that you know which section to show in the modal.
Let's say your data() will look like this:
data() {
return {
modalVisible: false,
modalSectionUUID: null
}
}
Then you can create two methods to show and hide the modal:
methods: {
showModal(sectionUUID) {
this.modalVisible = true;
this.modalSectionUUID = sectionUUID;
},
hideModal() {
this.modalVisible = false;
this.modalSectionUUID = null;
}
}
Now, your template will finally look something like this:
<b-modal v-model="modalVisible">Fill form to add an item !
<button v-on:click="showSectionID(modalSectionUUID)">SHOW</button>
</b-modal>
<div v-for="(section) in allDataObject['Section']" :key="section['uuid']">
<h4>Section Name: {{ section["sectionName"] }}</h4>
<h4>Section Description: {{ section["sectionDescription"] }}</h4>
<template>
<div>
<b-button #click="showModal(section['uuid'])">Add Item</b-button>
</div>
</template>
</div>

Async calls with Apollo + Vue

Currently, I am trying to fetch data from my server, but the problem that I am running into is that the data takes a little time to fetch(in postman though it is instantaneous), longer than it takes the DOM to get mounted/loaded, and hence I get errors(data not defined) and nothing will load to the DOM.
If I console.log the data after the DOM has finished mounting then I can see it in the console, but I haven't been able to find a workaround where the component waits to render until the data is fetched.
I tried using a v-if statement, and writing it in a few different ways, but I am still getting the errors of the data not being defined, and it does not load either after the query is done fetching. Currently I've set the data to first be equal to null, which in JS is actually an object and it does get filled with the data after the fetching is done. I can see this in the console. Before that I tried a simple v-if="GameWeek", and with GameWeek defined as both an empty object and an empty array, but none of these will work, and force the component to wait until the data is done fetching.
My question is, is there any way to do this asynchronously, or better yet, make the component wait until the data has been fetched and then correctly load it to the DOM?
This is what my component looks like:
<template>
<!-- Highest climber & longest fall -->
<v-container>
<v-card class="card-container mx-auto" v-if="GameWeek !== null" :v-for="player in GameWeek" :key="player.player_id">
<!-- Top part of card -->
<v-list-item three-line>
<v-list-item-content>
<div class="card_top_section">
<v-avatar>
<img
src="https://cdn.vuetifyjs.com/images/john.jpg"
alt="John"
>
</v-avatar>
<div class="ml-3">
<p class="cardText player_name">
{{ player.player_name }}
</p>
<p class="cardText team_name">
{{ player.team_name }}
</p>
</div>
</div>
<div class="card_divs mt-7">
<p class="cardText points">
Points this week {{ player.points }}
</p>
<!-- <p class="points_green points">
</p> -->
</div>
<!-- Second Row Card -->
<div class="card_divs bottom_line">
<p class="cardText points">
Total points {{ player.total }}
</p>
<!-- <p class="points_green points">
</p> -->
</div>
</v-list-item-content>
</v-list-item>
</v-card>
</v-container>
</template>
<script>
import gql from 'graphql-tag'
export default {
name: 'PlayerCard',
data: () => {
return {
GameWeek: null
}
},
apollo: {
GameWeek: gql`query GameWeek {
GameWeek {
team_id
points
player_name
rank
previous_rank
total
player_id
team_name
}
}`
},
mounted() {
console.log('This is the gameweek', this.GameWeek)
},
}
</script>
Well, turns out this was easy to solve once I found the issue.
It was the : infront of the v-for statement. Once that was removed it all worked :)

v-on:click not working - dynamically added html element

I am trying to get all images for a category using Vue
<div class="col-md-12 col-sm-2 p-2">
<a v-on:click="onCategoryManageImageClick($event)" data-target="#location-
category-images">
</span>
</a>
</div>
So the event onCategoryManageImageClick ($event) does not work, if I am adding a html block and then click on get image button.
this is index.js
methods:{
onImagesTabClick(){
this.$root.$emit('activated-tab:location-images');
},
onCategoriesTabClick(){
window.j1App.eventBus.$emit("j1-location-image-list:shown");
},
onCategoryManageImageClick: function(event) {console.log('working event..');
event.preventDefault();
window.j1App.eventBus.$emit("j1-location-category-image-
list:shown",event.currentTarget.id);
}
}
So basically it need to to work like we do in jQuery
$(document).on('click',function{
})
So it works either page load or if adding any new html element on DOM. same I want in Vue.
You cannot alter the Vue template outside of Vue. That won't work. Vue compiles the template once when starting up and adds the event listeners to the rendered elements. If you add elements afterwards, Vue will not know about them.
The correct way of doing this would be to add those new elements in Vue.
<div
class="col-md-12 col-sm-2 p-2"
v-for="item in items"
:key="item.id"
>
<a
v-on:click="onCategoryManageImageClick($event, item)"
data-target="#location-category-images"
>
</a>
</div>
See https://v2.vuejs.org/v2/guide/list.html for documentation. In this case you need the items array variable in data and add more array elements to it, if you need more links.
Try raplacing your a tag with p
<div class="col-md-12 col-sm-2 p-2">
<p v-on:click="onCategoryManageImageClick" data-target="#location-
category-images">
</p>
</div>

vue-instagram : images showing as icons, even though src/url is correct

I'm using the vue-instagram component to display images from my own instagram account..
The url's are correct (when i inspect element, and open the url in new tab, the image shows up...), but it only shows up as an icon (see image below)..
Here's my code : (boilerplate from example) :
<template>
<vue-instagram token="209161622.1677ed0.cd18b9a41f0c4a53b646b8f012f465ab" :count="5" mediaType="image">
<template slot="feeds" slot-scope="props">
<!-- <li class="fancy-list"> {{ props.feed.link }} </li> -->
<img :src="props.feed.link" />
</template>
<template slot="error" slot-scope="props">
<div class="fancy-alert"> {{ props.error.error_message }} </div>
</template>
</vue-instagram>
import VueInstagram from 'vue-instagram'
export default {
components: {
VueInstagram,
}
}
</script>
As you see from the image below, it only display the icon, not the picture itself :
Here is the rendered HTML :
Any idea what i'm doing wrong here ?
Your links are to the post (an HTML page), not directly to the image so they cannot be displayed as images.
From snooping around the component's Github page, it seems you want
<img :src="props.feed.images.low_resolution.url" alt="Image">