How to update Time in DOM In Vue.js without uisng set-timeout or set-interval - vue.js

I want to update time without using setInterval function in Vue. Is there any way? It's work with setInterval like the code below. However, I want something inbuilt in vue or any other best/different way to do it.
new Vue({
el: '#app',
data: {
seconds: '',
},
mounted:function(){
setInterval( () => {
this.seconds= new Date().getSeconds();
}, 100);
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id="app">
Realtime Second = {{seconds}}
</div>

For things that need to change after a single update cycle we have this.$nextTick. This is, however, not really useful for a timer. That makes window.setInterval the next best thing.
Keep in mind that just like with manually added event handlers, timeouts and intervals must be manually cleared in a lifecycle hook. Your current code should be something like:
new Vue({
el: '#app',
data: {
seconds: (new Date).getSeconds(),
intervalRef: null
},
mounted () {
this.intervalRef = window.setInterval(() => {
this.seconds = (new Date).getSeconds();
});
},
beforeDestroy () {
if (this.intervalRef) {
window.clearInterval(this.intervalRef);
this.intervalRef = null;
}
}
});

Related

How to translate a basic javascript variable in vue.js

How can I translate this :
var start = Date.now();
var end = Date.now() + 604800000;
to vue.js? Is it in methods? actions?
Is something like this correct?
actions: {
start ({commit, getters}, payload) {
var start = Date.now()
},
Do you want to use vuejs or Vuex? actions is a reserved to register actions on a Vuex store. You can find below how to translate your code in a simple Vue instance.
index.html
<body>
<div id="app"></div>
</body>
main.js
import Vue from "vue";
new Vue({
el: "#app",
template: "<p> {{ end }}</p>",
data: {
start: null
},
mounted() {
this.start = Date.now();
},
computed: {
end() {
return this.start + 604800000;
}
}
});
For this example, start is calculated when the vue instance is mounted on the <div id="app"></div> block. end is a computed property that will be calculated as soon as the start property value has changed.
Have a look at here, they describe a similar example.

How to implement dirty state in VueJs

I am new to VueJs and I am working on a form that I want to enable the Save button only when a change occurs at the model.
My initial thought is to compute a dirty function comparing the initial model with the current.
Note: This code is not tested, it's here just for an example.
var app = new Vue({
el: '#app',
data: {a:0, b:'', c:{c1:null, c2:0, c3:'test'}},
initialData: null,
mounted():{ initialData = JSON.parse(JSON.stringify(data));},
computed: {
isDirty: function () {
return JSON.stringify(data) === JSON.stringify(initialData)
}
}
});
Is there a better way of doing this or is there any improvement you could suggest on the above-mentioned code?
You can use the deep option of watch as shown in the manual
var app = new Vue({
el: '#app',
data:
{
model:
{
a:0,
b:'',
c:
{
c1:null,
c2:0,
c3:'test'
}
},
dirty: false
},
watch:
{
model:
{
handler(newVal, oldVal)
{
this.dirty = true;
},
deep: true
}
}
});
Borrowing from -- > https://stackoverflow.com/a/48579303/4050261
You can bind single onchange event on the parent container and benefit from the fact that change events bubble:
<div class="container" #change="someThingChanged()">
<input v-model="foo">
<input v-model="bar">
... etc.
</div>

V-model with datepicker input

Trying to build a component that works with daepicker and using v-model to bind the input value. But the input event does not appear to be firing and I can’t seem to figure out why. Here’s my component:
<div id="app">
<datepicker v-model="date"></datepicker>
</div>
Vue.component('datepicker', {
template: '<input type="text" class="form-control pull-right" placeholder="dd/mm/aaaa" autocomplete="off">',
mounted: function() {
$(this.$el).datepicker({
autoclose: true,
startView: 'years',
}).on('changeDate', function(e) {
this.$emit('input', e.format('dd/mm/yyyy'));
});
},
destroyed: function () {
$(this.$el).datepicker('destroy');
}
});
var app = new Vue({
el: '#app',
data: {
date: '2018-03-01'
}
})
In addition, the following error appears in the console:
Uncaught TypeError: this.$emit is not a function
If you're mixing jQuery and Vue (just a guess from the code fragment), you're mixing up your contexts. One (of many) ways to fix:
mounted: function() {
const self = this;
$(this.$el).datepicker({
autoclose: true,
startView: 'years',
}).on('changeDate', function(e) {
self.$emit('input', e.format('dd/mm/yyyy'));
});
},
I failed with jacky's answer, but thanks to https://github.com/Xelia, problem sovled (even in Vue 1.0, using ready life cycle instead of mounted)
Manually update vue data in datepicker changeDate event listener, like this
var app = new Vue({
el: '#app',
data: {
startDate: '',
},
mounted() {
$("#startDate").datepicker().on(
"changeDate", () => {this.startDate = $('#startDate').val()}
);
},
})
https://jsfiddle.net/3a2055ub/
And by the way, if you are working on legacy company project using ES5 function instead of ES6 fat arrow function. Need to bind this, which is vue instance, into the function. For example:
mounted() {
var self = this; // the vue instance
$("#startDate").datepicker().on(
"changeDate", function() {self.startDate = $('#startDate').val()}
);
},
Of course there are other ways to reach this goal, as this blog written by Jason Arnold
shows.
Reference: https://github.com/vuejs/vue/issues/4231
Probable related question: v-model not working with bootstrap datepicker

Vue.js re-render static content

I'm new with Vue.js, and I notice some content re-render after changing any data that is not part of that content, here is an example:
https://jsfiddle.net/gustavompons/rtxqhyv2/1/
HTML
<div id="app">
<input v-model="foo1">
<div v-html="showFoo1()"></div>
<div v-html="showFoo2()"></div>
</div>
JS
new Vue({
el: '#app',
data: {
foo1: 'foo1',
foo2: 'foo2'
},
methods: {
showFoo1 () {
console.log('this is ok to execute on input')
return this.foo1
},
showFoo2 () {
console.log('this should NOT execute on input')
return this.foo2
}
}
})
So every time I type on the input, I get "this should NOT re-render on input" in the console, which I think it's not ok because there is no reason to execute that piece of code every time.
Is this the way Vue work or am I doing something wrong?
I'm using vue.js v2
The results of methods are not cached and will be executed every time the component is re-rendered. If you want caching and dependency tracking, use computed properties instead:
computed: {
showFoo1 () {
console.log('this is ok to execute on input')
return this.foo1
},
showFoo2 () {
console.log('this should NOT execute on input')
return this.foo2
}
}
And get rid of the () when accessing them.

VueJs async template/component with placeholder

I am pretty new to VueJs, so I am still figuring things out.
Since our templates are stored in the database, I want my templates to load async. For my components I now use the component-factory approach.
var c = Vue.component('my-async-component', function(resolve, reject){
setTimeout(function(){
resolve({
template: '<div class="loader">loaded asynchronous: {{ pageName }}</div>',
data() {
return {
pageName: 'my Page'
}
}
})
},2000)
})
But is it possible to have some kind of placeholder while loading it? I know I can do something with But in that case I need to have a parent component and I would like this to be independent.
On a Vue-instance you can do stuff in the render function end hook it up to mounted like:
var app = new Vue({
el: '#app',
data: {
finish: false,
template: null
},
render: function(createElement) {
if (!this.template) {
return createElement('div', 'loading...');
} else {
return this.template();
}
},
mounted() {
var self = this;
$.post('myUrl', {foo:'bar'}, function(response){
var tpl = response.data.template;
self.template = Vue.compile(tpl).render;
})
}
})
Is this possible in a component? And is this still working when I have some nested divs (see an other question of mine: here)
Ok, I figured it out. I just needed to reed de VUE guide a little bit bettter.
I just followed the advanced async example from the docs and now I have a working example.
So I have my template like this:
<div id="app">
<my-async-component></my-async-component>
</div>
Then in my JS I declared the template like:
var c = Vue.component('my-async-component', function(){
return {
component: new Promise(function(resolve, reject){
// setTimeout to simulate an asynchronous call
setTimeout(function(){
resolve({
template: '<div class="loader">loaded asynchronous</div>'
})
},3000)
}),
loading: Vue.component('loader', {
template: '<p>loading...</p>'
}),
error: Vue.component('load-error', {
template: '<p>error loading component</p>'
}),
delay: 200,
timeout: 10000
}
})
var vm = new Vue({
el: '#app'
});
The loading and error components could also be globally registered components, so it's easy to reuse.
Hopefully I could help someone with this answer to my own question.