How to emit momentjs dates in correct format - vue.js

I am trying to format my data to send it to parent component but it seem like it is not reactive
if(this.selectedDate !== '' && this.selectedMonth !== '' && this.selectedDate !== '' ){
this.$emit("emit-data", this.selectedYr+"-"+moment().set(this.selectedDate) .format("DD")+"- "+moment().set(this.selectedMonth).format("MM"))
}
It won't send the selected drop-down but default ones which were pre-selected on page load. But If I take off moment() format from the data being sent, it sent correct values but I still need that format the data be in e.g YYYY-DD-MM
Is there any way to do this is computed using setters and getters before emitting? I am not sure how but If there is a way?

Yes, you can absolutely use a reactive computed getter for this. Here is an example:
<div id="app">
<parent-component />
</div>
const parentComponent = Vue.component('parent-component', {
data () {
return {
formattedDate: null
}
},
template: `
<div>
<p>You have selected: {{ formattedDate || "nothing yet" }}.</p>
<child-component
#emit-data="(payload) => formattedDate = payload"
/>
</div>
`
})
const childComponent = Vue.component('child-component', {
data () {
return {
selectedDate: null,
selectedMonth: null,
selectedYear: null
}
},
computed: {
formattedDate () {
if (![this.selectedDate, this.selectedMonth, this.selectedYear].every((el) => el)) return null
return moment({
day: this.selectedDate,
// Months in Moment.js are 0-indexed!
month: this.selectedMonth - 1,
year: this.selectedYear
}).format("YYYY-DD-MM")
}
},
watch: {
formattedDate (newVal) {
this.$emit("emit-data", newVal)
}
},
template: `
<div>
<input v-model="selectedDate" type="number" placeholder="Day" min="1" max="31" step="1">
<input v-model="selectedMonth" type="number" placeholder="Month" min="1" max="12" step="1">
<input v-model="selectedYear" type="number" placeholder="Year" min="1900" max="2100" step="1">
</div>
`
})
new Vue({
el: "#app"
})
You can run the above interactively on https://jsfiddle.net/46vuLcy0/.

Try
this.$emit('emit-data', moment(new Date(this.selectedMonth + "-" + this.selectedDate + "-" + this.selectedYr)).format(YYYY-DD-MM))
You can also see these examples
UPDATE
In the above code, your data is processed in to moment date. The result of this can be formatted in to your desired format.
Example
If you want the date to be 15-JUL-2020, you can have
moment(/* your date */).format('DD-MMM-YYYY')
Your can be directly provided to moment like
this.$emit("emit-data", moment(this.selectedYr + "-" + this.selectedDate + "-" + this.selectedMonth).format("YYYY-DD-MM"))
The code will result something like 2020-15-07 based on the format.

Related

limiting date with quasar v1

I am using quasar date component with limiting dates.
The documentation says to use options prop to be supplied with an array or function.
<template>
<div class="q-pa-md">
<div class="q-gutter-md">
<q-date
v-model="date"
:options="options"
/>
<q-date
v-model="date"
:options="optionsFn"
/>
<q-date
v-model="date"
:options="optionsFn2"
/>
</div>
</div>
</template>
<script>
export default {
data () {
return {
date: '2019/02/01',
options: [ '2019/02/01', '2019/02/05', '2019/02/06', '2019/02/09', '2019/02/23' ]
}
},
methods: {
optionsFn (date) {
return date >= '2019/02/03' && date <= '2019/02/15'
},
optionsFn2 (date) {
const parts = date.split('/')
return parts[2] % 2 === 0
}
}
}
</script>
The problem is that I am not able to pass any other argument in the optionsFn function.
since options takes in a function call but you are passing options= the return result of that function is not allowed you can fix it to :options="date => optionsFn(date, 'test ')" and it will work as you want

Get name model in vue js with help id input or name

Can i get model name if i now id input?
For examle
<input v-model="data.name" id="name_db">
I have in db value for data.name
Before vue i did this:
valuesFromDb.forEach(data=>{
if(data.fromdb==name_db)
$("#name_db").val(data.fromdb)
}
...
But it can't work with vueJS
I know i can do this:
data.name = data.fromdb
But i have many data in db and before vue i put data with help forloop.
Model and id have different names ​​and it will take a long time to manually iterate through all the data
Now i want get model name and put value to it
Somethinks like this:
var modelName = $("#name_db").getModelNameVue();
modelName=data.fromdb
If i do this, in input value change but in data dont
data(){
return{
mainPdf:{
left: 5,
bottom:5,
top:5,
right:5
}
}
}
<input v-model="mainPdf.left" id="left_margin">
<input v-model="mainPdf.bottom" id="bot_margin">
<input v-model="mainPdf.isMargin" id="right_margin">
<input v-model="mainPdf.isMargin" id="up_margin">
getFromdb(){
api.getFromdb(e=>{ // string=e
var string = "left_margin=0&bot_margin=1&right_margin=2&up_margin=3"
var rPlus = /\+/g;
$.each( string.split( "&" ), function( index, field ) {
$.each( string.split( "&" ), function( index, field ) {
var current = field.split( "=" );
if( current[ 1 ] && current[ 0 ]) {
var name = decodeURIComponent(current[0].replace(rPlus, "%20"));
var value = decodeURIComponent(current[1].replace(rPlus, "%20"));
$("#"+ name).val(value);
}
});
})
})
I can't dynamic-binding because i can't change name of properties in mainPdf, because i have entity with same fields(left,bottom,top,right) in my backend
==========i found solution
i used dispatchEvent
$("#" + NAME).prop("checked", true);
$("#"+ NAME")[0].dispatchEvent(new Event('change')); //or input
Using Vue.js and dynamic programming techniques, it's a piece of cake.
Vue.component('dynamic-binding', {
template: `
<div style="display: flex;">
<input
v-for="field in Object.keys(mainPdf)" :key="field"
v-model="mainPdf[field]"
>
</div>
`,
data() {
return {
mainPdf: {},
};
},
methods: {
fromDb(val = 'left_margin=0&bot_margin=1&right_margin=2&up_margin=3') {
const db = new URLSearchParams(val);
this.mainPdf = Object.fromEntries(db);
},
},
mounted() {
this.fromDb();
},
});
new Vue({ el: '#app' });
<div id="app">
<dynamic-binding></dynamic-binding>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

VueJS set date value as Date instead of String

I need to change type of datepicker value and it should return value as type Date instead of String https://prnt.sc/r6vr3g. But i don't know how can i make it.
Can anyone pls help me?
Here is code:
<template>
<q-input
#focusin="onFocusIn"
:value="value"
#input="e => $emit('input', e.toString())"
#click="alert = true"
>
<q-dialog v-model="alert">
<q-date
:value="value" #input="onInput"
:mask="mask"
/>
</q-dialog>
<script>
import _ from 'lodash'
export default {
props: {
..props
},
data () {
return {
alert: false,
sValue: ''
}
},
..computed
methods: {
onInput (e) {
let dateObj = new Date(e)
this.$emit('input', dateObj)
this.alert = false
},
onFocusIn (e) {
e.target.blur()
}
}
}
</script>
<style type="text/css">
</style>
<div class="col">
<s-datetime-picker v-model="data.dateStart" label="Date Start" required />
{{ data.dateStart }}
</div>
Here is code for datepicker component and after that there si example of using this component.
I've edited code, because i changed component. Now i have another error, in input field it shows message 'Invalid Date' and in console i got this error "failed for prop "value". Expected String with value "Invalid Date", got Date"
Format your emitting object before emit
<template>
<q-datetime-picker
..more properties
:value="value"
#input="formatDate(e)"
/>
</template>
<script>
import _ from 'lodash'
export default {
props: {
...all properties
},
computed: {
sLabel () {
if (!this.required || _.isUndefined(this.label)) return this.label
return this.label + ' *'
},
sRules () {
if (!this.required) return this.rules
let rule = val => { if (val.length === 0) return 'This field is Required' }
if (_.isUndefined(this.rules)) return [ rule ]
return (_.cloneDeep(this.rules)).push(rule)
}
},
formatDate(val){
let dateObj = new Date(val);
this.$emit('input', dateObj);
}
}
</script>
<style type="text/css">
</style>
<div class="col">
<s-datetime-picker v-model="data.dateStart" label="Date Start" required />
{{ data.dateStart }}
</div>
Format your date according to your need in formatDate function.
Hope this helps you,
Just pass the value you are getting as string to new Date it will return a date object.
var dt = "2020-02-13T00:00"; // <-- this is the value you get from date picker
var dtObj = new Date(dt); // <-- this one is date type
Full Vue Code
<template>
<div id="app">
<input type="date" v-model="dateFromField">
<button :click="showDate()">Submit</button>
</div>
</template>
<script>
export default {
name: "App",
data: function() {
return {
dateFromField: Date
};
},
methods: {
showDate() {
console.log(this.dateFromField);
console.log(typeof this.dateFromField);
let newDate = new Date(this.dateFromField);
console.log("conversion");
console.log(newDate);
console.log(typeof newDate);
}
}
};
</script>

Vee-Validate custom date validation

I was wondering if there is anyway you can write a custom date validation using vee-validate plugin where the end date cannot be less than the start date? I have looked high and low, and there is nowhere I can find a definite answer to this.
If there is no way to implement this, then I can make do without it, however, right now what I have implemented in my template for my start date is:
<input type="text" id="startDate" name="startDate" class="form-control" v-model="startDate" v-validate="'required|date_format:DD-MM-YYYY'" :class="{'input': true, 'is-danger': errors.has('startDate') }">
<label class="mb-0" for="startDate">Start Date</label>
<span v-show="errors.has('startdate')" class="text-danger"><center>{{ errors.first('startdate') }}</center></span>
My script looks like this:
export default {
name: 'App',
data: () => ({
task: '',
startDate: '',
startTime: '',
endDate: '',
endTime: '',
description: 'test'
}),
methods: {
validateBeforeSubmit() {
this.$validator.validateAll().then((result) => {
if (result) {
// eslint-disable-next-line
alert('Form Submitted!');
return;
}
alert('Correct them errors!');
});
}
}
};
But there is no validation that is showing up. I think I am missing something in my script but I am not sure how to implement the date into there. Any help would be greatly appreciated.
First, it's maybe some typo error but in your template you use startDate and startdate lowercased.
Then, to answer your question, it's possible to define a custom validator with a date comparison with vee-validate.
As your chosen date format "DD-MM-YYYY" is not a valid javascript Date format, the string dates need to be rewritten into a valid format to make it work.
Vue.use(VeeValidate)
new Vue({
el: "#app",
data() {
return {
startDate: '',
endDate: '',
}
},
created() {
let self = this
this.$validator.extend('earlier', {
getMessage(field, val) {
return 'must be earlier than startDate'
},
validate(value, field) {
let startParts = self.startDate.split('-')
let endParts = value.split('-')
let start = new Date(startParts[2], startParts[1] -1, startParts[0]) // month is 0-based
let end = new Date(endParts[2], endParts[1] -1, endParts[0])
return end > start
}
})
},
methods: {
validateBeforeSubmit() {
this.$validator.validateAll().then((result) => {
if (result) {
alert('Form Submitted!');
return;
}
alert('Correct them errors!');
});
}
}
})
.is-danger, .text-danger {
color: red;
}
<script src="https://unpkg.com/vee-validate#2.0.0-rc.19/dist/vee-validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<div>
<input type="text" name="startDate" v-model="startDate"v-validate="'required|date_format:DD-MM-YYYY'" :class="{'input': true, 'is-danger': errors.has('startDate') }">
<label class="mb-0" for="startDate">Start Date</label>
<span v-show="errors.has('startDate')" class="text-danger">{{ errors.first('startDate') }}</span>
</div>
<div>
<input type="text" name="endDate" v-model="endDate" v-validate="'required|date_format:DD-MM-YYYY|earlier'" :class="{'input': true, 'is-danger': errors.has('endDate') }">
<label class="mb-0" for="endDate">End Date</label>
<span v-show="errors.has('endDate')" class="text-danger">{{ errors.first('endDate') }}</span>
</div>
<button #click="validateBeforeSubmit">Save</button>
</div>
Note: i put the custom validator inside the created hook for the example but you can put it inside any file you want in your projet. Just import it correctly as the documentation recommends.

dynamic variable combining a double value + filter

I have the following case:
<bl-card :subtitle="card.beforeChanged + ' ' + (card.changed | formatDate)" />
The subtitle needs to be set by combining two strings. card.beforeChanged contains "last changed to:" string, the card.changed variable contains a datetimestring. Via de formatDate() the datetimestring gets formatted to a readable date.
subtitle now returns: "last changed to: 2069882880".
The question: is it possible to combine two strings where one of them get's formatted via the filter property in one go?
Got it working through a method. Computed properties weren't an option since the datestring comes from within a for loop in the template.
Method:
formatDate: (date, format) => {
if (!date) return ''
if (!format) format = 'DD.MM.YYYY'
return moment(date).format(format)
}
Implementation:
<bl-column v-for="(card, index) in cards" :key="card.id">
<bl-card :index="index" type="section" action="drawer" :title="card.titleShort" :subtitle="(card.beforeChanged || '') + ' ' + formatDate(card.changed)" />
</bl-column>
You should use a computer property for that.
Vue.filter('formatDate', function (value) {
return moment(value).fromNow()
})
Vue.component('todo', {
computed: {
formatedText: function () {
return `${this.text} - ${Vue.filter('formatDate')(this.date)}`
}
},
props: ['text', 'date'],
template: '<li>{{ formatedText }}</li>'
});
var demo = new Vue({
el: '#demo',
data: {
todos: [
{text:'testing', date: new Date()},
{text:'old text', date: moment().subtract(7, 'days')}
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<div id="demo" v-cloak>
<p v-if="!todos.length">No todos at this moment.</p>
<ul v-else>
<todo v-for="t in todos" :text=t.text :date=t.date></todo>
</ul>
</div>