Running functions on a data object - vue.js

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>

Related

vue-js-modal not showing in HTML

I checked the demo and confirmed it does work in the demo way. But I need to use the components in HTML but not in webpack-ed a modal.vue template. So I wrote the following:
<body>
<div id="app">
<modal name="test">
test
</modal>
</div>
<script src="{% static 'js/tmpdev.bundle.js' %}" type="text/javascript"></script>
<script>
Vue.use(VueJsModal, {
dialog: true,
dynamicDefaults: {
draggable: true
}
})
new Vue({
el: '#app',
components: {
},
data() {
return {
};
},
mounted() {
window.addEventListener('keydown', (e) => {
if (e.key == 'Escape') {
this.toggle();
}
});
this.$modal.show('test');
},
methods: {
toggle() {
this.$modal.show('test');
}
},
filters: {
},
});
</script>
</body>
The above should display the modal window on the screen immediately when I reloaded the tab or additionally when I pressed "esc" key. But for some reason this doesn't show the modal. The console log has no error on it, I can see <div id="modals-container"></div> on the HTML source, the this.$modal.show('test'); part is executed without an error. So I have no clue now. What is wrong with the code above? Thanks.
You should add Escape key EventListener code in the created life cycle hook.
window.addEventListener('keydown', this.toggle);
In methods object :
toggle(event) {
if (event.keyCode === 27) {
this.$modal.show('test');
console.log('esc key pressed');
}
}
Once you done with the requirement, You can destroy this event to prevent memory leaks.
destroyed: function() {
document.removeEventListener('keydown', this.toggle);
}

Vue.js - How to switch the URL of an image dynamically?

I am working on a site where the user can select an image via radio selection.
I would like to dynamically update the image URL depending on selection of the user. My approach is to use a computed variable which returns the URL from a list of objects depending on the selection of the user.
<template>
<v-img
:src="require(currBackgroundURL)"
class="my-3"
contain
width="397"
height="560"
></v-img>
</template>
<script>
// data() ...
currBackground: 0,
backgrounds: [
{
name: "Flowers",
url: "../assets/background/bg_1.png"
},
// ...
computed: {
currBackgroundURL: function() {
return this.backgrounds[this.currBackground].url
}
}
</script>
Unfortunately, i get an error which says Critical dependency: the request of a dependency is an expression.
And the browser console says: [Vue warn]: Error in render: "Error: Cannot find module '../assets/background/bg_1.png'"
Question: What is the right way to switch the URL of the image dynamically?
Thanks for your help!
Here is a working example:
var app = new Vue({
el: '#app',
data: () => ({
currBackground: 0,
backgrounds: [
{
name: "black",
url: "https://dummyimage.com/600x400/000/fff"
},
{
name: "blue",
url: "https://dummyimage.com/600x400/00f/fff"
},
{
name: "red",
url: "https://dummyimage.com/600x400/f00/fff"
}
]
}),
computed: {
currBackgroundURL: function() {
return this.backgrounds[this.currBackground].url
}
},
methods: {
nextImage() {
this.currBackground += 1
if (this.currBackground > 2) {
this.currBackground = 0
}
}
}
})
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.18/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<div id="app">
<v-btn #click="nextImage()">Change image</v-btn>
<v-img
:src="currBackgroundURL"
class="my-3"
contain
width="397"
height="560"
></v-img>
</div>
</body>
I removed the require.
The src is a link/path so you don't need require. require will try to take a path and load it into a module instead of a link/path.
Hopefully, this helps.

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

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>

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>