Can you make vue2-datepicker disregard timezone and always think in UTC? - vuejs2

My time comes back from the server as 2019-12-06T16:00:00.000Z. vue2-datepicker keeps showing as 10am.
Can I make vue2-datepicker disregard timezones so that it displays 4pm and also returns UTC when selecting a time? Out of the box when I set 10am it sends 4pm. I need it to send the time that I chose in the UI.
I realize more information may be needed in order for you to help; if so, please comment and I will provide.

npm install moment --save
convert server time by moment and try this code:
<template>
<div class="container" style="direction: ltr; margin-top: 100px;">
<div class="row">
<div class="col-12 text-center">
<date-picker2 v-model="date"
type="datetime"
format="YYYY-MM-DD hh:mm:ss A"
valueType="format">
</date-picker2>
</div>
</div>
</div>
</template>
<script>
import DatePicker2 from 'vue2-datepicker';
import 'vue2-datepicker/index.css';
var moment = require('moment');
export default {
name: "test",
data() {
return {
server_date_time: '2019-12-06T16:00:00.000Z',
date: null
}
},
mounted() {
moment.locale('en');
this.date = moment(this.server_date_time, 'YYYY-MM-DDTHH:mm:ss').format('YYYY-MM-DD hh:mm:ss A')
},
watch: {
date() {
console.log('date= ' + this.date);
}
},
components: { DatePicker2 },
}
</script>
<style scoped>
</style>

Related

Nuxt.js date time format

I have this html:
<template>
<div>
<div class="card text-center">
<h2><strong>Title: </strong>{{story.title}}</h2>
<p><strong>Score: </strong>{{story.score}}</p>
<p><strong>Author: </strong>{{story.by}}</p>
<p><strong>Date: </strong>{{ formatDate(story.time) }}</p>
<!--<p><strong>Date: </strong>{{ dateFormat(new Date(story.time*1000),v) }}</p> -->
<NuxtLink :to="`/${story.id}`">
<p class="btn my-4">View details</p> </NuxtLink>
</div>
</div>
</template>
and this scripts:
<script setup>
const { story } = defineProps(['story'])
export default {
data () {
return {
time: 0,
}
},
methods: {
formatDate(time) {
date = new Date(time).format("YYYY/MM/DD")
return date
}
}
}
</script>
I am not getting this kinda date format: "YYYY/MM/DD".
Please help how can I do that in Nuxt.js?
AFAIK, there isn't a single function call to achieve that. I would suggest you re-writing your formatDate using Date.toLocaleString to have full control of your format.
In addition, do not use export default in your <script setup>. It's not a valid syntax.
<script setup>
// Your other setup
function formatDate(time) {
const date = new Date(time);
// Get year, month, and day part from the date
const year = date.toLocaleString("default", { year: "numeric" });
const month = date.toLocaleString("default", { month: "2-digit" });
const day = date.toLocaleString("default", { day: "2-digit" });
return `${year}/${month}/${day}`;
}
</script>
You could use dayjs (tested with Nuxt 2.15)
yarn add #nuxtjs/dayjs
export default {
// ...
modules: [
'#nuxtjs/dayjs'
],
<template>
<div>
{{ $dayjs(new Date()).format('YYYY/MM/DD') }}
</div>
</template>

if-emoji lookup table with Vue

I'm using the npm module if-emoji to detect whether a user can view emojis or not. There is a similar tool in Modernizr.
If the user can't view emojis, I'm displaying an image of the emoji instead. So my Vue HTML looks like this:
<h2 v-if="this.emojis">😄</h2>
<h2 v-if="!this.emojis"><img src="https://example.com/emoji.png">/h2>
Does this still download the image for users who can view emojis, therefore using bandwidth unecessarily?
And is there a more efficient way of doing this, so that I don't need to go and add v-if every time I use an emoji? Can there be some sort of lookup table, if there's an emoji and !this.emojis?
You can solve this also by creating your own vue.component
<emojiorimage usesmily="false" smily="😄" imgpath="https://i.stack.imgur.com/QdqVi.png"></emojiorimage>
that capsulates the decision if image or smily inside itself.
var app = new Vue({
el: "#app",
data: function(){
return {
extendedCost: 0,
}
},
components: { "emojiorimage" : {
template : `
<h2>
usesmily is {{usesmily}}<br/>
<div v-if="usesmily === 'true'">{{ smily }}</div>
<div v-else><img :scr="imgpath" width="50" height="50" :alt="imgpath" /></div>
</h2>`,
props: ["usesmily", "smily", "imgpath"],
}}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>Emoji or Image</h1>
<emojiorimage
usesmily="false"
smily="😄"
imgpath="https://i.stack.imgur.com/QdqVi.png"
></emojiorimage>
<emojiorimage
usesmily="true"
smily="😎"
imgpath="https://i.stack.imgur.com/QdqVi.png"
></emojiorimage>
</div>
You can then feed it the isemoji from your npm package that you query once and store somewhere.
For seperate vue files it would look kind of like this:
emojiorimage.vue
<template>
<h2>
<div v-if="usesmily === 'true'">{{ smily }}</div>
<div v-else><img :scr="imgpath" width="50" height="50"
:alt="imgpath" /></div>
</h2>
</template>
<script>
export default {
props: ["usesmily", "smily", "imgpath"],
};
</script>
App.vue
<template>
<div id="app">
<h1>Emoji or Image</h1>
<emojiorimage
usesmily="false"
smily="😄"
imgpath="https://i.stack.imgur.com/QdqVi.png"
/>
<emojiorimage
usesmily="true"
smily="😎"
imgpath="https://i.stack.imgur.com/QdqVi.png"
/>
</div>
</template>
<script>
import emojiorimage from "./components/emojiorimage.vue";
export default {
components: {
emojiorimage,
},
};
</script>
index.html
<div id="app"></div>
index.js
import Vue from "vue";
import App from "./App";
Vue.config.productionTip = false;
new Vue({
el: "#app",
template: "<App/>",
components: { App }
});
to get:
Learning resources:
https://v2.vuejs.org/v2/guide/components.html
https://v2.vuejs.org/v2/guide/single-file-components.html
This should work as well:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<h2 v-if="true">😄</h2>
<h2 v-else><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/1200px-SNice.svg.png" width=15 height=15></h2>
<h2 v-if="false">😄</h2>
<h2 v-else><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/1200px-SNice.svg.png" width=15 height=15></h2>
The v-if part only is part of the sourcecode if the statement is true - else the else statement is in instead. If the img tag is not part of the loaded source the image wont be loaded.
<h2 v-if="emojis">😄</h2>
<h2 v-else><img src="https://example.com/emoji.png"></h2>
Is probably the only way to improve your code as #Patrick Artner pointed out.
You do not need this. in the template
To the question if the image is loaded if it is not shown the simple answer is no. Vue only renders v-ifs when they are needed and does not render it - the image is loaded only if !emojis.
Thanks to #PatrickArtner who posted the idea of using a Vue component to render the emoji / image. Here is my final solution, which resizes the emoji / image to fit the surrounding text — it uses fitty to resize the emojis, and sets the images to height:1em;.
Emoji.vue
<template>
<div class="emojiContainer">
<span id="fittyEmoji" v-if="emojis">{{ insert }}</span>
<img v-if="!emojis" :src="insert" class="emojiImage">
</div>
</template>
<style scoped>
.emojiContainer {
display: inline;
}
.emojiImage {
height:1em;
}
</style>
<script src="fitty.min.js"></script>
<script>
import fitty from 'fitty';
import ifEmoji from 'if-emoji'
export default {
name: 'Emoji',
props: ['name'],
data: function() {
return {
insert: "",
emojis: false,
}
},
methods: {
insertEmoji(){
var names = ['frog', 'fire']
var emojis = ['🐸','🔥']
var urls = ['https://example.com/frog.png',
'https://example.com/fire.png']
if (this.emojis) {
this.insert = emojis[names.indexOf(this.name)];
} else {
this.insert = urls[names.indexOf(this.name)];
}
fitty('#fittyEmoji')
}
},
beforeMount() {
if (ifEmoji('🐸')) {
this.emojis = true;
} else {
this.emojis = false;
}
this.insertEmoji();
}
}
</script>
Then in your parent components you can just insert like this:
<template>
<div id="app">
<h1><Emoji name='frog'/> Frog Facts</h1>
<p>Lorem ipsum <Emoji name='fire'/><p>
</div>
</template>
<script>
import Emoji from '#/components/Emoji.vue'
export default {
components: {
Emoji,
},
};
</script>

How to return date format from Bootstrap-vue's b-form-timepicker component from HH:mm:ss to HH:mm

Bootstrap-vue b-form-timepicker returns the value as with the format HH:mm:ss. I need its return value as HH:m', but I cannot find any way to change it.
Is there any way to change the return value format into HH:mm? If there is, please help.
You can remove the seconds by removing the property show-seconds as described in the component table properties. Then we'll format the date using vanilla JavaScript inside a Vue's watcher like so:
<template>
<div>
<label for="example-input">Choose a time</label>
<b-input-group class="mb-3">
<b-form-input
id="example-input"
v-model="value"
type="text"
placeholder="HH:mm"
></b-form-input>
<b-input-group-append>
<b-form-timepicker
v-model="value"
button-only
right
locale="en"
aria-controls="example-input"
></b-form-timepicker>
</b-input-group-append>
</b-input-group>
<p>Value: '{{ value }}'</p>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
value: "",
};
},
watch: {
value() {
this.value = this.value.split(':').slice(0,2).join(':');
},
},
};
</script>
You can check this working code playground example.

v-for delay dom patching when data update

I'm noticing that the v-for I'm using to render some images inside a component, when data are updated using the event bus,I will have a little delay in DOM content replacing. Is there a way to solve this little problem?
NB: I can't replicate the data passed because it's a 50 elements list of images urls and are provided by an external api service.
<template>
<div class="row m-0 pl-5 pr-5">
<div class="col-4 col-img hide p-0" v-for="(img, idx) in feed" :key="idx" v-observe-visibility="visibilityChanged">
<img class="img-fluid w-100 h-100 ig-image" :src="img.url">
<div class="card-img-overlay text-center">
<p class="text-white">{{ img.likes }} <i class="fas fa-heart"></i> {{ img.comments }} <i class="fas fa-comment"></i></p>
</div>
<a class="stretched-link" href="#image-modal" data-toggle="modal" v-on:click.prevent="zoomImage(img.url)"></a>
</div>
</div>
</template>
<script>
import { EventBus } from '#/standalone/event-bus'
export default {
name: 'UserMedia',
data() {
return {
feed: null,
imgUrl: null
}
},
mounted() {
EventBus.$on('profile-media', (media) => {
this.$set(this, 'feed', media)
})
},
methods: {
zoomImage(url) {
this.$set(this, 'imgUrl', url)
},
visibilityChanged(isVisible, el) {
if(isVisible){
el.target.classList.remove('hide')
el.target.classList.add('show')
}
}
}
}
</script>
<style scoped>
.col-img {
height: 420px;
}
</style>
Since if you change the data 'feed', it will take time to load the images but inorder to load small size images prior to heavy size for good user experience you can use some very good npm packages:
npm i vue-lazyload (I have used it and recommend this one)
npm i v-lazy-image (I haven't used yet but you can explore this as well)

Momentjs: How can I get correct time from utc date using mixin in Vue?

I'm not sure what I'm doing wrong here. Can anyone point out my mistake?
dateMixin.js
`
import moment from 'moment'
export const dateMixin = {
methods: {
convertDate (date, format) {
return moment(date, 'YYYY-MM-DD').format(format)
}
}
}
`
component.vue
here date = 2019-06-11T15:28:07.226938-07:00
`
<template>
<div>
{{ convertDate(date, 'MM/DD/YYYY hh:mm A') }}
</div>
</template>
<script>
import { dateMixin } from '../mixins/dateMixin.js'
export default {
mixins: [dateMixin]
}
</script>
`
Current output: 06/11/2019 12:00 AM
Expected output: 06/11/2019 03:28 PM
Thanks!
You hard-coded the parsing format in your mixin ('YYYY-MM-DD'), on this line:
return moment(date, 'YYYY-MM-DD').format(format)
Which reads the first part of your date string (2019-06-11T15:28:07.226938-07:00) as YYYY-MM-DD and disregards the rest. If you remove the parsing format string and allow moment to read the entire date, i.e:
return moment(date).format(format)
...it will output correctly. See it working:
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: '#hook',
template: '#appTemplate',
data: () => ({
date: '2019-06-11T15:28:07.226938-07:00'
}),
computed: {
getTimezone() {
return moment.tz.guess();
}
},
methods: {
convertDate(date, format) {
return moment(this.date).format(format)
},
convertToUtc(date, format) {
return moment(this.date).utc().format(format)
}
}
})
dl { font-family: monospace; }
dd { margin-bottom: 1rem; }
dt { font-weight: bold; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.25/moment-timezone-with-data.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/template" id="appTemplate">
<div id="app">
<dl>
<dt v-text="getTimezone"></dt>
<dd v-text="convertDate(date, 'MM/DD/YYYY hh:mm A')"></dd>
<dt v-text="`UTC`"></dt>
<dd v-text="convertToUtc(date, 'MM/DD/YYYY hh:mm A')"></dd>
</dl>
</div>
</script>
<div id="hook"></div>
Otherwise it will read only the date, and default the time to 00:00:00.000000 (which is why you're seeing 12:00 AM).