<template>
...
<div class="pagination">
<el-pagination
#current-change="handleCurrentChange"
layout="prev, pager, next"
:total="totalCount">
</el-pagination>
</div>
</template>
<script>
import Vue from 'vue';
Vue.use(ElementUI);
export default {
data() {
return {
tableData: [],
orderTableUrl: setting.orderTableUrl,
width: 110,
page_size: 10,
page_num: 1,
messages: [],
totalCount: 100,
}
},
created() {
this.getTableData()
},
methods: {
getTableData: function () {
let self = this;
axios.Get({
url: self.orderTableUrl,
params: {
'page_size': self.page_size,
'page_num': self.page_num
},
callback: function (res) {
self.tableData = res.data.orders;
self.totalCount = res.data.orders_total_pages;
console.log(self.totalCount)
}
});
},
}
}
the pagination part use element.ui .
Here is my problem: in method callback, console.log can echo real num of total page, but it cannot display on template, and only can see the num 1 of page on window.
I'm so puzzled for that.
Is it said that vue can immediately show data on change on view
finish the question. the ':total' does work, just surprised that it means the count of objects instead of pages ...
Related
export default {
props: {
pageNumber: {
type: Number,
required: true
}
},
data() {
return {
currentPage: 1,
perPage: 12,
},
computed: {
rows() {
return this.productsList.length;
},
paginatedItems() {
return this.productsList.slice(
this.currentPage * this.perPage,
(this.currentPage + 1) * this.perPage
);
},
methods: {
handleClick(event, pageNumber) {
alert('hi');
},
},
<div class="listview-plp" v-for="product in paginatedItems" :key="product.key" id="product" :items="productsList" :per-page="perPage" :current-page="currentPage">
<div>ds</div>
<b-pagination v-model="currentPage" :total-rows="rows" :per-page="perPage" #change="loadPage" :pageNumber="currentPage" #page-click="handleClick(event, pageNumber)"></b-pagination>
I want to emit an event when the user clicks on a specific page number? For that #page-click="handleClick(event, pageNumber)" i have taken an event in the method. But using page number is not pointing to specific page, So i have tool some prop value and then passing it to them,
But not sure how to pass value for each page.
You don't need to specify the parameters in the template,
#page-click="handleClick"
the method :
methods: {
handleClick(event ,pageNumber) {
alert('hi ', pageNumber);
},
},
I'm trying to clear up the form in the child component after the event containing the entered form data has been successfully passed from the child to parent component. However, I notice that the form gets cleared before the data gets propagated via the event to the parent component, such that the event passes empty values to the parent. I tried delaying the clearForm() using a timeout, but it didn't help. Is there a way to modify the behavior such that the clearForm() happens only after the event completes and the data has been saved?
Attached is the code.
Child Component
<template>
<!-- Contains a form -- >
</template>
<script>
export default {
data() {
return {
additionalInfo:
{
id: new Date().toISOString(),
fullName: '',
preAuthorize: '',
serviceAddress: ''
},
validation: {
fullNameIsValid: true,
serviceAddressIsValid: true
},
formIsValid: true,
addServiceButtonText: '+ Add Service Notes (Optional)',
serviceNotes: [],
showServiceNotes: false,
enteredServiceNote: '', //service notes addendum
}
},
computed : {
// something
},
methods: {
setServiceNotes(){
this.showServiceNotes = !this.showServiceNotes;
},
addAnotherParty(){
this.validateForm();
if(!this.formIsValid){
return;
}
this.$emit('add-parties', this.additionalInfo); //event
console.log(this.clearForm);
},
clearForm(){
this.additionalInfo.fullName = '';
this.additionalInfo.serviceAddress = '';
this.additionalInfo.preAuthorize = false;
}
}
}
</script>
Parent Component
<template>
<div>
<base-card
ref="childComponent"
#add-parties="updateAdditionalInfoList">
<!-- Wrapper for the `Parties Being Served` component-->
<template v-slot:title>
<slot></slot>
</template>
</base-card>
</div>
</template>
<script>
export default {
data() {
return {
hasElement: false,
selectedComponent: 'base-card',
additionalInfoList : [],
clearForm: false
}
},
methods: {
updateAdditionalInfoList(additionalInfo){ //save changes passed via event
this.additionalInfoList.push(additionalInfo);
console.log('emitted');
console.log(this.additionalInfoList);
setTimeout(() => {
this.$refs.childComponent.clearForm(); //clear the form in child
}, 2000);
}
}
}
</script>
Try this
addAnotherParty(){
this.validateForm();
if(!this.formIsValid){
return;
}
let emitObj = JSON.parse(JSON.stringify(this.additionalInfo));
this.$emit('add-parties', emitObj); //event
console.log(this.clearForm);
}
If your object is not deep then you can use
let emitObj = Object.assign({}, this.additionalInfo);
instead of stringify and parse
I have this:
<template>
<div class="col-md-12" style="margin-bottom: 10px;">
<b-pagination
v-model="currentPage"
:total-rows="totalRows"
:per-page="perPage"
/>
</div>
</template>
<script>
data : function () {
return {
images: [],
isLoadingImage: true,
loadingText: "Please wait while we're loading the images...",
searchText : '',
currentPage: 1,
totalRows: 16,
perPage: 50,
}
},
watch : {
currentPage (to, from) {
this.searchImage();
},
},
mounted() {
this.searchImage();
},
methods : {
searchImage() {
let _this = this;
this.isLoadingImage = true;
MyCustomService.showImage(this.searchText,this.currentPage).then(function(result){
_this.isLoadingImage = false;
_this.images = result.data.results;
_this.totalRows = result.data.page.totalitems;
_this.perPage = result.data.page.itemsperpage;
});
}
}
</script>
I noticed that when I clicked the numbers on the pagination, this one:
It calls the searchImage() twice. So when i wanted to go to page 2, so that makes the currentPage = 2, it goes to page 2 then it resets back to 1.
BTW - the MyCustomService.showImage() is an async function, not sure if that gives you an additional info.
Why is that? I think my code is very straight forward but i am getting this strange result.
Let me know if you need further clarification and i'm happy to add some information.
Thanks and your help is greatly appreciated!
I'm working on a Vue project which has a component for loading content into a modal via an ajax call:
<load-content target="foo"></load-content>
<load-content target="bar"></load-content>
<load-content target="oof"></load-content>
<load-content target="rab"></load-content>
Here's an example template:
<template>
<span class="load-content-wrapper" v-on:click="load">
Click
</span>
</template>
<script>
export default {
name: 'load content',
props: {
target: {
type: String,
required: true
}
},
methods: {
load() {
$('#load-content-modal').modal('show');
this.$store.dispatch('loadContent', this.target);
},
}
};
</script>
Which would trigger this example action:
const actions = {
loadContent ({ commit }, target) {
$.ajax({
url: '/api/fetch-content/' + target,
}).then((data) => {
// Load Modal Window
});
},
};
This all works well, except we cannot guarantee that the Ajax call will always return content. Depending on the target it could return 404.
Ideally I want to automatically disable individual load-content components if '/api/fetch-content/' + target isn't available to prevent users from trying to select unavailable content.
What is the correct/ most efficient way to do this?
You should make your "target" field not required and instead add a default value empty string.
And add an "if" condition to your load method. If "target" is empty, it will not proceed.
export default {
name: 'load content',
props: {
target: {
type: String,
default: ''
}
},
methods: {
load() {
if (!this.target) return;
$('#load-content-modal').modal('show');
this.$store.dispatch('loadContent', this.target);
},
}
};
Create a store variable loading and mutate it in your actions as follows:
loading: false
const actions = {
loadContent ({ commit }, target) {
$.ajax({
url: '/api/fetch-content/' + target,
}).then((data) => {
// Load Modal Window
commit(setLoading)
});
},
};
Then in muatations ->
setLoading (state, loading) {
state.loading = true
}
Now in your vue file use this store variable and check if it is true then load the component.You may check this created or mounted events of the component.
Option 1
Preemptively load the content, and disable the ones that return an error.
This is what the parent component will look like
<template>
<load-content
v-for="(target, index) in loadedTargets"
:key="index"
target="target"
/>
</template>
<script>
export default {
name: 'load content parent',
data: function() {
return {
targets: [
{link: 'foo', data: null, loaded: false, error: null},
{link: 'bar', data: null, loaded: false, error: null},
{link: 'oof', data: null, loaded: false, error: null},
{link: 'rab', data: null, loaded: false, error: null},
]
}
},
computed: {
loadedTargets() {
return this.targets.filter(t => t.loaded)
}
},
methods: {
load(target) {
const self = this;
$.ajax({
url: '/api/fetch-content/' + target.link,
}).then((data) => {
self.targets[indexOf(target)].data = data
self.targets[indexOf(target)].loaded = true
}).catch((error) => {
self.targets[indexOf(target)].error = error
});
},
},
mounted() {
this.targets.forEach(target => this.load(target))
}
};
</script>
Option 2
Preemptive loading is expensive (and since I don't know how many targets you might have), you could also show success/error in the modal. Proper UX would dictate that an explicit action by the user should lead to a result (i.e. if the user clicks a link, he should either see data in the modal, or an error)
This is what your action will look like:
const actions = {
loadContent ({ commit }, target) {
$.ajax({
url: '/api/fetch-content/' + target,
}).then((data) => {
// Load Modal Window
}).catch((error) => {
// Load Modal Window, and show the error
});
},
};
My component looks like this:
<template>
<div>
<div v-if="!loaded">
<p><i class="fas fa-spinner fa-spin"></i> Loading feed</p>
</div>
<div v-else>
<div data-slider ref="feedSlider" v-if="length > 0">
<div class="swiper-wrapper">
<div class="slide" v-for="record in records" :key="record.id">
<slot :record="record"></slot>
</div>
</div>
</div>
<div v-else>
<p>There are no records available.</p>
</div>
</div>
</div>
</template>
<script>
import Swiper from 'swiper';
import AjaxCaller from '../../mixins/AjaxCaller';
export default {
mixins: [AjaxCaller],
data() {
return {
loaded: false,
records: [],
length: 0,
}
},
mounted() {
this.makeCall(this.success, this.failure);
},
methods: {
success(response) {
this.loaded = true;
if (!response.data.records) {
return;
}
this.records = response.data.records;
this.length = this.records.length;
if (this.length < 2) {
return;
}
setTimeout(() => {
this.initiateSlider();
}, 1000);
},
initiateSlider() {
(new Swiper(this.$refs.feedSlider, {
effect: 'slide',
slideClass: 'slide',
slideActiveClass: 'slide-active',
slideVisibleClass: 'slide-visible',
slideDuplicateClass: 'slide-duplicate',
slidesPerView: 1,
spaceBetween: 0,
loop: true,
speed: 2000,
autoplay: {
delay: 5000,
},
autoplayDisableOnInteraction: false,
}));
},
failure(error) {
this.stopProcessing();
console.log(error);
}
}
}
</script>
The imported mixin AjaxCaller, which works fine with any other component:
<script>
export default {
props: {
url: {
type: String,
required: true
},
method: {
type: String,
default: 'post'
}
},
data() {
return {
processing: false
}
},
computed: {
getMethodParams() {
if (this.method === 'post') {
return {};
}
return this.requestData();
},
postMethodData() {
if (this.method === 'get') {
return {};
}
return this.requestData();
}
},
methods: {
requestData() {
return {};
},
startProcessing() {
this.processing = true;
this.startProcessingEvent();
},
stopProcessing() {
this.processing = false;
this.stopProcessingEvent();
},
startProcessingEvent() {},
stopProcessingEvent() {},
makeCall(success, failure) {
this.startProcessing();
window.axios.request({
url: this.url,
method: this.method,
params: this.getMethodParams,
data: this.postMethodData
})
.then(success)
.catch(failure);
}
}
}
</script>
And here's how I call it from within the view:
<feed-wrapper url="{{ route('front.news.feed') }}">
<div slot-scope="{ record }">
<p>
<a :href="record.uri" v-text="record.name"></a><br />
<span v-text="record.excerpt"></span>
</p>
</div>
</feed-wrapper>
Everything works fine in any browser other than IE 11 (and lower).
It even works in Edge - no issues what so ever.
In IE I get
[Vue warn]: Failed to generate render function:
Syntax Error: Expected identifier in ...
It doesn't even get to execute method call from within the mounted segment.
I use laravel-mix with Laravel so everything is compiled using webpack with babel so it's not ES6 related issue.
I've already spent whole night trying to un-puzzle this so any help would be much appreciated.
I know you've already said that you don't believe it's an ES6 issue but the evidence suggests it is.
IE11 doesn't support destructuring. If you type something like var {record} = {} into your IE11 console you'll see this same error message, 'Expected identifier'.
Try doing a search through the compiled code in your original error message and look for the word record. I suspect you'll find something like this:
fn:function({ record })
If you see that it means that the destructuring has made it to the browser without being compiled through Babel.
Exactly why this is happening depends on where you're using that scoped slot template. If you're using it inside a single-file component it should be going through Babel but if you aren't then it may be making it to the browser without transpiling. You said that you're calling it 'from within the view' but that doesn't clarify exactly how you're using it. There's a note about this in the docs, for what it's worth:
https://v2.vuejs.org/v2/guide/components-slots.html#Destructuring-slot-scope
Assuming you aren't able to fix the transpiling problem directly (e.g. by moving the template to somewhere it'll go through Babel) you can just remove the ES6 destructuring. So something like:
<div slot-scope="slotProps">
and then using slotProps.record instead of record in the code that follows.