apply jquery plugin on vue json data - vuejs2

I'm using a vue component to fetch and show data as below:
export default {
data() {
return {
posts: [],
post: {
id: '',
title: '',
rating: '',
ver: ''
},
pagination: {},
}
},
created() {
this.fetchRecentPosts();
},
methods: {
fetchRecentPosts() {
fetch('api/recentposts')
.then(res => res.json())
.then(res => {
this.posts = res.data;
})
}
},
}
I'm also using rateYo plugin to show posts rating.
without using vue.js i'm able to turn my div attribute into star rating by :
$(".rateYo").each(function () {
var rating = $(this).data("rating");
$(this).rateYo({
rating: rating,
starWidth: "13px",
spacing: "3px",
ratedFill: "#ffb300",
normalFill: "#d3d8e4",
readOnly: true
});
});
So, How should I apply it work on evey div inside a v-for loop using vue.js ?
Thanks

var app = new Vue({
el: '#app',
data() {
return {
posts: [
{
id: 1,
title: 'Post One',
rating: 2.5
},
{
id: 2,
title: 'Post Two',
rating: 4.1
}
],
post: {
id: '',
title: '',
rating: '',
ver: ''
},
pagination: {},
}
},
mounted() {
$('.rateYo').each(function() {
$(this).rateYo({
rating: $(this).data('rating'),
starWidth: "13px",
spacing: "3px",
ratedFill: "#ffb300",
normalFill: "#d3d8e4",
readOnly: true
});
});
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rateYo/2.3.2/jquery.rateyo.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/rateYo/2.3.2/jquery.rateyo.min.css">
<div id="app">
<div v-for="(post,index) in posts" :key="index">
<h3>{{ post.title }}</h3>
<div class="rateYo" :data-rating="post.rating"></div>
</div>
</div>

Related

Filter data coming from API with Nuxt

Im using slick slider in Nuxt im getting the images from an API with Axios
The API look like this :
"images_selection": [
{
title: 'Global Landing',
slug: 'global-landing-1',
id: 113,
images: [
{
title: '',
description: '',
file_extension: 'jpeg',
position: 0,
url: 'https://####images',
type: 0,
link: '',
id: 3603,
video_link: '',
},
],
},
{
title: 'Home Slider 1',
slug: 'home-slider-1',
id: 331,
images: [
{
title: '',
description: '',
file_extension: 'jpeg',
position: 0,
url: 'https://###images',
type: 0,
link: '',
id: 5773,
},
],
},
]
My Axios :
async mounted() {
const response = await axios.get('/api/')
this.resultsimages = response.data.images_selection.filter(r => r.slug = home-slider-1)
},
Im trying to get the image only in "Home Slider 1" with a filter .filter(r => r.slug = home-slider-1);
But im doing something wrong what will be the best way to target only the home slider 1 ?
EDIT: here is my page where I am not able to loop on the fetched images.
<template>
<div>
<div class="home-slider">
<VueSlickCarousel
:arrows="false"
:dots="true"
:slidesToShow="3"
:rows="1"
:slidesPerRow="3"
:autoplay="true"
:fade="true"
>
<div class="slide1">
<div v-for="result in resultsimages" :key="result.id">
<div class="img1">
<img
v-for="images in result.images"
:key="images.id"
:src="images.url"
/>
</div>
</div>
</div>
</VueSlickCarousel>
</div>
</div>
</template>
<script>
export default {
data() {
return {
resultsimages: [],
data: [],
};
async mounted() {
const { data } = await axios.get("/api/", {
headers: {
"X-AUTH-TOKEN": "####",
"Content-Type": "application/json",
},
});
this.resultsimages = data.images_selection.filter((image) => (image) =>
image.slug === "home-slider-1"
);
},
};
</script>
I heavily formatted your question, especially for the axios part by using only async/await and not a mix of both async/await + .then.
This is how the block should look like
async mounted() {
const { data } = await axios.get('/api/')
this.resultsimages = data.images_selection.filter((image) => (image) => image.slug === 'home-slider-1')
},
Please format your code with more effort next time.

Using a method as data inside the app parent

So I'm still learning Vue.js and I got my list working well and I have one question. I will explain what I'm trying to do below as best as possible and I wanted to see if someone could help me with my issue.
So here is the component that I have on the HTML side:
<favorites-edit-component
v-for="(favorite, index) in favorites"
v-bind:index="index"
v-bind:name="favorite.name"
v-bind:key="favorite.id"
v-on:remove="favorites.splice(index, 1)"
></favorites-edit-component>
Here is the vue.js portion that I have:
Vue.component('favorites-edit-component', {
template: `
<div class="column is-half">
<button class="button is-fullwidth is-danger is-outlined mb-0">
<span>{{ name }}</span>
<span class="icon is-small favorite-delete" v-on:click="$emit('remove')">
<i class="fas fa-times"></i>
</span>
</button>
</div>
`,
props: ['name'],
});
new Vue({
el: '#favorites-modal-edit',
data: {
new_favorite_input: '',
favorites: [
{
id: 1,
name: 'Horse',
url: 'www.example.com',
},
{
id: 2,
name: 'Sheep',
url: 'www.example2.com',
},
{
id: 3,
name: 'Octopus',
url: 'www.example2.com',
},
{
id: 4,
name: 'Deer',
url: 'www.example2.com',
},
{
id: 5,
name: 'Hamster',
url: 'www.example2.com',
},
],
next_favorite_id: 6,
},
methods: {
add_new_favorite: function() {
this.favorites.push({
id: this.next_favorite_id++,
name: this.new_favorite_input
})
this.new_favorite_input = ''
},
get_favorite_menu_items: function() {
wp.api.loadPromise.done(function () {
const menus = wp.api.collections.Posts.extend({
url: wpApiSettings.root + 'menus/v1/locations/favorites_launcher',
})
const Menus = new menus();
Menus.fetch().then(posts => {
console.log(posts.items);
return posts.items;
});
})
}
}
});
So as you can see, I have the data: { favorites: [{}] } called inside the vue app and I get this console.log:
Now I built a method called get_favorite_menu_item and this is the return posts.items output inside console.log:
Problem: I don't want to have a manual array of items, I want to be able to pull in the method output and structure that - How would I take a approach on pulling the items?
Could I call something like this:
favorites: this.get_favorite_menu_items?
Here is a JFiddle with all the items: https://jsfiddle.net/5opygkxw/
All help will be appreciated on how to pull in the data.
First I will init favorites to empty array.
then on get_favorite_menu_items() after I will init data from post.item to favorites.
on created() hooks i will call get_favorite_menu_items() to fetch the data when the view is created.
new Vue({
el: '#favorites-modal-edit',
data: {
new_favorite_input: '',
favorites: [],
next_favorite_id: 6,
},
methods: {
add_new_favorite: function() {
this.favorites.push({
id: this.next_favorite_id++,
name: this.new_favorite_input
})
this.new_favorite_input = ''
},
get_favorite_menu_items: function() {
wp.api.loadPromise.done(function () {
const menus = wp.api.collections.Posts.extend({
url: wpApiSettings.root + 'menus/v1/locations/favorites_launcher',
})
const Menus = new menus();
Menus.fetch().then(posts => {
console.log(posts.items);
// need map key also
this.favorites = posts.items;
});
})
}
},
created () {
// fetch the data when the view is created
this.get_favorite_menu_items();
},
});

How to use google data-table chart in vuejs project?

In my vuejs project how to use google data-table chart? Google data-table chart link given below:
https://developers.google.com/chart/interactive/docs/gallery/table
I can implement this chart in normal javascript code. But how to use in vuejs code.
You can use your own component. Here I have made one simple example.
Vue.component('google-data-table', {
template: `<div id='app' ref="table_div"></div>`,
props: {
columns: {
type: Array,
required: true
},
tableData: {
type: Array,
required: true
}
},
mounted() {
google.charts.load('current', {
'packages': ['table']
});
google.charts.setOnLoadCallback(this.drawTable);
},
methods: {
drawTable: function() {
var data = new google.visualization.DataTable();
this.columns.forEach(element => {
data.addColumn(element.type, element.title);
});
data.addRows(this.tableData);
var table = new google.visualization.Table(this.$refs.table_div);
table.draw(data, {
showRowNumber: true,
width: '100%',
height: '100%'
});
}
}
});
new Vue({
el: '#app',
data: {
columns: [{
type: 'string',
title: 'Name'
},
{
type: 'number',
title: 'Salary'
},
{
type: 'boolean',
title: 'Full Time Employee'
}
],
tableData: [
['Mike', {
v: 10000,
f: '$10,000'
}, true],
['Jim', {
v: 8000,
f: '$8,000'
}, false],
['Alice', {
v: 12500,
f: '$12,500'
}, true],
['Bob', {
v: 7000,
f: '$7,000'
}, true]
]
}
});
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="app">
<google-data-table :columns='columns' :table-data='tableData' />
</div>
</body>
</html>

Getting bootstrap vue pagination to play with REST api

Trying to get Bootstrap Vue to play with a REST api that returns data for one page and the total number of records (based on this):
<template>
</div>
<b-pagination
v-on:change="onPageChange"
:total-rows="totalRows"
:per-page="perPage"
v-model="currentPage" />
<b-table responsive striped hover show-empty
stacked="md"
:items="items"
:fields="fields"
:current-page="currentPage"
:per-page="perPage"
:filter="filter"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
:sort-direction="sortDirection"
#filtered="onFiltered">
</b-table>
</div>
</template>
<script>
...
export default {
name: 'TableList',
data() {
return {
module: null,
title: 'Table',
items: [],
fields: [],
errors: [],
currentPage: 1,
perPage: 15,
totalRows: 0,
pageOptions: [ 5, 10, 15 ],
sortBy: null,
sortDesc: false,
sortDirection: 'asc',
filter: null,
}
},
created() {
...
this.fetch();
},
methods: {
fetch() {
var me = this;
var requestParams = {
page: this.currentPage,
per_page: this.perPage
};
if(this.sortBy) {
requestParams = Object.assign({ sort_by: this.sortBy }, requestParams);
}
Rest('GET', '/table/' + this.table, requestParams, this.$root.user.token)
.then(response => {
me.items = response.data[1]
me.totalRows = response.data[0].total_entries
})
.catch(error => {
this.errors.push('Error: ' + error.response.status + ': ' + error.response.statusText)
})
.finally(() => {
//alert('turn off loader!');
});
}
}
</script>
This Vue works if I fetch the entire table. However, when I use the REST api to return one page at a time, the number of pages is calculated to be 1, and the forward and end links are inactive. Thus, I am unable to trigger a request for e.g. page 2.
The REST api correctly returns the total number of rows in the table, and the number of rows requested, but Bootstrap Vue does not appear to be watching/reacting to changes to this.totalRows.
What have I missed?
You need to set the per-page prop to 0 on the b-table component to disable the local pagination and allow b-pagination to handle the data. Here's an example:
new Vue({
el: '#app',
data() {
return {
items: [],
fields: [{
key: 'postId',
label: 'Post ID'
},
{
key: 'id',
label: 'ID'
},
{
key: 'name',
label: 'Name'
},
{
key: 'email',
label: 'Email'
},
{
key: 'body',
label: 'Body'
}
],
currentPage: 0,
perPage: 10,
totalItems: 0
}
},
mounted() {
this.fetchData().catch(error => {
console.error(error)
})
},
methods: {
async fetchData() {
this.items = await fetch(`https://jsonplaceholder.typicode.com/comments?_page=${this.currentPage}&_limit=${this.perPage}`)
.then(res => {
this.totalItems = parseInt(res.headers.get('x-total-count'), 10)
return res.json()
})
.then(items => items)
}
},
watch: {
currentPage: {
handler: function(value) {
this.fetchData().catch(error => {
console.error(error)
})
}
}
}
})
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.js"></script>
<script src="//unpkg.com/babel-polyfill#latest/dist/polyfill.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.js"></script>
<div id="app">
<b-table show-empty :items="items" :fields="fields" :current-page="currentPage" :per-page="0"></b-table>
<b-pagination size="md" :total-rows="totalItems" v-model="currentPage" :per-page="perPage"></b-pagination>
</div>
You can also disabled local pagination in the table, so that your items provider becomes responsible for controlling the pagination.

VueJs: Form handling with Vuex and inputs generated with an API

Here's an example of a component:
<script>
export default {
name: 'my-form',
computed: {
myModules() {
return this.$store.state.myModules;
}
}
</script>
<template>
<form>
<p v-for="module in myModules">
<input type="checkbox" :value="module.id" />
<label>module.name</label>
</p>
<button type="submit">Submit</button>
</form>
</template>
The associated store:
state: {
myModules: []
},
mutations: {
setModules(state, modules) {
state.myModules = modules;
}
},
actions: {
getModules({commit}) {
return axios.get('modules')
.then((response) => {
commit('setModules', response.data.modules);
});
}
}
And finally, an example of return of the API "getModules":
modules : [
{
id: 1,
name: 'Module 1',
isActive: false
},
{
id: 2,
name: 'Module 2',
isActive: false
},
{
id: 3,
name: 'Module 3',
isActive: false
}
]
My question: what's the best way to change the "isActive" property of each module to "true" when I check the checkbox corresponding to the associated module, directly in the store?
I know that Vuex's documentation recommends to use "Two-way Computed Property" to manage the forms, but here I don't know the number of modules that the API can potentially return, and I don't know their name.
Thank you in advance!
This is a little bit wicked approach, but it works. You can create an accessor object for every item you access in a loop:
const store = new Vuex.Store({
mutations: {
setActive (state, {index, value}) {
state.modules[index].isActive = value
}
},
state: {
modules : [
{
id: 1,
name: 'Module 1',
isActive: false
},
{
id: 2,
name: 'Module 2',
isActive: false
},
{
id: 3,
name: 'Module 3',
isActive: false
}
]
}
});
const app = new Vue({
el: '#target',
store,
methods: {
model (id) {
const store = this.$store;
// here i return an object with value property that is bound to
// specific module and - thanks to Vue - retains reactivity
return Object.defineProperty({}, 'value', {
get () {
return store.state.modules[id].isActive
},
set (value) {
store.commit('setActive', {index: id, value});
}
});
}
}
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.min.js"></script>
<div id="target">
<div v-for="(item, id) in $store.state.modules">
Module #{{ item.id }} state: {{ item.isActive }}
</div>
<div v-for="(item, id) in $store.state.modules">
<label>
Module #{{ item.id }}
<input type="checkbox" v-model="model(id).value"/>
</label>
</div>
</div>
This is still quite a messy approach, but at least you don't have to commit mutations directly in template. With a little help of Vue.set() you can use this approach even to overcome standard reactivity caveats.
I have an alternative solution for you. You could make a child component for the checkboxes to clean up the code a bit.
UPD: I just realised that everything that I and #etki proposed is an overkill. I left the old version of my code below in case you still want to take a look. Here is a new one:
const modules = [{
id: 1,
name: 'Module 1',
isActive: true,
},
{
id: 2,
name: 'Module 2',
isActive: false,
},
{
id: 3,
name: 'Module 3',
isActive: false,
},
];
const store = new Vuex.Store({
state: {
myModules: [],
},
mutations: {
SET_MODULES(state, modules) {
state.myModules = modules;
},
TOGGLE_MODULE(state, id) {
state.myModules.some((el) => {
if (el.id === id) {
el.isActive = !el.isActive;
return true;
}
})
}
},
actions: {
getModules({
commit
}) {
return new Promise((fulfill) => {
setTimeout(() => {
commit('SET_MODULES', modules);
fulfill(modules);
}, 500)
});
}
}
});
const app = new Vue({
el: "#app",
store,
data: {},
methods: {
toggle(id) {
console.log(id);
this.$store.commit('TOGGLE_MODULE', id);
}
},
computed: {
myModules() {
return this.$store.state.myModules;
},
output() {
return JSON.stringify(this.myModules, null, 2);
},
},
mounted() {
this.$store.dispatch('getModules').then(() => console.log(this.myModules));
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<script src="https://unpkg.com/vue"></script>
<div id="app">
<form>
<div v-for="data in myModules">
<label :for="data.id">{{ data.name }}: {{data.isActive}}</label>
<input type="checkbox" :id="data.id" :name="'checkbox-' + data.id" :checked="data.isActive" #change="toggle(data.id)">
</div>
</form>
<h3>Vuex state:</h3>
<pre v-text="output"></pre>
</div>
As you can see above you could just call a function on input change and pass an id as a parameter to a method that fires vuex action.
The old version of my code.
A new one on jsfiddle