use setInterval to achieve parameter add 10 every 5seconds but the result sequence is very strange - vue.js

I use setInterval to achieve parameter mytime add 10 every 5seconds.
For example, I expect to get a result list like 1 11 21 31 41...
But the real result sequence is 1 11 31 71 151 311...
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>
<body>
<div id="app-6">
{{ aaa() }}
</div>
</body>
</html>
<script>
var app6 = new Vue({
el: '#app-6',
data: {
mytime: 1
},
methods: {
aaa: function() {
setInterval(() => {
this.bbb()
}, 5000);
return this.mytime;
},
bbb: function() {
this.mytime = this.mytime + 10;
},
}
})
</script>

Every time it re-renders, it calls aaa() again. And every time this function is called, it sets a new timer.
Everytime a timer is set, it will add multiple times:
at first it adds 10 (because there's only one timer), but this first adding triggers aaa() again, which creates an additional timer
so when another 5s pass, there are two timers now, which add 10 each, this going from 11 to 31 straight. But this change also triggers aaa() which also creates new timers, and this goes on...
Solution: My suggestion is you add {{ mytime }} to the templated and trigger one setInterval() only at the created() lifecycle hook.
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>
<body>
<div id="app-6">
{{ mytime }}
</div>
<script>
var app6 = new Vue({
el: '#app-6',
data: {
mytime: 1
},
created() {
setInterval(() => {
this.bbb()
}, 5000);
},
methods: {
bbb: function() {
this.mytime = this.mytime + 10;
},
}
})
</script>
</body>
</html>

Related

Vue - #input is triggered by :placeholder in Internet Explorer 11 immediately upon page load not when entering a value

Vue - #input is triggered by :placeholder in Internet Explorer 11 immediately upon page load not when entering a value. That is, the problem is only in the explorer. When the page loads, input is triggered immediately, but only if there is a placeholder
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Тег SCRIPT</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<component-c/>
</div>
<script type="text/javascript">
var ComponentA = Vue.component('ComponentA', {
props: ['field'],
methods: {
//#input is triggered by :placeholder in Interner Exployer 11 immediately upon page load not when entering a value
validator: function (ev){
console.log(ev.target.value, 'value in validator');
}
},
computed: {
fieldPlaceholder: function () {
return this.field.placeholder;
},
},
template: '<input type="password" #input="validator" :placeholder = "fieldPlaceholder">'
});
var ComponentС = Vue.component('ComponentB', {
data: function () {
return {
field: {
placeholder: 'place'
}
}
},
components: {
'component-a': ComponentA,
},
template: '<component-a :field = "this.field" />'
})
var app = new Vue({
el: '#app',
components: {
'component-c': ComponentС,
}
})
</script>
</body>
</html>

How to include promises in vuejs methods

The code below has vuejs methods. One is calling another through the promise function. How can I make handleStart be invoked first, then once done is true, foo will be resolve, and handleStart will finish. The start button must be clicked first
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button
#click="handleStart"
>
START
</button>
<button
#click="done = true"
>DONE</button>
<h1>Start the app: {{start}}</h1>
<h1>Is it done? {{done}}</h1>
</div>
<script>
var app = new Vue({
el: '#app',
data () {
return {
start: false,
done:false
}
},
methods: {
foo() {
return new Promise( (resolve) => {
if (this.done) {
console.log("done is recorded")
resolve("Yaa")
}
})
},
handleStart () {
this.start = true
// how to make this an obsersable
this.foo()
.then( (data ) => console.log("I must be printed with:", data))
}
}
})
</script>
</body>
</html>
you need to use watchers to watch this.done change
watch: {
done(newVal, oldVal) {
if (newVal) {
// do something
}
}
},
methods: {
async handleStart () {
// how to make this async
this.start = true
const data = await this.foo()
console.log("I must be printed with:", data))
}
}
The problem is with the if (this.done) check.
When done is false, the promise is never resolved, and the handleStart never receives data.
If you need to react when a data has changed, take a look Vue's watchers

How to set pageCount manually in vuejs-paginate?

My HTML:
<paginate
:pageCount="max"
:containerClass="'pagination'"
:clickHandler="redirectToPage"
:force-page="selectedPage">
</paginate>
max is getter from vuex. When paginate is loading max = undefined, so I need to set pageCount after value max is changed.
In offical docs only static value:
Taking Belmin Bedak's comment into account, here it is working with a v-if to make it wait for pageCount to load. In testing, I found that updating pageCount works as expected: the number of pages available is updated.
vm = new Vue({
el: '#app',
data: {
max: null
},
components: {
paginate: VuejsPaginate
},
methods: {
clickCallback: function(page) {
console.log(page);
}
},
mounted() {
// Pretend we're getting from vuex
setTimeout(() => {
this.max = 7;
}, 1000);
}
});
<link href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet" />
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<script src="https://unpkg.com/vuejs-paginate#0.8.0"></script>
<div id="app">
<paginate v-if="max"
:page-count="max"
:container-class="'pagination'"
:click-handler="clickCallback">
</paginate>
<div v-else>
Loading...
</div>
</div>

VueJS Data ForLoop Issue

I'm using forloop to check the items in my data in COMPONENT.
{
data:function(){
return {
items:[
{id:1,name:'John'},
{id:2,name:'FooBz'}
]
}
}
}
now I want to check the value first in console in ready hook of my component.
{
.....
ready:function(){
console.log(this.items);
// this return a [__ob__: Observer]
this.items.forEach(function(x,y){
............
});
}
}
the this.items return a '[ob: Observer]' which I can't iterate through because the length of that value is 0 it supposed to be 2.
EDIT:
this is strange on my JSBIN all are working but in my real code its not. Even though I copied my logic from my real code I'm using Laravel Elixir to compile my javascript and 1.0.24 version of Vue.
http://jsbin.com/gijaniqero/edit?html,js,console,output
Your code should be okay.
Just using your code, i have made demo. It should be okay
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<test_component></test_component>
</div>
<template id="test_component">
<div></div>
</template>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el:'#app',
data: {
},
components : {
'test_component' : {
template : '#test_component',
data:function(){
return {
items:[
{id:1,name:'John'},
{id:2,name:'FooBz'}
]
}
},
ready : function(){
this.items.forEach(function(x,y){
console.log( 'id is : ' + x.id);
console.log( 'name is L ' + x.name);
console.log( 'key is ' + y);
});
}
}
}
})
</script>
</body>
</html>

Running functions on a data object

Basically, when I load my homepage, vue.js requests an api, that returns a json response like so
[
{
"time": 321
},
{
"time": 2712
}
]
When the request is finished loading, I assign the the array to a timers object in the data object in my vue.js file.
This is where it gets tricky. So basically, when above is loaded into vue, I need each one to be incremented each second, with setInterval(). To make it even worse, I need another callback for each function where I can pause the timer, and send another request to the server (to pause the timer serverside).
Any ideas?
I ended up creating a new timer that starts, when the document is loaded. To the response I've also added a counting attribute (boolean).
new Vue({
el: "#body",
data: {
timers: [
{
time: 222,
counting: true
},
{
time: 4123,
counting: true
}
],
test: 2
},
methods: {
pauseTimer: function(timer) {
timer.counting = !timer.counting;
}
},
ready: function() {
var that = this;
var timer = setInterval(function(){
$.each(that.$data.timers, function(index, value){
if(value.counting)
value.time++;
});
}, 1000);
}
});
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body id="body">
<ul>
<li v-repeat="timers">{{ time }} - </li>
</ul>
{{ $data | json 2 }}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.10/vue.js"></script>
</body>
</html>