Errors with vee-validate custome rule - vee-validate

In #vue/cli 4.1.1 app I use v-money and vee-validate and I see that required rule does not work for
v-money , as it always has “0” value. So I make custom validation as it is written here
http://vee-validate.logaretm.com/v2/guide/custom-rules.html#using-the-custom-rule
Inserting this exam[ple in test page I got warnings in console :
WARNING Compiled with 2 warnings 7:45:56 AM
warning in ./src/views/Test.vue?vue&type=script&lang=js&
"export 'Validator' was not found in 'vee-validate'
warning in ./src/views/Test.vue?vue&type=script&lang=js&
"export 'Validator' was not found in 'vee-validate'
App running at:
- Local: http://localhost:8080/
- Network: unavailable
and in browser I see error :
vue-router.esm.js?8c4f:2113 TypeError: Cannot read property 'extend' of undefined
at eval (Test.vue?f246:87)
at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Test.vue?vue&type=script&lang=js& (4.js:11)
at __webpack_require__ (app.js:790)
at fn (app.js:151)
My test component :
<template>
<div class="frontend_item_container">
<ValidationObserver
ref="pageObserverForm"
v-slot="{handleSubmit}"
>
<b-form #submit.prevent="handleSubmit(onSubmit)">
<b-card-header>
<h3 class="row_content_left_aligned p-2" v-show="is_page_loaded">
<i :class="'info_link '+getHeaderIcon('page')"></i>{{ getHeaderTitle }}
</h3>
<div v-show="!is_page_loaded">
<h3>
<b-spinner variant="success" label="Page loading"></b-spinner> Page loading...
</h3>
</div>
</b-card-header>
<b-card-body v-show="is_page_loaded">
<b-row class="editor_row">
<b-col md="4">
<label for="editable_ad_price" class="pt-2 ">
Price<span class="required"> * </span>:
</label>
</b-col>
<b-col md="8">
price::{{ price}}
<ValidationProvider
name="editable_ad_price"
rules="required|truthy"
v-slot="{ errors }"
>
<money
v-model="price"
v-bind="moneyConfig"
name="editable_ad_price"
id="editable_ad_price"
class="form-control text-right"
placeholder="Enter price"
>
</money>
<p class="validation_error">{{ clearErrorMessage(errors[0]) }}</p>
</ValidationProvider>
</b-col>
</b-row>
</b-card-body>
<b-card-footer class="buttons_container" v-show="is_page_loaded">
<b-button size="md" #click.prevent="$router.push('/admin/pages')" class="m-3">
<i :class="'a_link '+getHeaderIcon('cancel')"></i>Cancel
</b-button>
<b-button type="submit" size="md" variant="success" class="m-3">
<i :class="'action_link '+getHeaderIcon('save')"></i>{{ submit_label }}
</b-button>
</b-card-footer>
</b-form>
</ValidationObserver>
</div>
</template>
<script>
import appMixin from '#/appMixin';
import Vue from 'vue'
import money from 'v-money'
Vue.use(money, {precision: 4})
import {settingsLocalizeMessages} from '#/app.settings.js'
import {ValidationObserver, ValidationProvider, extend} from 'vee-validate'
import * as rules from 'vee-validate/dist/rules';
Object.keys(rules).forEach(rule => {
extend(rule, rules[rule]);
});
import { Validator } from 'vee-validate';
Validator.extend('truthy', {
getMessage: field => 'The ' + field + ' value is not truthy.',
validate: value => !! value
});
let instance = new Validator({ trueField: 'truthy' });
instance.extend('falsy', (value) => ! value);
instance.attach({
name: 'falseField',
rules: 'falsy'
});
import {localize} from 'vee-validate';
localize({
en: settingsLocalizeMessages['en']
});
export default {
data() {
return {
apiUrl: process.env.VUE_APP_API_URL,
price: 12,
moneyConfig: {
decimal: ',',
thousands: '.',
prefix: '$',
suffix: '',
precision: 2,
masked: false
},
is_page_loaded: false,
}
}, // data() {
name: 'testPage',
mixins: [appMixin],
components: {
ValidationObserver, ValidationProvider
},
mounted() {
}, // mounted() {
created() {
}, // created() {
beforeDestroy() {
},
methods: {
}, // methods: {
computed: {
getHeaderTitle: function () {
return 'Test'
},
}, //computed: {
}
</script>
Why error and how to fix it ?
"bootstrap-vue": "^2.3.0",
"v-money": "^0.8.1",
"vee-validate": "^3.2.1",
"vue": "^2.6.11",
Thanks!

You are using the old documentation for vee-validate. In version 3 you have to do:
import { extend } from 'vee-validate';
Also check out the 3.x docs here: https://logaretm.github.io/vee-validate/guide/basics.html#adding-rules

Related

Laravel 8 Vue Package Could Not Find a Declaration Module

I'm trying to create a table view with laravel framework using jetstream inertia js vue package, and came across revogrid npm package, so i installed it using the vue 3 version.
Installation went fine, but when i imported the component, it gives me Could not find a declaration module for '#revolist/vue3-datagrid' and after npm run dev no changes happened.
my container.vue :
<template>
<app-layout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Customer
</h2>
</template>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
<v-grid
theme="compact"
:source="rows"
:columns="columns"
></v-grid>
</div>
</div>
</div>
</app-layout>
</template>
<script>
import AppLayout from '#/Layouts/AppLayout'
export default {
data: function () {
return {
columns: [{ prop: "name" }, { prop: "details" }],
rows: [{
name: "1",
details: "Item 1",
}]
}
},
components: {
AppLayout,
VGrid
},
methods: {
fetchCustomer: function () {
axios.get('/api/customers')
.then(response => this.rows = response.data)
.catch(error => console.log(error))
}
},
created: function () {
this.fetchCustomer()
}
}
</script>
error :
error message
result is empty page, while expected result is a sample table

[Vue warn]: Error in mounted hook: "Error: viewType "" is not available. Please make sure you've loaded all neccessary plugins

Im trying to use FullCalendar as a vue component in Laravel. I've loaded the plugins correctly as per the documentation but for whatever reason, they are not loading https://fullcalendar.io/docs/vue
Component:
template>
<div class="container">
<div class="row justify-contnet-center">
<div class="col-lg-8">
<form #submit.prevent>
<div class="form-group">
<label for="event_name">event Name</label>
<input
type="text"
id="event_name"
class="form-control"
v-model="newevent.event_name"
>
</div>
<div class="row">
<div class="cold-lg-8">
<div class="form-group">
<label for="date">Date</label>
<input
type="date"
id="date"
class="form-control"
v-model="newevent.date"
>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<div class="form-group">
<label for="time">Time</label>
<input
type="time"
id="time"
class="form-control"
v-model="newevent.time"
>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4" v-if="addingMode">
<button class="btn btn-custom" #click="addNewevent">Book event</button>
</div>
<template>
<div class="col-lg-6 mb-4">
<button class="btn btn-success" #click="updateevent">Update</button>
<button class="btn btn-danger" #click="deleteevent">Delete</button>
<button class="btn btn-warning" #click="addingMode = !addingMode">Cancel</button>
</div>
</template>
</form>
</div>
<div class="col-lg-8 full-calendar" id="calendar">
<FullCalendar #eventClick="showevent" defaultView:="dayGridMonth" :plugins="calendarPlugins" :events="events"/>
</div>
</div>
</div>
</template>
<script>
import { Calendar } from '#fullcalendar/core'
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction'
import axios from 'axios'
export default {
components:{
FullCalendar // make custom tag avaliable
},
data() {
return {
calendarPlugins: [ dayGridPlugin, interactionPlugin],
events: "",
newevent: {
event_name: "",
date: "",
time: ""
},
addingMode: true,
indexToUpdate: ""
};
},
created() {
this.getevents();
},
methods: {
addNewevent() {
axios.post('/api/event', {
...this.newevent
})
.then(data=> {
this.getevents(); //update list of getevents
this.resetForm();
})
.catch(err =>
// alert("Unable to add event")
console.log(err.response.data)
);
},
showevent(arg) {
console.logt(arg);
this.addingMode = false;
const {id, event, date, time} = this.events.find (
event => event.id === +arg.event.id
);
this.indexToUpdate = id;
this.newevent = {
event_name: event, // comeback to and see if inserts into db as event_name
date: date,
time: time
};
},
updateevent() {
axios.put('/app/event/' + this.indexToUpdate, {
...this.newevent
})
.then(resp => {
this.resetForm();
this.getevents();
this.addingMode = !this.addingMode;
})
.catch(err =>
// alert('Unable to update event!')
console.log(err.response.data)
);
},
deleteevent() {
axios.delete('/api/event/' + this.indexToUpdate)
.then(resp => {
this.resetForm();
this.getevents();
this.addingMode = !this.addingMode;
})
.catch(err =>
// alert('Unable to delete event')
console.log(err.response.data)
);
},
getevents(){
axios.get('/api/event')
.then(resp => (this.events = resp.data.data))
.catch(err => console.log(err.response.data));
},
resetForm() {
Object.keys(this.newevent).forEach(key=> {
return (this.newevent[key] = "");
});
}
},
watch: {
indexToUpdate() {
return this.indexToUpdate
}
}
};
Then also I have initialized the component with es6 as per this part of the doc https://fullcalendar.io/docs/initialize-es6
import { Calendar } from '#fullcalendar/core';
import dayGridPlugin from '#fullcalendar/daygrid';
import interactionPlugin from '#fullcalendar/interaction';
document.addEventListener('DOMContentLoaded', function() {
let calendarEl = document.getElementById('calendar');
let calendar = new Calendar(calendarEl, {
plugins: [ dayGridPlugin , interactionPlugin ]
});
calendar.render();
});
This is my app.js
Vue.component('calendar-component', require('./components/CalendarComponent.vue').default);
<FullCalendar #eventClick="showevent" defaultView:="dayGridMonth" :plugins="calendarPlugins" :events="events"/>
should become
<FullCalendar :options="calendarOptions" />
I saw the FullCalendar code in github and it doesn't support props defaultView and plugins. Instead it uses prop with name "options"
<script>
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction'
export default {
components: {
FullCalendar // make the <FullCalendar> tag available
},
data() {
return {
calendarOptions: {
plugins: [ dayGridPlugin, interactionPlugin ],
initialView: 'dayGridMonth'
}
}
}
}
</script>
<template>
<FullCalendar :options="calendarOptions" />
</template>
Please check the plugin documentation

Search functionality with rest api prevent DDOSing the server

The Problem
I have a search component and component which implements the search component. When I type something in the search bar after 1/2 second of not typing (debounce) the server should be hit and the results should be returned.
The solution i am trying to implement comes from this post on Stackoverflow
The code
This leads me to the following code.
I have search.vue
<template>
<label for="search">
<input
id="search"
class="w-full py-2 px-1 border-gray-900 border"
type="text"
name=":searchTitle"
v-model="searchFilter"
:placeholder="searchPlaceholder"
autocomplete="off"
v-on:keydown="filteredDataset"
/>
</label>
</template>
<script>
import {debounce} from 'lodash';
export default {
props: {
searchPlaceholder: {
type: String,
required: false,
default: ''
},
searchName: {
type: String,
required: false,
default: 'search'
}
},
data() {
return {
searchFilter: '',
}
},
methods: {
filteredDataset() {
console.log('event fired');
this.$emit('searchValue', this.searchFilter);
}
},
}
</script>
And product.vue
<template>
<div>
<div class="my-4">
<search
search-placeholder=""
search-name=""
v-on:searchValue="filterValue = $event"
v-model="productsFiltered"
>
</search>
<div class="flex w-full py-1 border px-2 my-2" v-for="product in productsFiltered"> (...)
</div>
</div>
</div>
</div>
</template>
<script>
import {debounce} from 'lodash';
export default {
data() {
return {
products: [],
filterValue: '',
filteredProducts: ''
}
},
computed: {
productsFiltered: {
get(){
console.log('getter called');
return this.filteredProducts;
},
set: _.debounce(function(){
console.log('setter called');
if (this.filterValue.length < 1) {
this.filteredProducts = [];
}
axios.get(`${apiUrl}search/` + this.filterValue)
.then(response => {
this.products = response.data.products;
const filtered = [];
const regOption = new RegExp(this.filterValue, 'ig');
for (const product of this.products) {
if (this.filterValue.length < 1 || product.productname.match(regOption)) {
filtered.push(product);
}
}
this.filteredProducts = filtered;
});
}, 500)
}
},
}
</script>
The result
The result is that the setter in the computed property in product.vue does not get called and no data is fetched from the server. Any ideas on how to solve this?
Your first code block imports debounce but does not use it. It also declares a prop, searchName, that isn't used. These aren't central issues, but clutter makes it harder to figure out what's going on.
Your second code block uses v-model but does not follow the required conventions for getting v-model to work with components:
the component must take a prop named value
the component must emit input events to signal changes to value
You have the component emit searchValue events, and handle them with a v-on that sets a data item. You seem to expect the v-model to call the setter, but as I noted, you haven't hooked it up to do so.
From what's here, you don't even really need to store the input value. You just want to emit it when it changes. Here's a demo:
const searchComponent = {
template: '#search-template',
props: {
searchPlaceholder: {
type: String,
required: false,
default: ''
}
},
methods: {
filteredDataset(searchFilter) {
console.log('event fired');
this.$emit('input', searchFilter);
}
}
};
new Vue({
el: '#app',
data() {
return {
products: [],
filterValue: '',
filteredProducts: ''
}
},
components: {
searchComponent
},
computed: {
productsFiltered: {
get() {
console.log('getter called');
return this.filteredProducts;
},
set: _.debounce(function() {
console.log('setter called');
if (this.filterValue.length < 1) {
this.filteredProducts = [];
}
setTimeout(() => {
console.log("This is the axios call");
this.filteredProducts = ['one','two','three'];
}, 200);
}, 500)
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<template id="search-template">
<label for="search">
<input
id="search"
class="w-full py-2 px-1 border-gray-900 border"
type="text"
name=":searchTitle"
:placeholder="searchPlaceholder"
autocomplete="off"
#input="filteredDataset"
/>
</label>
</template>
<div id="app">
<div class="my-4">
<search-component search-placeholder="enter something" v-model="productsFiltered">
</search-component>
<div class="flex w-full py-1 border px-2 my-2" v-for="product in productsFiltered"> (...)
</div>
</div>
</div>

Property or method "contact" is not defined on the instance but referenced during render Vuejs Laravel

I'm developing chat app on laravel using vue.js and i'm new to vue.js.
but i'm getting below mentioned error, please help me solve this
Error1 :
[Vue warn]: Property or method "contact" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property
Error2 :
[Vue warn]: Error in render: "TypeError: Cannot read property 'avatar' of undefined"
/ ChatApp.vue file/
<template>
<div class="chat-app">
<Conversation :contact="selectedContact" :messages="messages"/>
<ContactsList :contacts="contacts"/>
</div>
</template>
<script>
import Conversation from './Conversation.vue';
import ContactsList from './ContactsList.vue';
export default {
props: {
user: {
type: Object,
required: true
}
},
data(){
return {
selectedContact: null,
messages: [],
contacts: []
};
},
mounted(){
axios.get('/contacts')
.then((response) => {
this.contacts = response.data;
});
},
methods: {
startConversationWith(contact) {
axios.get(`/conversation/$(contact.id)`)
.then((response) => {
this.messages = response.data;
this.selectedContact = contact;
})
}
},
components: { ContactsList, Conversation }
};
</script>
/ ContactsList.vue file/
<template>
<div class="contacts-list">
<ul v-if="contacts.length > 0">
<li v-for:"(contact, index) In contacts" :key="contact.id"
#click="selectContact(index, contact)" :class="{ 'selected' : index ==
selected}">
<div class="avatar">
<img :src="contact.avatar" :alt="contact.name">
</div>
<div class="contact">
<p class="name">{{ contact.name }}</p>
<p class="email">{{ contact.email }}</p>
</div>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
contacts: {
type: Array,
default: []
}
},
data() {
return {
selected: 0
};
},
methods: {
selectContact(index, contact) {
this.selected = index;
this.$emit('selected', contact);
}
}
};
</script>
/ conversation.vue /
<template>
<div class="conversation">
<h1>{{ contact ? contact.name : 'Select a contact' }}</h1>
<MessagesFeed :contact="contact" :messages="messages" />
<MessageComposer #send="sendMessage" />
</div>
</template>
<script>
import MessagesFeed from './MessagesFeed.vue';
import MessageComposer from './MessageComposer.vue';
export default {
props: {
contact: {
type: Object,
default: null
},
messages: {
type: Array,
default: []
}
},
methods:{
sendMessage(text) {
console.log(text);
}
},
components: {MessagesFeed, MessageComposer}
};
</script>
#Akash you can use it this way :
data() {
return {
contactsNotEmpty:false
}
},
// ...
mounted() {
axios.get('/contacts')
.then((response) => {
this.contacts = response.data;
this.contactsNotEmpty = true;
});
}
<ul v-if="contactsNotEmpty">
...
</ul>
also you may check this vuejs article about what is happening : https://vuejs.org/2016/02/06/common-gotchas/#Why-isn%E2%80%99t-the-DOM-updating
I guess you can do it like that:
<ul v-if="contacts.length > 0">
<li v-for="contact in contacts" :key="contact.id">
<div class="avatar">
<img :src="contact.avatar" :alt="contact.name">
</div>
<div class="contact">
<p class="name">{{ contact.name }}</p>
<p class="email">{{ contact.email }}</p>
</div>
</li>
</ul>
The first error is throwing in your Conversation.vue, you were passing data to a child component, you have to make sure it is defined as a prop in that component
export default{
props: ['contact']
};
and if it is defined, your prop type is not expecting a null value. I would change it to string and on rendering in my ChatApp.vue, I would set selectedContact to string.Empty||''
For the second error, the avatar key is missing from your response object. You have to check if it is present first before accessing it. Kindly refer to El Alami Anas's answer above.

redux-form data is not passed to handleSubmit

I'm having trouble again with redux-form. I'm calling the handleSubmit function from the parent, and the windows.alert() is calledcorrectly, but the data is not passed to the function. What am I doing wrong?
import React, {Component, PropTypes} from 'react';
import {reduxForm} from 'redux-form';
import memberValidation from './memberValidation';
class DashboardAdding extends Component {
static propTypes = {
fields: PropTypes.object.isRequired,
handleSubmit: PropTypes.func.isRequired,
resetForm: PropTypes.func.isRequired
}
render() {
const {
fields: { pseudo, email},
handleSubmit,
resetForm
} = this.props;
return (
<div>
<form className="form-horizontal" onSubmit={handleSubmit.bind(this)}>
<div className={'form-group' + (pseudo.error && pseudo.touched ? ' has-error' : '')}>
<label className="col-sm-2">Pseudo</label>
<div className={'col-sm-8 '}>
<input type="text" className="form-control" id="pseudo" {...pseudo}/>
{pseudo.error && pseudo.touched && <div className="text-danger">{pseudo.error}</div>}
</div>
</div>
<div className={'form-group' + (email.error && email.touched ? ' has-error' : '')}>
<label className="col-sm-2">Email</label>
<div className={'col-sm-8 '}>
<input type="text" className="form-control" id="email" {...email}/>
{email.error && email.touched && <div className="text-danger">{email.error}</div>}
</div>
</div>
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button className="btn btn-success" onClick={handleSubmit}>
<i className="fa fa-paper-plane"/> Submit
</button>
<button className="btn btn-warning" onClick={resetForm} style={{marginLeft: 15}}>
<i className="fa fa-undo"/> Reset
</button>
</div>
</div>
</form>
</div>
);
}
}
export default reduxForm({
form: 'dashboardForm',
fields: ['pseudo', 'email'],
validate: memberValidation,
asyncBlurFields: ['email']
})(DashboardAdding);
...and the parent calling the handleSubmit:
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import Helmet from 'react-helmet';
import {bindActionCreators} from 'redux';
import {initialize} from 'redux-form';
import {isLoaded, loadMembers} from 'redux/modules/members/members';
import * as addActions from 'redux/modules/members/addSingleMember';
import {addMember} from 'redux/modules/members/addSingleMember';
import { DashboardList } from 'components';
import { DashboardHeader } from 'components';
import { DashboardAdding } from 'components';
import { asyncConnect } from 'redux-async-connect';
#asyncConnect([{
deferred: true,
promise: ({store: {dispatch, getState}}) => {
if (!isLoaded(getState())) {
return dispatch(loadMembers());
}
}
}])
class Dashboard extends Component {
static propTypes = {
members: PropTypes.array,
error: PropTypes.string,
loading: PropTypes.bool,
addMember: PropTypes.func,
initialize: PropTypes.func.isRequired
}
handleSubmit = (data, dispatch) => {
window.alert(data);
dispatch(addMember(JSON.stringify(data)));
this.props.initialize('dashboardForm', {});
}
handleInitialize = () => {
this.props.initialize('dashboardForm', {
pseudo: 'Pibo',
email: 'pibirino#gmail.com'
});
}
render() {
const {members} = this.props;
return (
<div className="container">
<h1>Dashboard</h1>
<Helmet title="Dashboard"/>
<DashboardHeader />
<div>
<DashboardList members={members}/>
<h3>Ici commence le form</h3>
<div style={{textAlign: 'center', margin: 15}}>
<button className="btn btn-primary" onClick={this.handleInitialize}>
<i className="fa fa-pencil"/> Initialize Form
</button>
</div>
</div>
<DashboardAdding onSubmit={this.handleSubmit}/>
</div>
);
}
}
function mapStateToProps(state) {
return {
members: state.members.data,
error: state.members.error,
loading: state.members.loading
};
}
function matchDispatchToProps(dispatch) {
return bindActionCreators({
addActions,
addMember,
initialize: initialize
}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(Dashboard);
The redux-documentation says:
"You are upgrading from a previous version of redux-form that required that {valid: true} be returned".
I suspect that the problem is that, but I really don't understand what that could mean!
My version -> "redux-form": "^3.0.0"
Thanks!
Find the solution where I didn't expect... The form gives the data in json format. JSON.stringify() messed it up.
I hope it can help somebody. Bye

Resources