Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a countdown with vue.js and moment.js

I am creating a timer using vue.js and moment.js, I use only minutes and seconds, my code should work, but I do not get the desired result:

var app = new Vue({
  el: '#app',
  data: {
    date: moment(60 * 10 * 1000)
  },
  computed: {
    time: function(){
      return this.date.format('mm:ss');
    }
  },
  mounted: function(){
    var aa = this.date;
    
    setInterval(function(){
      aa.subtract(1, 'seconds');
    }, 1000);
  }
});
<script src="https://momentjs.com/downloads/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>

<div id="app">{{ time }}</div>
like image 709
Caio Kawasaki Avatar asked Aug 28 '18 00:08

Caio Kawasaki


3 Answers

As @Phil pointed out, the issue is caused by reactivity issue. subtract just update some properties then return orginal object.

So we should have to use one new object to replace old one. (Probably exists one way to use Vue.set or vm.$set to update the properties of moment object, hopefully someone can point out.)

Like below demo:

var app = new Vue({
  el: '#app',
  data: {
    date: moment(60 * 10 * 1000)
  },
  computed: {
    time: function(){
      return this.date.format('mm:ss');
    }
  },
  mounted: function(){   
    setInterval(() => {
      this.date = moment(this.date.subtract(1, 'seconds'))
    }, 1000);
  }
});
<script src="https://momentjs.com/downloads/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>

<div id="app">{{ time }}</div>
like image 142
Sphinx Avatar answered Nov 15 '22 19:11

Sphinx


here is example of count down using VUE with moment

<script>
new Vue({
el: '#app',
data: {
message: 'Current Time:',
currentTime: null },

methods: {
updateCurrentTime: function updateCurrentTime() {
  this.currentTime = moment().format('LTS');
} },

created: function created() {var _this = this;
this.currentTime = moment().format('LTS');
setInterval(function () {return _this.updateCurrentTime();}, 1 * 1000);
} });

</script>
<section id="app" class="section">
<h3 class="title is-3 shadow" v-text="message"></h3>
<p class="time shadow" v-text="currentTime"></p>
</section>

<style> 
body, html {
width: 100%;
height: 100%; 
}

body {
background: -webkit-linear-gradient(LightSteelBlue, LightSalmon);
background: -o-linear-gradient(LightSteelBlue, LightSalmon);
background: -moz-linear-gradient(LightSteelBlue, LightSalmon);
background: linear-gradient(LightSteelBlue, LightSalmon); 
}

section.section {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 140px;
background: transparent;
}

h3.is-3, p.time {
color: white;
}

h3.is-3:not(:last-child) {
margin: 0;
padding: 0;
}

.time {
font-size: 7em;
}

.shadow {
text-shadow: 0 0 15px rgba(100, 100, 100, 0.35);

</style>

Countdown component for VueJS with momentjs

here is a reference link

alsi that's example without vue only using moment

// get next Sunday
var nextSunday = moment().day(7).format("YYYY-MM-DDT11:00:00Z");

// make it a moment object again
var event = moment(nextSunday);

// get current time/date
var current = moment();

// get difference between event and current
var diffTime = event.diff(current);

// let moment.js make the duration out of the timestamp
var duration = moment.duration(diffTime, 'milliseconds', true);

// set interval to milliseconds
var interval = 1000;

setInterval(function(){
  duration = moment.duration(duration - interval, 'milliseconds');
  $('#clock').html(
      "<div class=\'days cell\'>"+duration.days()+"<span>days</span></div>" +
      "<div class=\'hours cell\'>"+duration.hours()+"<span>hours</span></div>" +
      "<div class=\'mins cell\'>"+duration.minutes()+"<span>mins</span></div>" +
      "<div class=\'secs cell\'>"+duration.seconds()+"<span>secs</span></div>")
}, interval);
$section-color: #343436;
body {
  background-color: #1d1f20;
  color: #99999d;
}
body * {
  box-sizing: border-box;
}

#clock {
  width: 80%;
  margin: 10em auto;
  text-align: center;
  transform: scale(0.8);
}
#clock .cell {
  display: inline-block;
  width: 80px;
  height: 60px;
  background-color: #1b1b1c;
  position: relative;
  border-radius: 5px;
  margin-right: 5px;
  font-size: 3rem;
  padding-top: 2px;
}
#clock .cell span {
  position: absolute;
  left: 0;
  bottom: -30px;
  clear: both;
  text-align: center;
  text-transform: uppercase;
  width: 80px;
  height: 20px;
  font-size: 10px;
}

body {
  background-color: #1d1f20;
  color: lighten($section-color, 40%);
  
  * {
    box-sizing: border-box;
  }
}

#clock {
  width: 80%;
  margin: 10em auto;
  text-align: center;
  transform: scale(.8);
  

}
  .cell {
    display: inline-block;
    width: 80px;
    height: 60px;
    background-color: darken($section-color, 10%);
    position: relative;
    border-radius: 5px;
    margin-right: 5px;
    font-size: 3rem;
    padding-top: 2px;
    color:white;
  }
  .cell span {
    position: absolute;
    left: 0;
    bottom: -30px;
    clear: both;
    text-align: center;
    text-transform: uppercase;
    width: 80px;
    height: 20px;
    font-size: 10px;
   color:white;
  }
}
 <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment.min.js'></script>

<div id="clock"></div>

<div style= "color:white;" id="countdown">

</div>
like image 3
Ahmed amin shahin Avatar answered Nov 15 '22 19:11

Ahmed amin shahin


This is a reactivity issue. Vue isn't going to watch / bind on method calls to your moment object.

You'll need to assign the result of the date manipulation back to your date property. You also need to clone the moment instance so it appears as a new value and not the same instance.

setInterval(() => {
  this.date = this.date.clone().subtract(1, 'seconds')
}, 1000)
like image 2
Phil Avatar answered Nov 15 '22 18:11

Phil