Vuelidate date input field - vuejs2

I hope someone can clarify to me, how to properly use Vuelidate while validating Date object. I want to use the current date as a minimal date, so if a user inputs a date later, an error will be shown.
I have an example: https://jsfiddle.net/cheslavcc/fns8eh0f/1/
Vue.use(window.vuelidate.default)
const { required, minValue } = window.validators
new Vue({
el: "#app",
data: {
text: ''
},
validations: {
text: {
minValue: minValue(moment(new Date(), 'DD.MM.YYYY').format('DD.MM.YYYY')),
}
}
})
I'm using Moment.js as a date formatter, and minValue from the official Vuelidate documentation: https://monterail.github.io/vuelidate/#sub-builtin-validators
Any help appreciated, thanks a lot!

You can define custom validator:
Vue.use(window.vuelidate.default)
const { required, minValue } = window.validators
const currentDate = moment(new Date()).startOf('day')
const minDate = window.vuelidate.withParams({minDate: currentDate.format('DD.MM.YYYY')}, value => moment(value, 'DD.MM.YYYY', true).isSameOrAfter(currentDate))
new Vue({
el: "#app",
data: {
text: ''
},
validations: {
text: {
minDate
}
}
})
input {
border: 1px solid silver;
border-radius: 4px;
background: white;
padding: 5px 10px;
}
.error {
border-color: red;
background: #FDD;
}
.error:focus {
outline-color: #F99;
}
.valid {
border-color: #5A5;
background: #EFE;
}
.valid:focus {
outline-color: #8E8;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/validators.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/vuelidate.min.js"></script>
<div id="app">
<input type="text" v-model="text"
v-on:input="$v.text.$touch"
v-bind:class="{error: $v.text.$error, valid: $v.text.$dirty && !$v.text.$invalid}"
>
<pre>{{ $v }}</pre>
Text: {{ text }}
</div>

Related

Is it valid to provide to v-for unclosed tags for iteration in vue.js?

Assume, I have such vue-code:
<template>
<div v-for="(item, index) in items">
<div v-if="item.isComponent">
<component :is="item.value"/>
</div>
<template v-else>
{{item.value}}
</template>
</div>
</template>
<script>
export default {
data: function(){
return {
items: [
{
value: '<p>this is first part of paragraph
},
{
value: 'componentName',
isComponent: true,
},
{
value: 'this is the last part of paragraph</p>
},
],
//...
</script>
items - it's a parsed (which I haven't parsed yet) string for contenteditable tag editor.
If this is invalid, what workaround could be?
UPD.
items is a json which I will get from database which should be saved to database as user input to contenteditable div editor.
Html will get sanitize the Html part. So it is not a good idea. to do such things.
Html should be kept in template of vue.
But let say you wanted to show some data in tag. Instead of doing use computed prop and hide and show p tag. It also prevents the incomplete tag issue.
I am attaching jsfiddle solution[
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
items: [
{
value: '<p>this is first part of paragraph'
},
{
value: 'componentName',
isComponent: true,
},
{
value: 'this is the last part of paragraph</p>'
},
],
},
computed:{
dataVal(){
let val = "";
for(let i=0;i<this.items.length;i++){
val += this.items[i].value + " "
}
return val;
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app" v-html="dataVal">
</div>
]1

VueJS complex v-if

I want to show a button ONLY if two conditions are met. First I try v-if with only one condition at a time:
v-if="editMode"
v-if="$can('customersdelete')"
using only one condition at a time, the button is display, so i think both conditions are true. If i use:
v-if="editMode && $can('customersdelete')"
The button isn't display. $can is a mixin, to validate user has permission to do something.
<script>
export default {
methods: {
$can(permissionName) {
return Permissions.indexOf(permissionName) !== -1;
},
},
};
</script>
I don't know why this is not working...
Apparently, any subsequent v-if is ignored and only the first one is taken into account, as demonstrated by the following example:
Vue.config.devtools = false;
Vue.config.productionTip = false;
const Permissions = ['customersdelete'];
new Vue({
el: '#app',
data() {
return { editMode: true };
},
methods: {
$can(permissionName) {
return Permissions.indexOf(permissionName) !== -1;
},
},
})
code {
background-color: #f5f5f5;
border: 1px solid #eee;
padding: 2px 5px;
color: red;
border-radius: 3px;
display: inline-block;
}
div {
margin-top: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<label><input type="checkbox" v-model="editMode">editMode</label><br><br>
<div>$can('customersdelete') => <code v-text="$can('customersdelete')"></code></div>
<div>editMode => <code v-text="editMode"></code></div>
<hr />
<div v-if="$can('customersdelete')">
<code>v-if="$can('customersdelete')"</code>
</div>
<div v-if="editMode">
<code v-if="editMode">v-if="editMode"</code>
</div>
<div v-if="editMode && $can('customersdelete')">
<code>v-if="editMode && $can('customersdelete')"</code>
</div>
<div v-if="editMode"
v-if="$can('customersdelete')">
<code>v-if="editMode" v-if="$can('customersdelete')"</code>
</div>
<div v-if="$can('customersdelete')"
v-if="editMode">
<code>v-if="$can('customersdelete')" v-if="editMode"</code>
</div>
</div>
I would suggest use function and then use in v-if.
example
v-if="isButtonShow()"
and below is the method portion:
methods:{
isButtonShow(){
if(this.editMode){
if(this.$can('customersdelete'){
return true;
}
}
return false;
}
}

Pass a variable to a child component

I'm trying to pass a class name as a variable to a child component.
Context: I have two types of header ( 2 different bakgrounds ) used all across the site.
Page1:
<HeaderMain bg="bg" />
data() {
return {
pageTitle: 'patterson.travel',
bg: 'bg-white',
}
}
Page:2
<HeaderMain bg="bg" />
data() {
return {
pageTitle: 'patterson.travel',
bg: 'bg-header',
}
}
HeaderMain :
<header>
<nav class="main md:bg-transparent" :class="bg"></nav>
</header>
But the class never gets applied to the <nav>
I tried adding the variable to HeaderMain component like so (as a default):
data() {
return {
bg: 'bg-red', // default?
}
}
But That is the class it allways has...
So, any idea what I'm missing, here?
( I also tried :bg="bg" )
You have to define the bg property on your HeaderMain component:
// HeaderMain.vue
<script>
export default {
props: ['bg']
}
</script>
You will then be able to use it in your template just like you did:
<header>
<nav class="main md:bg-transparent" :class="bg"></nav>
</header>
In order to access it, you need to define props as an array inside your children component.
Look at the code below.
Vue.component('user-name', {
props: ['name'],
template: '<p>Hi {{ name }}</p>'
})
const LastName = {
template: '<span> Patel </span>'
}
const Header = {
props: ['bg'],
template: '<span :class="bg"> {{bg}} Header </span>'
}
new Vue({
el: "#app",
data: function() {
return {
headerBg: 'header-bg'
}
},
components: {
'last-name': LastName,
'header-view': Header
}
});
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
.header-bg {
background: red;
}
.header-bg {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<header-view :bg="headerBg"></header-view>
<user-name name="Varit"></user-name>
<last-name></last-name>
</div>

Can I execute a method when an input box gets to a certain length?

I have an input box that takes a string. Can I execute a method (in vue.js) when the length of the string gets to a certain number?
something like
<input v-if="inputBox.length == 6 THEN runme()"...>
You can use watch option, you'll be able to react to data changes :
new Vue({
el: '#root',
data: {
message: '',
inputLength : undefined
},
methods : {
doSomething(){
console.log('I did it !')
}
},
watch :{
message : function(val) {
if(val.length>=5){
this.inputLength = val.length
this.doSomething();
}
}
}
})
.container {
padding-top: 2em;
}
.intro {
font-size: 1.5em;
margin-bottom: 1.5em;
}
.input-value {
margin-top: 1em;
font-size: 1.25em;
}
.highlight {
color: #00d1b2;
font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container">
<h1 class="intro">Binding with Vue</h1>
<div id='root' class="box">
<label class="label">Enter text here</label>
<input class="input is-medium" type='text' id='input' v-model='message'>
<p class="input-value">The value of the input is: <span class="highlight">{{ inputLength }}</span></p>
</div>
</div>
In this example, if input length is >= 5 then it will change the inputLenght value in data and execute a method.
For more informations about this, go see :
https://v2.vuejs.org/v2/guide/computed.html#Watchers
You can use a watcher to trigger a method when the string exceeds the length:
new Vue({
data () {
return {
model: ''
}
},
watch: {
model: {
handler: function (value) {
if (value.length >= 6) {
this.trigger()
}
}
}
},
el: '#app',
methods: {
trigger () {
alert('hi there')
}
},
template: `<input v-model="model">`
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

Vue: Change class with the value of a variable in setInterval

I am learning Vue JS. I want to change class using setInterval. But can’t pass the changing value of Method to Computed Property. After two seconds class will change automatically with the changed value of "changeColor"
My Code:
HTML:
<div>
<button #click="startEffect">Start Effect</button>
<div id="effect" :class="myClass"></div>
</div>
CSS:
.highlight {
background-color: red;
width: 200px !important;
}
.shrink {
background-color: gray;
width: 50px !important;
}
Vue JS:
new Vue({
el: '#exercise',
data: {
changeColor: false
},
methods : {
startEffect: function() {
setInterval(function(){
this.changeColor = !this.changeColor;
//alert(this.changeColor);
}, 2000);
//alert(this.changeColor);
}
},
computed: {
myClass: function() {
return {
highlight: this.changeColor,
shrink: !this.changeColor
}
}
}
})
bind your function to the component...
setInterval(function(){
this.changeColor = !this.changeColor;
}.bind(this), 2000);
and then you can do ...
<div id="effect" :class="[changeColor?'highlight':'shrink']"></div>