how can we make v-if loading work with an Async typo from Es6 with Vue?
here is the template, and I will put the solution also below, hope it helps.
this helped me so I know everyone learns differently so here is the way I understood things, less theoretical more practical, have a nice day!
<template>
<div class="container-fluid">
<v-col
md="6"
offset-md="3"
v-if="loading"
justify="center">
<v-progress-circular
:size="50"
color="blue"
indeterminate
>
</v-progress-circular>
</v-col>
<div v-else class="row">
<main role="main" class="col-md-12 ml-sm-auto col-lg-12 pt-3 px-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 ">
<h2>Learning loading with async</h2>
</div>
</main>
</div>
</div>
</template>
<script>
import Row from '#/components/Row.vue';
const { GoogleSpreadsheet } = require('google-spreadsheet');
const creds = require('#/client_secret.json');
export default {
name: "Sheet",
components: {
Row
},
props: ["sheet"],
data() {
return {
rows: [], // your data things
}
},
methods:{
async accessSpreadSheet() {
const doc = new GoogleSpreadsheet('blahblahblah');
await doc.useServiceAccountAuth(creds);
await doc.loadInfo();
const sheet = doc.sheetsByIndex[0];
const rows = await sheet.getRows({
offset: 1
})
this.rows = rows;
}
},
created() {
this.accessSpreadSheet();
}
}
Example using v-if loading for skeleton loader or whatever, with async data method... I guess in vue
not perfect but i hope it helps out, I will just add the important parts:
<template>
<div class="container-fluid">
<v-col
md="6"
offset-md="3"
v-if="loading"
justify="center">
<v-progress-circular
:size="50"
color="blue"
indeterminate
>
</v-progress-circular>
</v-col>
<div v-else class="row">
<main role="main" class="col-md-12 ml-sm-auto col-lg-12 pt-3 px-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 ">
<h2>Learning loading with async</h2>
</div>
</main>
</div>
</div>
</template>
<script>
import Row from '#/components/Row.vue';
const { GoogleSpreadsheet } = require('google-spreadsheet');
const creds = require('#/client_secret.json');
export default {
name: "Sheet",
components: {
Row
},
props: ["sheet"],
data() {
return {
rows: [], // your data things
loading: true, //this is what matters
}
},
methods:{
async accessSpreadSheet() {
const doc = new GoogleSpreadsheet('blahblahblah');
await doc.useServiceAccountAuth(creds);
await doc.loadInfo();
const sheet = doc.sheetsByIndex[0];
const rows = await sheet.getRows({
offset: 1
})
this.rows = rows;
this.loading = false; //this is what works
}
},
created() {
this.accessSpreadSheet();
}
}
Related
I have pretty simple table of users here with only 4 cols, and i want to show a button for each user depending on his status 'isActive'. If user is active i want to show button with text 'disable' and vice versa. I am little bit stuck with this because i dont have an idea how can i show these buttons, because i am using vuexy template for this project(admin panel). Is there a way to do this with JSX?
Please take a look at code, i am getting data from mysql with nodejs. Ask me if you need more info. Thanks.
<template>
<div>
<div class="container">
<b-card-text class="mb-2">
<div
v-if="showLoginError"
class="text-center bg-danger colors-container rounded text-white width-360 height-50 d-flex align-items-center justify-content-center mr-1 ml-50 my-1 shadow"
>
<span>{{ loginError }}</span>
</div>
</b-card-text>
<b-card-text class="mb-2">
<div
v-if="showSuccessMessage"
class="text-center bg-success colors-container rounded text-white width-360 height-50 d-flex align-items-center justify-content-center mr-1 ml-50 my-1 shadow"
>
<span>{{ successMessage }}</span>
</div>
</b-card-text>
<section id="card-actions" class="input-section">
<b-row>
<b-col cols="8">
<b-card-actions ref="cardAction">
<validation-observer ref="simpleRules">
<b-form>
<b-row>
<b-col md="6">
<b-form-group>
<validation-provider
#default="{ errors }"
name="First Name"
rules="required"
>
<b-form-input
v-model="name"
:state="errors.length > 0 ? false:null"
placeholder="Twitter username"
/>
</validation-provider>
</b-form-group>
</b-col>
<b-col cols="12">
<b-button
variant="primary"
type="submit"
#click.prevent="validationForm"
>
Submit
</b-button>
</b-col>
</b-row>
</b-form>
</validation-observer>
</b-card-actions>
</b-col>
</b-row>
</section>
// This is table
<b-table responsive="sm" :items="items"/>
</div>
</div>
</template>
<script>
import { ValidationProvider, ValidationObserver } from 'vee-validate'
import {
BFormInput, BFormGroup, BForm, BRow, BCol, BButton, BTable,
} from 'bootstrap-vue'
import { required } from '#validations'
import axios from 'axios'
import { getUserToken } from '#/auth/auth'
export default {
components: {
ValidationProvider,
ValidationObserver,
BFormInput,
BFormGroup,
BForm,
BRow,
BCol,
BButton,
BTable,
},
data() {
return {
name: '',
successMessage: '',
showSuccessMessage: false,
loginError: '',
showLoginError: false,
required,
items: [],
}
},
beforeMount() {
this.getAllUsers()
},
methods: {
getAllUsers() {
const API_URL = `${this.$server}/api/twitter/allusers`
const params = {
token: getUserToken(),
}
axios.post(API_URL, null, { params }).then(res => {
if (res.data) {
res.data.forEach(element => {
let isActive = 'active'
if (element.isActive === 0) {
isActive = 'disabled'
}
const arr = {
twitter_name: element.twitter_name,
twitter_username: element.twitter_username,
twitter_id: element.twitter_id,
userActive: isActive,
}
this.items.push(arr)
})
}
})
},
validationForm() {
const API_URL = `${this.$server}/api/twitter/adduser`
const params = {
twitter_username: this.name,
token: getUserToken(),
}
axios.post(API_URL, null, { params }).then(res => {
if (res.data.success) {
this.successMessage = res.data.message
this.showSuccessMessage = true
// Hide message after 5sec
setTimeout(() => {
this.successMessage = ''
this.showSuccessMessage = false
}, 5000)
} else {
this.loginError = res.data.message
this.showLoginError = true
// Hide message after 5sec
setTimeout(() => {
this.loginError = ''
this.showLoginError = false
}, 5000)
}
})
},
},
}
</script>
I'm a little bit confused, where do you want to show your button ?
If it's in the table, you can use the custom templation of Bootstrap-Vue, you'll find the doc here with an example : https://bootstrap-vue.org/docs/components/table#custom-data-rendering
EDIT: here an example for your case
<b-table responsive="sm" :items="items">
<template #cell(userActive)="data">
<b-button v-if="data.userActive">Disabled</b-button>
<b-button v-else>Enabled</b-button>
</template>
</b-table>
everyone, I am new to vuejs and vuetify and trying to make a book app but the problem is all the code is complete but when I click on the dropdown item it shows all the books item but I want to show only selected book item.
This is my HTML where I am stuck I am doing mistakes here this and I am failed many times cannot get my answer
<v-container fluid>
<v-row aign="center">
<v-col cols="12">
<v-toolbar-title>State Selection</v-toolbar-title>
<div v-on-clickaway="away" class="searchField dropdown">
<v-text-field
:label="labeling"
v-model="search"
#input="waitForSearch"
>
</v-text-field>
<!-- <div class="bookParent" v-for="item in items" :key="item.id"> -->
<!-- <img :src="item.volumeInfo.imageLinks.thumbnail" /> -->
<div
class="clickUpdateElement"
v-for="(item, index) in items"
:key="item.id"
>
<HelloWorld v-show="show">
<template v-slot:contentHandler class="option" id="option1">
<div
#click="clickCard(item, $event.target)"
class="containerForI"
>
<v-img>
<img :src="item.volumeInfo.imageLinks.thumbnail" />
</v-img>
<a class="anchorTag">{{ item.volumeInfo.title }}</a>
<!-- <span>{{ item.volumeInfo.author }}</span> -->
</div>
</template>
</HelloWorld>
<div class="content">
<Content v-show="show2" #load="updateCard(item, $event.target)">
<template v-slot:cardContent>
<v-card class="mx-auto" elevation="2" outlined shaped>
<v-list-item three-line>
<v-list-item-avatar>
<!-- <v-img :src="imageSrc"></v-img> -->
</v-list-item-avatar>
<v-list-item-content>
<v-card-title>
{{ item.volumeInfo.title }}
</v-card-title>
<v-card-subtitle>
{{ index }} {{ item.volumeInfo.description }}
</v-card-subtitle>
</v-list-item-content>
<v-card-actions>
<v-btn primary>Act</v-btn>
</v-card-actions>
</v-list-item>
</v-card>
</template>
</Content>
</div>
</div>
<v-btn #click="show2 = false">Remove</v-btn>
</div>
</v-col>
</v-row>
</v-container>
MY JS
import axios from "axios";
import { directive as onClickaway } from "vue-clickaway";
import HelloWorld from "../components/HelloWorld";
import Content from "../components/Content";
export default {
name: "Home",
directives: {
onClickaway: onClickaway,
},
data() {
return {
BASE_URL: "https://www.googleapis.com/books/v1/volumes",
items: [],
search: "",
timerId: "",
labeling: "Search For Book",
show: false,
show2: false,
imageSrc: "",
showTitle: "",
showDescription: "",
};
},
components: {
HelloWorld,
Content,
},
created() {},
computed: {},
//Fetch the required Information from Google Book Api
watch: {},
methods: {
async getBooks() {
this.show = true;
let response = await axios.get(`${this.BASE_URL}`, {
params: {
q: this.search,
apikey: "",
},
});
this.items = response.data.items;
console.log(this.items);
},
away() {
console.log("clicked away");
this.show = false;
},
clickCard(item, target) {
console.log(item);
console.log(target);
this.show = false;
this.show2 = true;
},
updateCard(item, target) {
console.log(item);
console.log(target);
},
//Method That Take and wait for the Input
waitForSearch() {
// this.search = "";
clearTimeout(this.timerId);
this.timerId = setTimeout(() => {
this.getBooks();
}, 1000);
},
},
Content.vue i just used slot nothing else
<div class="container">
<div class="row">
<slot name="cardContent"></slot>
</div>
</div>
HelloWorld.vue
html
<div class="menu pointerCursor hide">
<slot name="contentHandler"></slot>
</div>
I try many times but failed. Any leads, please?
What I would try is to keep a record of the index that I want to show.
So what you could do is the following:
1.Change the code calling ClickCard
<div #click="clickCard(item, index)" class="containerForI">
2.Assign the value of index to a component variable
clickCard(item, index) {
console.log(item);
this.indexToShow = index;
this.show = false;
this.show2 = true;
},
3.Initialize the aforementioned variable in your component
data() {
return {
BASE_URL: "https://www.googleapis.com/books/v1/volumes",
indexToShow: null,
...
4.Finally, check if the currently selected index is the one to show
<Content v-show="indexToShow === null || indexToShow === index"
If you want to show all items, after showing only 1, you will have to set indexToShow to null. The Content component is checking for it.
I am trying to make a modal component and dismiss it when I click outside of the component. Here is my current setup:
Auth component with click event set on a div element:
<template> <div>
<transition name="modal">
<div class="modal-mask" #click="$parent.$emit('close')">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">Default Header</slot>
</div>
<div class="model-body">
<slot name="body">Default Body</slot>
</div>
<div class="modal-footer">
<slot name="footer">Default Footer</slot>
</div>
</div>
</div>
</div>
</transition> </div> </template>
SignIn component that injects necessary information:
<template>
<div>
<Auth />
</div>
</template>
Home component that uses the SignIn component:
<template>
<div class="home">
<SignIn v-if="showModal" #close="showModal = false" />
</div>
</template>
Right now when I click outside the modal it behaves ok, the close event is called.
But it is also called when I click inside the modal.
Not I tried to use #click.self , but now it doesn't work anymore even when clicking outside the modal.
<div class="modal-mask" #click.self="$parent.$emit('close')">
I am currently learning VueJs, but I don't understand how this works. I thought self will prevent propagating click event to child elements and thats it.
Anyone has an idea what is going on ?
PS: I am using this setup, because I want to have a SignIn and SignUp using the Auth component.
Either <div class="modal-wrapper"> or <div class="modal-container"> needs #click.prevent.stop
<template>
<div>
<transition name="modal">
<div class="modal-mask" #click="$parent.$emit('close')">
<div class="modal-wrapper">
<div class="modal-container" #click.prevent.stop>
<div class="modal-header">
<slot name="header">Default Header</slot>
</div>
<div class="model-body">
<slot name="body">Default Body</slot>
</div>
<div class="modal-footer">
<slot name="footer">Default Footer</slot>
</div>
</div>
</div>
</div>
</transition>
</div>
</template>
With this code you don't have to worry about click event's propagation #click.stop, for the style purpose I am using bootstrap.css but you can write your own style.
Here is the reusable component BsModal.vue
<template lang="pug">
div(v-if="showModal")
.modal.fade.d-block(tabindex='-1', role='dialog', :class="{'show': addShowClassToModal}")
.modal-dialog(role='document')
.modal-content.border-0
.modal-header.border-0
h5.modal-title
slot(name="title")
button.close(type='button', data-dismiss='modal', aria-label='Close', #click="hideModal")
span ×
.modal-body.p-0
slot
.modal-backdrop.fade(:class="{ 'show': addShowClassToModalBackdrop }")
</template>
<script>
export default {
name: 'BsModal',
props: {
showModal: {
default: false,
type: Boolean,
},
},
data() {
return {
addShowClassToModal: false,
addShowClassToModalBackdrop: false,
};
},
mounted() {
this.toggleBodyClass('addClass', 'modal-open');
setTimeout(() => {
this.addShowClassToModalBackdrop = true;
}, 100);
setTimeout(() => {
this.addShowClassToModal = true;
}, 400);
},
destroyed() {
this.toggleBodyClass('removeClass', 'modal-open');
},
methods: {
hideModal() {
setTimeout(() => {
this.addShowClassToModal = false;
}, 100);
setTimeout(() => {
this.addShowClassToModalBackdrop = false;
this.$emit('hide-modal', false);
}, 400);
},
toggleBodyClass(addRemoveClass, className) {
const elBody = document.body;
if (addRemoveClass === 'addClass') {
elBody.classList.add(className);
} else {
elBody.classList.remove(className);
}
},
},
};
</script>
And use it wherever you need by importing it:
<template lang="pug">
div
button(#click="showModal = true")
| Show Modal
bs-modal(
v-if="showModal",
:show-modal="showModal",
#hide-modal="showModal = false"
).modal
template(slot="title") Modal Title
// Modal Body content here
</template>
<script>
import BsModal from '~/components/BsModal.vue';
export default {
name: 'your component',
components: { BsModal },
data() {
return {
showModal: false,
};
},
};
</script>
If you don't like pug template language then you can convert PUG to HTML here: https://pughtml.com/
I have a web page that displays items. For each items there is a button (vuejs component) which allow user to toggle (add/remove) this item to his collection.
Here is the component:
<template lang="html">
<button type="button" #click="toggle" name="button" class="btn" :class="{'btn-danger': dAdded, 'btn-primary': !dAdded}">{{ dText }}</button>
</template>
<script>
export default {
props: {
added: Boolean,
text: String,
id: Number,
},
data() {
return {
dAdded: this.added,
dText: this.text,
dId: this.id
}
},
watch: {
added: function(newVal, oldVal) { // watch it
this.dAdded = this.added
},
text: function(newVal, oldVal) { // watch it
this.dText = this.text
},
id: function(newVal, oldVal) { // watch it
this.dId = this.id
}
},
methods: {
toggle: function(event) {
axios.post(route('frontend.user.profile.pop.toggle', {
pop_id: this.dId
}))
.then(response => {
this.dText = response.data.message
let success = response.data.success
this.dText = response.data.new_text
if (success) {
this.dAdded = success.attached.length
let cardPop = document.getElementById('card-pop-'+this.dId);
if(cardPop)
cardPop.classList.toggle('owned')
}
})
.catch(e => {
console.log(e)
})
}
}
}
</script>
For each item, the user can also open a modal, loaded by a click on this link:
<a href="#" data-toggle="modal" data-target="#popModal" #click="id = {{$pop->id}}">
<figure>
<img class="card-img-top" src="{{ URL::asset($pop->img_path) }}" alt="Card image cap">
</figure>
</a>
The modal is also a Vuejs component:
<template>
<section id="pop" class="h-100">
<div class="card">
<div class="container-fluid">
<div class="row">
<div class="col-12 col-lg-1 flex-column others d-none d-xl-block">
<div class="row flex-column h-100">
<div v-for="other_pop in pop.other_pops" class="col">
<a :href="route('frontend.pop.collection.detail', {collection: pop.collection.slug, pop: other_pop.slug})">
<img :src="other_pop.img_path" :alt="'{{ other_pop.name }}'" class="img-fluid">
</a>
</div>
<div class="col active order-3">
<img :src="pop.img_path" :alt="pop.name" class="img-fluid">
</div>
</div>
</div>
<div class="col-12 col-lg-6 content text-center">
<div class="row">
<div class="col-12">
<img :src="pop.img_path" :alt="pop.name" class="img-fluid">
</div>
<div class="col-6 text-right">
<toggle-pop :id="pop.id" :added="pop.in_user_collection" :text="pop.in_user_collection ? 'Supprimer' : 'Ajouter'"></toggle-pop>
</div>
<div class="col-6 text-left">
<!-- <btnaddpopwhishlist :pop_id="propid" :added="pop.in_user_whishlist" :text="pop.in_user_whishlist ? 'Supprimer' : 'Ajouter'"></btnaddpopwhishlist> -->
</div>
</div>
</div>
<div class="col-12 col-lg-5 infos">
<div class="header">
<h1 class="h-100">{{ pop.name }}</h1>
</div>
<div class="card yellow">
<div class="card p-0">
<div class="container-fluid">
<div class="row">
<div class="col-3 py-2">
</div>
<div class="col-6 py-2 bg-lightgray">
<h4>Collection:</h4>
<h3>{{ pop.collection ? pop.collection.name : '' }}</h3>
</div>
<div class="col-3 py-2 bg-lightgray text-center">
<a :href="route('frontend.index') + 'collections/' + pop.collection.slug" class="btn-round right white"></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
export default {
props: {
id: Number
},
data() {
return {
pop: {
collection: {
}
}
}
},
ready: function() {
if (this.propid != -1)
this.fetchData()
},
watch: {
id: function(newVal, oldVal) { // watch it
// console.log('Prop changed: ', newVal, ' | was: ', oldVal)
this.fetchData()
}
},
computed: {
imgSrc: function() {
if (this.pop.img_path)
return 'storage/images/pops/' + this.pop.img_path
else
return ''
}
},
methods: {
fetchData() {
axios.get(route('frontend.api.v1.pops.show', this.id))
.then(response => {
// JSON responses are automatically parsed.
// console.log(response.data.data.collection)
this.pop = response.data.data
})
.catch(e => {
this.errors.push(e)
})
// console.log('fetchData')
}
}
}
</script>
Here is my app.js script :
window.Vue = require('vue');
Vue.component('pop-modal', require('./components/PopModal.vue'));
Vue.component('toggle-pop', require('./components/TogglePop.vue'));
const app = new Vue({
el: '#app',
props: {
id: Number
}
});
I would like to sync the states of the component named toggle-pop, how can I achieve this ? One is rendered by Blade template (laravel) and the other one by pop-modal component. But they are just the same, displayed at different places.
Thanks.
You could pass a state object as a property to the toggle-pop components. They could use this property to store/modify their state. In this way you can have multiple sets of components sharing state.
Your component could become:
<template lang="html">
<button type="button" #click="toggle" name="button" class="btn" :class="{'btn-danger': sstate.added, 'btn-primary': !sstate.added}">{{ sstate.text }}</button>
</template>
<script>
export default {
props: {
sstate: {
type: Object,
default: function() {
return { added: false, text: "", id: -1 };
}
}
},
data() {
return {};
},
methods: {
toggle: function(event) {
axios.post(route('frontend.user.profile.pop.toggle', {
pop_id: this.sstate.id
}))
.then(response => {
this.sstate.text = response.data.message
let success = response.data.success
this.sstate.text = response.data.new_text
if (success) {
this.sstate.ddded = success.attached.length
let cardPop = document.getElementById('card-pop-'+this.sstate.id);
if(cardPop)
cardPop.classList.toggle('owned')
}
})
.catch(e => {
console.log(e)
})
}
};
</script>
Live demo
https://codesandbox.io/s/vq8r33o1w7
If you are 100% sure that all toggle-pop components should always have the same state, you can choose to not define data as a function. Just declare it as an object.
data: {
dAdded: this.added,
dText: this.text,
dId: this.id
}
In https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function, it mentions
a component’s data option must be a function, so that each instance
can maintain an independent copy of the returned data object
If Vue didn’t have this rule, clicking on one button would affect the
data of all other instances
Since you want to sync the data of all toggle-pop component instances, you don't have to follow the data option must be a function rule.
i want to do filter and pagination in my view-candidates page..i want to display the candidates depending on the name and experience and expected ctc..i want to display the candidates..
Can anyone help me how to do that in vuejs...
Here is my view-candidates.blade.php
<div class="container">
<div class="row">
<el-row :gutter="12">
<el-col>
<p>View Candidates</p>
</el-col>
</el-row>
<el-row :gutter="12">
<template v-for="c in candidates">
<el-col :span="6">
<Candidate :c="c" :key="c.id"></Candidate>
</el-col>
</template>
</el-row>
</div>
here is my view-candidates.js page:
import Candidate from './components/Candidate.vue';
const app = new Vue({
el: '#app',
data() {
return {
candidates: window.data.candidates,
sortKey : 'first_name'
}
},
components: { Candidate },
});
here is my candidate.vue page:
<template>
<ElCard>
<div slot="header">
<strong>
{{c.first_name.toUpperCase() + ' ' + c.last_name.toUpperCase()}}
<br />
<small>{{c.role}} - {{c.experience}} Years</small>
</strong>
</div>
<p><strong>{{c.contact_no}} : {{c.email}}</strong></p>
<p>
<strong>Currently at:</strong> {{c.current_location}}
<br />
<strong>Ready to move:</strong> {{c.desired_location}}
</p>
<ElButton type="primary" size="small" #click="ResumeDialog = true">VIEW RESUME</ElButton>
<ElDialog class="text-left" :title="c.first_name.toUpperCase() + ' ' + c.last_name.toUpperCase()" v-model="ResumeDialog">
<p><strong>{{c.role}} - {{c.experience}} Years</strong></p>
<p>
<strong>Currently at:</strong> {{c.current_location}}
<br />
<strong>Ready to move:</strong> {{c.desired_location}}
</p>
<p>{{c.resume}}</p>
<br />
<p><strong>{{c.contact_no}} : {{c.email}}</strong></p>
</ElDialog>
</ElCard>
//script
import { Button as ElButton, Dialog as ElDialog, Card as ElCard } from 'element-ui';
import axios from 'axios';
export default {
props: ['c'],
data() {
return {
ResumeDialog: false,
}
},
components: { ElButton, ElDialog, ElCard },
}
Can anyone help me how to do that..
TIA..
In your view-candidates.js it should be like that:
import Candidate from './components/Candidate.vue';
const app = new Vue({
el: '#app',
data() {
return {
sortKey : 'first_name',
page: 0,
itemsPerPage: 4,
}
},
components: { Candidate },
methods: {
//custom method bound to page buttons
setPage(page) {
this.page = page-1;
this.paginedCandidates = this.paginate()
},
paginate() {
return this.filteredCandidates.slice(this.page*this.itemsPerPage, this.itemsPerPage * this.page + this.itemsPerPage)
},
},
computed: {
//compute number of pages, we always round up (ceil)
numPages() {
return Math.ceil(this.filteredCandidates.length/this.itemsPerPage);
},
filteredCandidates() {
//filter out all candidates that have experience less than 10
const filtered = window.data.candidates.filter((candidate) => {
//e.g.
if(candidate.experience < 10) {
return false;
}
return true;
})
return filtered;
},
paginedCandidates() {
return this.paginate()
}
}
});
And you render the buttons in the template:
<div class="container">
<div class="row">
<el-row :gutter="12">
<el-col>
<p>View Candidates</p>
</el-col>
</el-row>
<el-row :gutter="12">
<template v-for="c in paginedCandidates">
<el-col :span="6">
<Candidate :c="c" :key="c.id"></Candidate>
</el-col>
</template>
</el-row>
<el-row>
<!-- setPage is our method defined in methods object -->
<button v-for="n in numPages" #click="setPage(n)">#{{ n }}</button>
</el-row>
</div>
I believe this should do the magic. Probably you'll have to adjust it a little bit to your needs.