VueJS BPagination - calls my method multiple times everytime it changes the currentPage - javascript

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!

Related

Scheduling ToneJS events while transport is playing

I have 4 notes playing in my Tone JS app and would like to change the 3rd note to be something else whilst the transport is currently playing. Here is my code:
JS:
import { Transport, start, Sampler } from "tone";
const notesToPlay = [
{
timing: 0.25,
sameAsLast: false,
duration: 0.1,
velocity: 1
},
{
timing: 0.5,
sameAsLast: true,
duration: 0.1,
velocity: 1
},
{
timing: 0.75,
sameAsLast: false,
duration: 0.1,
velocity: 1
},
{
timing: 1,
sameAsLast: false,
duration: 0.2,
velocity: 1
}
];
var eventIds = [];
(function () {
function playSynth() {
Transport.start();
start();
}
const sampler = new Sampler({
urls: {
A1: "A1.mp3",
A2: "A2.mp3"
},
baseUrl: "https://tonejs.github.io/audio/casio/",
onload: () => {
loadNotes();
}
}).toDestination();
function loadNotes() {
notesToPlay.forEach((n) => {
const eventId = Transport.scheduleRepeat((time) => {
sampler.triggerAttackRelease(
["A1"],
n.duration,
n.timing + time,
n.velocity
);
}, 4);
eventIds.push(eventId);
});
}
document.getElementById("play").addEventListener("click", function () {
playSynth();
});
document.getElementById("stop").addEventListener("click", function () {
Transport.stop();
});
document.getElementById("replace").addEventListener("click", function () {
const arrayIdxToReplace = 2;
Transport.clear(eventIds[arrayIdxToReplace]);
const note = notesToPlay[arrayIdxToReplace];
Transport.scheduleRepeat((time) => {
sampler.triggerAttackRelease(
["D1"],
note.duration,
note.timing + time,
note.velocity
);
}, 4);
});
})();
HTML:
<div id="app">
<button id="play">play me</button>
<button id="stop">stop</button>
<button id="replace">Replace 3rd note</button>
</div>
When I click the replace 3rd note button it removes the old event which is good but when it schedules the new event in it is out of sync with where the old 3rd note would be.
A way to get around this is by stopping the Transport then clicking to replace the 3rd note and then clicking play again however I want to be able to do this while the Transport is still playing. Where have I gone Wrong?
Here is a fiddle to demo the issue:
https://codesandbox.io/s/tonejs-forked-fxhzm?file=/src/index.js:0-1643
This is pretty awkward to fix the way it is structured now. The trouble is that every note you add is on its own loop, which begins whenever you call scheduleRepeat ... you would have to correct for the offset between the original loop and the new one, which seems kind of tricky.
I'd suggest that you have call scheduleRepeat only once, and have the callback read the list of notes you have stored. That way you can just replace or alter one of those notes and the next time around it'll be changed, and you won't have any timing problems. I think that would mean including the pitch in your note schema.

How to add independent increment counter to new item in array. Vue.js

In my example, i have two arrays.
First array - values, second - zeros for incremental counter.
Any new item have own counter button for him.
But it is not working, and i do not know why. If i push several buttons, i see chaotioc behavior in arrays
JSfiddle
How to repair it?
How to do counter function without button?
Example: if i loading page, i see 3 elements. Counters begining counting from 0. After 10 seconds i add new element. Old counters continue to work, but counter in new element start from 0.
new Vue({
el: '#page',
data: {
arr: [1, 2 ,3],
count: [0, 0 ,0]
},
methods: {
addEll: function() {
this.arr.push(this.arr.length + 1);
this.count.push(0);
},
incrementio: function(val) {
interval = setInterval(() => {
Vue.set(this.count, this.count[val], 0);
this.count[val]++;
}, 1000);
},
},
computed: {
visibleList: function(){
return this.arr;
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="page">
<button v-on:click="addEll">Add element</button>
{{ arr }}
{{ count }}
<ul>
<li v-for="(item, index) in visibleList">
{{item}}
<button v-on:click="incrementio(index)">Counter: {{count[index]}}</button>
</li>
</ul>
</div>
I don't clearly understand from question what your counter should do, but i think it needs to change these lines
Vue.set(this.count, this.count[val], 0);
this.count[val]++;
to this 1 line:
Vue.set(this.count, val, this.count[val]+1);
And I think you need to change setInterval to setTimeout.
Here is updated jsfiddle.
If I understand correctly you trying to count lifetime of each value. Here is my approach. Firstly I tied the value and its counter together in one object as I find it more efficient. Moving on, I defined interval property, because not doing so (The compiler automatically defines it in global scope) may cause unwanted behaviour and it is regarded as an error in strict mode. I also removed unnecessary visibleList computed property from your code. And last but not least I added clearInterval function in beforeDestroy hook as it is a good habit. (In your particular case it might be unnecessary to do so but if it was a component reused many times it would be very important to have it as it frees up the memory.)
new Vue({
el: '#page',
data: {
arr: [{
value: 1,
counter: 0
}],
interval: null
},
mounted () {
this.interval = setInterval(() => {
this.arr.map(x => x.counter++);
}, 1000);
},
beforeDestroy () {
clearInterval(this.interval);
},
methods: {
addEll () {
this.arr.push({
value: this.arr.length + 1,
counter: 0
});
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="page">
<button v-on:click="addEll">Add</button> {{ arr }}
<ul>
<li v-for="(item, index) in arr">
{{item.value}} Counter: {{item.counter}}
</li>
</ul>
</div>
As you can see in the Vuejs documentation Vuejs Caveats
Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
When you modify the length of the array, e.g. vm.items.length = newLength
To overcome caveat 1, both of the following will accomplish the same as vm.items[indexOfItem] = newValue, but will also trigger state updates in the reactivity system:
Vue.set(vm.items, indexOfItem, newValue)
The example would be like this:
new Vue({
el: '#page',
data: {
arr: [1, 2 ,3],
count: [0, 0 ,0]
},
methods: {
addEll: function() {
this.arr.push(this.arr.length + 1);
this.count.push(0);
},
incrementio: function(index) {
this.$set(this.count, index, this.count[index] + 1)
},
},
computed: {
visibleList: function(){
return this.arr;
}
}
})

Vue Js: Issue with scoped slots and IE11

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.

vue pagination total didn't work

<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 ...

Polymer iron-scroll-threshold not triggering

I want to make a feed that automatically loads items when the bottom of the current page is reached, however the iron-scroll-threshold doesn't trigger. I'm using my api call to fill the items in the template and the restaurants load just fine. Also when I bind a load function to a button it works just fine. It seems that the iron-scroll-threshold never triggers. Can anyone explain to me what I'm missing/doing wrong?
Code:
<iron-scroll-threshold id="threshold" lower-threshold="100" on-lower-threshold="loadMoreData">
<div id="scroller" class="vertical layout center" fill>
<template is="dom-repeat" items="[[restaurants]]" filter="{{computeFilter(searchInput)}}" scroll-target="threshold" on-scroll="_scrollHandler">
<!-- Items -->
</template>
<div class="loadingIndicator" hidden$="[[!loadingRestaurants]]">
<paper-spinner active$="[[loadingRestaurants]]"></paper-spinner> Fetching restaurants</b>
</div>
</div>
</iron-scroll-threshold>
<script>
Polymer({
is: 'my-view2',
properties: {
restaurants:{
type: Array,
value: []
},
offset:{
type: Number,
value: 0
},
limit:{
type: Number,
value: 50
},
loadingRestaurants: Boolean
},
ready: function () {
this.$.requestRestaurants.generateRequest();
},
handleResponse: function (data) {
var self = this;
var response = data.detail.response;
response.forEach(function(restaurant){
self.push('restaurants', restaurant);
});
console.log(this.restaurants);
this.$.threshold.clearTriggers();
},
toggle: function(e) {
console.log(this.$.threshold.top);
var index = "#collapse" + e.model.__data.index;
this.$$(index).toggle();
this.loadMore();
},
loadMore: function() {
console.log("test");
this.offset+=50;
this.limit+=50;
this.$.requestRestaurants.generateRequest();
this.$.threshold.clearLower();
this.$.threshold.clearTriggers();
}
});
The naming was inconsistent
on-lower-threshold="loadMoreData"
loadMore: function()

Categories