I am building an app using Nuxtjs. I want to show the live clock in the app. It is showing a live clock until I refresh the page. Once I refresh the page the app gets vanished and a message come “ReferenceError: document is not defined”.
I placed the Clock component inside tags in index.vue file but still getting the same issue.
index.vue file
<template>
<div>
<Navbar />
<Clock />
<Footer />
</div>
</template>
<script>
import Navbar from '../components/Navbar.vue'
import Footer from '../components/Footer.vue'
import Clock from '../components/Clock.vue'
export default {
components: {
Navbar,
Footer,
Clock,
},
}
</script>
<style scoped>
//ignore the css
</style>
Clock.vue
<template>
<div class="clock">
<span>{{ currentDate }}</span>
<span id="clock">{{ startTime() }}</span>
</div>
</template>
<script>
export default {
name: 'Clock',
data() {
return {
currentDate: new Date().toDateString(),
}
},
methods: {
startTime() {
const today = new Date()
let h = today.getHours()
let m = today.getMinutes()
let s = today.getSeconds()
let session = 'AM'
if (h === 0) {
h = 12
}
if (h > 12) {
h = h - 12
session = 'PM'
}
m = this.checkTime(m)
s = this.checkTime(s)
document.getElementById('clock').innerHTML =
h + ':' + m + ':' + s + session
setTimeout(this.startTime, 1000)
},
checkTime(i) {
if (i < 10) {
i = '0' + i
}
return i
},
},
}
</script>
<style scoped>
// ignore the css
</style>
Add ref to your element in the clock.vue and access it in the method using ref.
Your element will be
<span ref="clock">{{ startTime() }}</span>
In your methode you can reference it with
this.$refs.clock.innerHTML = h + ':' + m + ':' + s + session
Related
I have an array with 4 objects, which I render as follows
<div v-for="item in cant_objetivos_tipo">
{{ item.__data__.nombre_monitor_tipo + ' : ' + item.__data__.cantidad_objetivos }}
</div>
then when i try fill another array with the data as follows
<div v-for="item in cant_objetivos_tipo">
{{ datapie.push(item.__data__.nombre_monitor_tipo + ' : ' + item.__data__.cantidad_objetivos) }}
</div
i get infinite loop error
datapie[] is declared before
<script>
import axios from 'axios'
export default {
data() {
return {
cant_objetivos_tipo: [],
datapie: [],
}
},...
I hope you can help me, thank you very much in advance
<template>
<div v-for="(item,index) in cant_objetivos_tipo" :key="index">
{{ item.__data__.nombre_monitor_tipo + ' : ' + item.__data__.cantidad_objetivos }}
</div
</template>
<script>
import axios from 'axios';
export default
{
name: 'MyCustomComponent',
data()
{
return {
cant_objetivos_tipo: [],
};
},
computed:
{
datapie()
{
return this.cant_objetivos_tip.map(item => item.__data__.nombre_monitor_tipo + ' : ' + item.__data__.cantidad_objetivos);
}
},
created()
{
this.fetchData();
}
methods:
{
fetchData()
{
axios.get('/api/get_tipo_objectivos').then(response =>
{
this.cant_objetivos_tipo = response || [];
});
}
}
}
</script>
I need to create a countdown for the expiration date in the VUE 3 application. I need the format of YYYY/MM/DD. my search results were using Moment.js.
After installation using:
npm i moment
I could not figure out the right way to use it.
My Code :
<template>
<p> Remaining time: {{moment(moment(30-9-2022) - moment(new Date())}}
</p>
</template>
<script>
import moment from "moment";
export default {
methods:{
moment,
}
}
</script>
const { createApp, reactive, onMounted } = Vue
const app = createApp({
data() {
const remaining = reactive({})
onMounted(() => {
setInterval(() => {
setTime()
}, 1000)
const eventTime = moment('2023.05.04 10:03:00', 'YYYY.MM.DD HH:mm:ss')
function setTime() {
let currenTime = moment()
remaining.days = moment.duration(eventTime.diff(currenTime)).asDays()
remaining.hours = moment.duration(eventTime.diff(currenTime)).get('hours')
remaining.minutes = moment.duration(eventTime.diff(currenTime)).get('minutes')
remaining.seconds = moment.duration(eventTime.diff(currenTime)).get('seconds')
}
})
return {
remaining
}
}
})
app.mount('#app')
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<div id="app">
<div v-if="Object.keys(remaining).length > 0">
{{ remaining.days.toFixed(0) }} :
{{ remaining.hours.toFixed(0) }} :
{{ remaining.minutes.toFixed(0) }} :
{{ remaining.seconds.toFixed(0) }}
</div>
</div>
I could not find the right usage for this particular problem through my research, so I thought it would be useful to publish it.
The Right Syntax :
<template>
<p>
{{ getRmainTime() }}
</p>
</template>
<script>
import moment from "moment";
export default {
methods:{
getRmainTimeToExp() {
return `${moment
.duration(moment(this.user.exp_time) - moment(new
Date())).years()} years,
${moment.duration(moment(this.user.exp_time) -
moment(new Date())).months()} months,
${moment.duration(moment(this.user.exp_time) -
moment(new Date())).days()} days`;
},
}
}
</script>
```
Im using displayLog function in my vue methods to render logs (in foreach loop) I got from axios.
And i need to bind some handler to my dynamic content, for example changeThisNote.
How can i bind it to my dynamic inserted content?
If I code '#click="changeThisNote' Vue doesn't render it as I need.
Thanks.
methods: {
displayLog: function(log) {
let str = '';
let space = ' ';
let date = log.created_at;...str = '<div class="note" #click="changeThisNote(' + log.id + ')"><div class="note__date">'
+ date + space + name
+ '</div><div class="note__body" id="note_' + log.id + '">' + log.msg + '</div><div></div></div>';
return str;
},
changeThisNote: function(log_id) {
// here I need hide note__body, insert textarea with its data for editing
}
}
You shouldn't be building strings of HTML and inserting them into the DOM. That's missing out on some of the best features of Vue.
What you should do instead is use data to drive your template.
For example, store an array of log data in your component and render that in your template. When your Axios request completes, the template will update automatically
export default {
data: () => ({ logs: [] }),
methods: {
async getLogs () {
const { data } = await axios.get("/logs") // just an example
this.logs = data.map(log => ({
...log,
editing: false // add an "editing" flag
}))
}
}
}
<div
v-for="log in logs"
:key="log.id"
class="note"
#click="log.editing = true"
>
<div class="note__date">
{{ log.created_at }}
{{ log.name }} <!-- 👈 not sure where "name" was meant to come from -->
</div>
<textarea v-if="log.editing" v-model="log.msg"></textarea>
<div v-else class="note__body" :id="`note_${log.id}">
{{ log.msg }}
</div>
</div>
the simplest way would be to create the html element like this:
// ...
methods: {
displayLog (log) {
const div = document.createElement('div')
div.classList.add('note')
div.addEventListener('click', this.changeThisNote(log.id))
div.innerHTML = '<div class="note__date">' + date + space + name + '</div><div class="note__body" id="note_'+log.id+'">' + log.msg + '</div><div></div>'
}
}
// ...
I have a fade-in transition that is working with all my components, the problem is a few of my components that are making api calls - transition in before the data is fully loaded.
So if I have a table with each row being populated with data from the api call, the table headers will transition initially and then a few seconds later - many rows with data will suddenly appear. What I want is for the table/data to fade-in. How can I trigger or delay the transition until the job_execs array gets populated with data from the API call?
views/releases.vue
<script>
import NavBar from "../components/NavBar.vue";
import Releases from "../components/releases/Releases.vue";
import Footer from "../components/Footer.vue";
export default {
name: "releases",
data() {
return {
loading: true
};
},
components: {
NavBar,
Releases,
Footer
},
};
</script>
<template>
<div id="vue-main">
<NavBar></NavBar>
<h1><b>Releases</b></h1>
<transition name="fade" appear mode="out-in">
<Releases></Releases>
</transition>
<Footer></Footer>
</div>
</template>
components/releases/Releases.vue
<template>
<div class="releases">
<table>
<template>
<tr>
<td><b>Version</b></td>
<td><b>Platform</b></td>
<td><b>Status</b></td>
</tr>
<tr v-for="(item, index) in orderedReleases">
<td :style="tdStyle">{{ item.version }}</td>
<td :style="tdStyle">{{ item.platform }}</td>
<td :style="tdStyle">{{ item.status }}</td>
</tr>
</template>
</table>
</div>
</template>
<script>
import moment from "moment";
import sortBy from "lodash/sortBy";
export default {
name: "Releases",
props: ["loading"],
data() {
return {
job_execs: []
};
},
computed: {
orderedReleases: function() {
let newlist = this.job_execs.sort(this.naturalCompare).reverse()
for ( var i = 0; i < newlist.length; i++) {
if (typeof newlist[i].version === "string") {
if (newlist[i].version.startsWith("iPad")) {
console.log(newlist[i].version)
newlist.splice(i,1);
i--;
}
}
}
return newlist;
},
},
methods: {
calculateDuration: function(time_start, time_end) {
this.theDuration = moment.duration(time_end.diff(time_start));
if (this.theDuration.seconds() == 0) {
this.cleanDuration = "N/A";
} else {
this.cleanDuration =
this.theDuration.hours() +
" hrs " +
this.theDuration.minutes() +
" min " +
this.theDuration.seconds() +
" sec";
}
return this.cleanDuration;
},
naturalCompare: function(a, b) {
var ax = [], bx = [];
a.version.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) });
b.version.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) });
while(ax.length && bx.length) {
var an = ax.shift();
var bn = bx.shift();
var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]);
if(nn) return nn;
}
return ax.length - bx.length;
}
},
created() {
this.jobExecEndpoint = process.env.VUE_APP_UATU_URL + "/api/v1/release/";
fetch(this.jobExecEndpoint)
.then(response => response.json())
.then(body => {
for (let i = 0; i < body.length; i++) {
this.cleanStartTime = moment(body[i].start_date);
this.job_execs.push({
version: body[i].version,
status: body[i].status.name,
start: this.cleanStartTime.format("LLL")
});
}
})
.catch(err => {
console.log("Error Fetching:", this.jobExecEndpoint, err);
return { failure: this.jobExecEndpoint, reason: err };
});
}
};
</script>
<style>
</style>
Add a v-if inside your Releases component on the div tag like so:
<div class="releases" v-if="job_execs"></div>
and change your data object like this:
data() {
return {
job_execs: null
};
},
The pattern I use:
loading: smth = null
loaded: smth = [...]
empty state: smth.length === 0
This way you don't need a separate loading property.
I've been trying to develop a carousel with Vue.js but I'm stuck with the transition effects. Following are my codes,
// Main component
<slider>
<slide v-for="(slide, index) in compOpts.blockImg" :key="index">
<img :src="slide" :alt="features ${index}`">
</slide>
</slider>
// Slider component
<transition-group class="slider__container" name="slideTr" tag="div" appear mode="out-in">
<slot></slot>
</transition-group>
import slide from './contentSliderSlide';
export default {
name: 'slider',
data: () => ({
slideCount: 0,
activeSlide: 0,
currentSlide: null,
lastSlide: null,
slideInterval: null
}),
mounted() {
this.init();
},
methods: {
getSlideCount() {
this.slideCount = (
this.$slots
&& this.$slots.default
&& this.$slots.default.filter(
slot => slot.tag
&& slot.tag.indexOf('slide') > -1
).length
) || 0;
},
init() {
this.getSlideCount();
this.$slots.default[this.activeSlide].elm.classList.add('visible');
this.playSlide();
},
gotoSlide(n, p) {
this.currentSlide = (n + this.slideCount) % this.slideCount;
if (p) {
this.lastSlide = ((n - 1) + this.slideCount) % this.slideCount;
this.$slots.default[this.lastSlide].elm.classList.remove('visible');
this.activeSlide += 1;
} else {
this.lastSlide = ((n + 1) + this.slideCount) % this.slideCount;
this.$slots.default[this.lastSlide].elm.classList.remove('visible');
this.activeSlide -= 1;
}
this.$slots.default[this.currentSlide].elm.classList.add('visible');
},
playSlide() {
this.slideInterval = setInterval(this.nextSlide, 2000);
},
nextSlide() {
this.gotoSlide(this.activeSlide + 1, true);
}
},
components: {
slide
}
};
// Slide component
<div class="slider__slide">
<slot></slot>
</div>
If there isn't any solution then at least please advise me how to implement css transition effect with before and after hook (using pure css method)