Vue-Slick and v-for with dynamic data - vue.js

i'm using vue-slick to show my images..
i've tried every solution that i found.. but none is working.
here is my template:
<slick ref="slick" :options="slickOptions">
<img v-for="(item) in categories" :src="'/images/category/'+item.image_url" alt="" class="img-fluid" >
</slick>
and here is my scripts:
data () {
return {
categories:'',
slickOptions: {
dots: true,
infinite: false,
autoplay: false,
arrows : false,
draggable:true,
speed: 1000,
slidesToShow: 1,
slidesToScroll: 1,
},
}
},
mounted() {
let _this = this;
axios({
method: 'post',
url: '/api/category',
data : {'name' : _this.name}
}).then( (response)=> {
console.log(response.data.data);
_this.categories = response.data.data;
}).catch((error) => {
console.log(error.response)
});
},
methods:{
next() {
this.$refs.slick.next();
},
prev() {
this.$refs.slick.prev();
},
reInit() {
this.$refs.slick.reSlick()
}
},
and only loading the image, and the slick is not working...!!?

I have faced the same issue, and what I did to solve this is to put the
v-if="categories.length > 0" on the <slick> tag.
It make the slick won't be created before the data that we want to display contains the data first.

Use below code to reinit slick, and call on success function of response
reInit() {
let currIndex = this.$refs.slick.currentSlide()
this.$refs.slick.destroy()
this.$nextTick(() => {
this.$refs.slick.create()
this.$refs.slick.goTo(currIndex, true)
})
}

I'm assuming your Axios is returning data with the structure you are looking for.
I'm also assuming you are using the vue-slick component and not slick.
You should iterate through a DIV like stated in the documentation. Without Axios, I did this:
In template:
<slick ref="slick" :options="slickOptions">
<div>Escolhe uma configuraĆ§Ć£o...</div>
<div v-for="d in data1"><a class="inline" :href="d.image"><img :src="d.image" alt="">{{ d.text }}</a></div>
</slick>
In Javascript:
data: function() {
return {
data1: [
{ image: 'http://placehold.it/100x100', text: 'Config1' },
{ image: 'http://placehold.it/100x100', text: 'Config2' },
{ image: 'http://placehold.it/100x100', text: 'Config3' },
{ image: 'http://placehold.it/100x100', text: 'Config4' }
]
}

Related

Vue.js access variable from method

I try to fetch stocks data from an API. This data should be used to create a chart.js graph.
how do I access in vue.js data to generate a chart.js line chart from the methods http(axios) call?
Is it possible to access the data directly in the mounted component or should I define a const in the section and create the variables there?
<template>
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<div>Selected: {{ selected }}</div>
<div>
<canvas id="myChart" height="200" width="650"></canvas>
</div>
<script>
export default {
mounted() {
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: "line",
data: {
labels: [prices[0].date],
datasets: [
{
label: 'Dataset msft',
data: prices[0].price
},
{
label: 'Dataset google',
data: prices[1].price
},
],
},
});
},
data() {
return {
selected: "",
prices: [],
options: [
{ text: "msft", value: "msft" },
{ text: "GOOGL", value: "GOOGL" },
],
};
},
watch: {
selected: function () {
this.getPrice();
},
},
methods: {
getPrice: function () {
var this_ = this;
axios
.get(
"https://site/...."
)
.then((response) => {
// JSON responses are automatically parsed.
this_.prices = response.data;
})
},
},
};
</script>
Yes, you can access variables in data() from mounted().
You need to prepend variables with this. when using the Options API
ex: this.prices[0].price
As you are putting watcher on selected but I did not see any changes in the selected variable in your code. As per my understanding you are making an API call to get the graph data based on the selected option.
If Yes, Instead of generating a chart in mounted you can generate it inside your getPrice() method itself based on the response. It should be :
methods: {
getPrice: function () {
var this_ = this;
axios
.get(
"https://site/...."
)
.then((response) => {
this.generateChart(response.data);
})
},
generateChart(prices) {
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: "line",
data: {
labels: [prices[0].date],
datasets: [
{
label: 'Dataset msft',
data: prices[0].price
},
{
label: 'Dataset google',
data: prices[1].price
}
]
}
});
}
}
Here, a very basic example:
<script>
export default {
async mounted() {
await this.$nextTick();
const ctx = document.getElementById("myChart");
this.chart = new Chart(ctx, {
type: "line",
data: {
labels: [],
datasets: [],
},
});
},
data() {
return {
selected: "",
chart: null,
options: [
{ text: "msft", value: "msft" },
{ text: "GOOGL", value: "GOOGL" },
],
};
},
watch: {
selected: function () {
this.getPrice();
},
},
methods: {
async getPrice() {
let { data } = await axios.get("https://site/....");
this.chart.data.datasets = [{ label: "dummy data" , data: [2, 3, 4]}];
this.chart.data.label = [1, 2, 3];
this.chart.update(); //very important, always update it
},
},
};
</script>
You create a property called chart and save your chart to it.
Then, after you fetch your data, you can access your chart with this.chart and then you set your datasets and labels. Whenever you make an change to the chart, use this.chart.update() to update it on the browser.
If you execute this code, you should see some dummy data in the chart

How can I re-initialise vue-awesome-swiper with a different loop setting?

I'm using vue-awesome-swiper for a product gallery. The user can select a different product and I want the gallery to update accordingly.
If the product has more than 1 image (most cases), I want the swiper to use the loop feature. If the product only has 1 image, I want it to work without the loop feature.
Assuming I'm able to capture when it should be true or false at the right time, how can I get the swiper to update or re-initialise with a different setting for the loop feature?
I've tried every combination of
this.swiper.destroy()
this.swiper.init()
new Swiper()
this.swiper.passedParams.loop = true/false
Whatever I do, either the loop feature stays, or the swiper doesn't actually initialise.
Edit: This is a really simplified version of the code. You will probably ask "why is he doing that?" on a couple of bits. It would make sense if you saw the full code, but its a bit too large to post here. Either way, it should not affect in responding with a solution for the loop problem.
<template>
<div class="pdp-main__gallery">
<swiper ref="mainSwiper"
id="pdpMainSwiper"
:options="mainSwiperOptions"
:data-swiper-group-id="swiperGroup"
:auto-update="true"
:auto-destroy="true"
>
<swiper-slide v-if="galleryProduct.LargeImage[1]">
<img ref="image" :data-href="galleryProduct.ExtraLargeImage[1]" :src="galleryProduct.LargeImage[1]" />
</swiper-slide>
<swiper-slide v-if="galleryProduct.LargeImage[2]">
<img ref="image" :data-href="galleryProduct.ExtraLargeImage[2]" :src="galleryProduct.LargeImage[2]" />
</swiper-slide>
<swiper-slide v-if="galleryProduct.LargeImage[3]">
<img ref="image" :data-href="galleryProduct.ExtraLargeImage[3]" :src="galleryProduct.LargeImage[3]" />
</swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
</swiper>
</div>
</template>
<script>
import { Swiper, SwiperSlide, directive } from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'
export default {
components: {
Swiper,
SwiperSlide,
},
props: {
swiperGroup: {
type: String,
required: true,
},
product: {
type: Object,
required: false,
default() {
return undefined;
},
},
},
data(){
return {
galleryProduct: {
LargeImage: {},
ExtraLargeImage: {},
},
mainSwiperOptions: {
loop: true,
watchOverflow: true,
setWrapperSize: false,
initialSlide: 0,
spaceBetween: 5,
centeredSlides: true,
slidesPerView: 'auto',
normalizeSlideIndex: false,
freeMode: false,
autoHeight: APP.Browser().data.isMobile,
followFinger: APP.Browser().data.isMobile,
pagination: {
el: '.swiper-pagination',
type: 'bullets',
clickable: true,
},
},
}
},
computed: {
mainSwiper() {
return this.$refs.mainSwiper.$swiper
},
shouldLoop() {
if(this.product.LargeImage1 && this.product.LargeImage2) return true; else return false;
},
},
created() {
this.setGalleryImages();
},
mounted() {
this.setGalleryImages();
},
watch: {
product(newVal, oldVal) {
if(newVal.LargeImage1 != oldVal.LargeImage1) {
this.setGalleryImages();
this.$nextTick(function() {
if(this.mainSwiperOptions.loop) this.mainSwiper.slideToLoop(0, 0);
this.thumbsSwiper.slideTo(0);
});
}
},
},
methods: {
setGalleryImages()
{
var needsReinit = false;
if(this.shouldLoop !== this.mainSwiperOptions.loop) {
this.mainSwiperOptions.loop = this.shouldLoop;
this.destroyMainSwiper();
needsReinit = true;
}
this.galleryProduct.LargeImage[1] = this.product.LargeImage1;
this.galleryProduct.ExtraLargeImage[1] = this.product.ExtraLargeImage1;
this.galleryProduct.LargeImage[2] = this.product.LargeImage2;
this.galleryProduct.ExtraLargeImage[2] = this.product.ExtraLargeImage2;
this.galleryProduct.LargeImage[3] = this.product.LargeImage3;
this.galleryProduct.ExtraLargeImage[3] = this.product.ExtraLargeImage3;
if(needsReinit) {
this.initMainSwiper();
}
return;
},
destroyMainSwiper() {
this.mainSwiper.destroy();
// this.mainSwiper.destroy(false, false);
},
initMainSwiper() {
//let swiper = this.mainSwiper.init();
var swiper = new Swiper('#pdpMainSwiper', this.mainSwiperOptions);
// this.$refs.mainSwiper.$swiper = swiper;
}
}
};
</script>
Help appreciated!

Vue-Tables-2 Side Server Get Error " Cannot read property 'data' of undefined" Why?

I am using vue-tables-2 for manage data. I wanna implement server side. But I got a problem. I can get the data as well. But I dont know why I got that error message. This is my code:
HTML
<v-server-table :columns="columns" :options="options"></v-server-table>
Vue Js
<script>
var config = {
"PMI-API-KEY": "erpepsimprpimaiy"
};
export default {
name: "user-profile",
data() {
return {
columns: ["golongan_name"],
options: {
requestFunction: function(data) {
return this.$http({
url: "api/v1/golongan_darah/get_all_data",
method: "post",
headers: config
}).then(res => {
this.data = res.data.data;
console.log(res);
});
},
filterable: ["golongan_name"],
sortable: ["golongan_name"],
filterByColumn: true,
perPage: 3,
pagination: { chunk: 10, dropdown: false },
responseAdapter: function(resp) {
return {
data: resp.data,
count: resp.total
};
}
}
};
}
};
</script>
This is the error:
enter image description here

How to Implement Delete Data in Vue-Tables-2?

I am confused how to implement delete in vue-tables-2. I used this library https://www.npmjs.com/package/vue-tables-2
This is my code
HTML
<v-client-table :columns="columns" v-model="data" :options="options">
<div slot="action">
<button #click="erase" class="btn btn-danger">Delete</button>
</div>
<div slot="nomor" slot-scope>
<span v-for="t in nomer" :key="t">{{t}}</span>
</div>
<div slot="category_name" slot-scope="{row}">{{row.category_name}}</div>
</v-client-table>
Vue Js
<script>
var config = {
"PMI-API-KEY": "erpepsimprpimaiy"
};
export default {
name: "user-profile",
data() {
return {
nomer: [],
columns: ["nomor", "category_name", "action"],
data: [],
options: {
headings: {
nomor: "No",
category_name: "Category Name",
action: "Action"
},
filterByColumn: true,
sortable: ["category_name"],
filterable: ["category_name"],
templates: {
erase: function(h, row, index) {
return <delete id={row.data.category_id}></delete>;
}
}
}
};
},
methods: {
load() {
this.$http({
url: "api/v1/news_category/get_all_data",
method: "post",
headers: config
}).then(res => {
this.data = res.data.data;
});
},
del() {
this.$http({
url: "api/v1/news_category/delete",
method: "post",
headers: config
}).then(res => {
console.log("success");
});
}
},
mounted() {
this.load();
}
};
</script>
When I run the code, I got error "erase not defined". I wanna implement like the documentation which you can see at https://www.npmjs.com/package/vue-tables-2#vue-components
Your template is missing the erase function which means you have to define erase as your components method, just like that:
methods: {
erase(h, row, index) {
return <delete id={row.data.category_id}></delete>;
}
}

How should data be structured for lineplots with vue/chart.js

I am retrieving data from an api (working) and generating a line plot with vue-chartjs.
However only the first two points are plotted. I must have my data structured in the wrong way but I don't know what it is expecting.
Here is my component:
import { Line } from "vue-chartjs";
export default {
extends: Line,
props: {
chartdata: {
type: Object,
default: null
}
},
mounted() {
this.renderChart(this.chartdata);
}
};
And in my App.vue file, I have this simple template:
<template>
<div id="app">
<div class="container">
<div class="Chart">
<h2>LineChart</h2>
<line-chart v-if="loaded" :chartdata="chartdata"></line-chart>
</div>
</div>
</div>
</template>
and this script:
<script>
import LineChart from './components/LineChart.js'
export default {
name: 'app',
components: { LineChart },
data:() => ({
loaded: false,
chartdata: null
}),
async mounted () {
this.loaded = false;
try {
let mydata = await fetch("http://myserver00/api/load/myserver02")
.then(stream => stream.json())
.then(mydata => {
let usercpu = [];
mydata.forEach(record => {
usercpu.push( record.cpu.user );
});
this.usercpu = usercpu;
});
} catch (e) {
console.error(e)
}
this.loaded = true;
this.chartdata = {
datasets: [
{label: 'CPU', data: this.usercpu}
]
};
}
}
</script>
As you may notice, I'm trying to system data from psutils to monitor servers. The original record from the api has several fields. This example just shows my attempt at CPU usage.
The browser tools show the data I expect, but apparently not what the chart expects. Here's a view of the data from the chrome vue devtools extension
Edit: to make sure the data is actually loaded, I added {{chartdata}} into my template and I see it all. Here is how it starts, the array goes on with all the data array. And the actual plot again shows only the first two data points.
{ "datasets": [ { "label": "CPU", "data": [ 2.7, 2.9, 3
Finally got it; I needed to re-read the doc for Chartjs. So here's the mounted function now. See that I had to put in x and y values for each point.
async mounted () {
this.loaded = false;
try {
let usercpu = [];
await fetch("http://server/api/load/server02")
.then(stream => stream.json())
.then(mydata => { mydata.forEach(record => {
usercpu.push( { y: record.cpu.user, x: record.date });});});
this.loaded = true;
this.chartdata = {
datasets: [ {
fill: false,
pointRadius: 0,
borderWidth: 2,
label: 'CPU',
data: usercpu
} ] };
} catch (e) {
console.error(e)
}
}
Also, in the data portion of the default function I had to add axes. I'm not exactly sure why, but even when the data was okay (above) I still couldn't see the plot. So when I added the axes, there everything was:
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: "hour",
displayFormats: {
hour: "M/DD # hA"
},
tooltipFormat: "MMM. DD # hA"
},
scaleLabel: {
display: true,
labelString: "Date/Time"
},
ticks: { autoSkip: true, maxTicksLimit: 5},
position: 'bottom'
}],
yAxes: [{
ticks: {
suggestedMin: 0,
suggestedMax: 10
}
}]
}
And of course I had to include the options in the directive:
<template>
<div id="app">
<div class="container">
<div id="cpu">
<h2>Server02</h2>
<line-chart v-if="loaded" :chartdata="chartdata" :options="options"></line-chart>
</div>
</div>
</div>
</template>