Vue vuelidate $v is not defined - vue.js

I am new to vue js my main.js file looks like this
import { createApp } from 'vue'
import App from './App.vue'
import router from './routes.js'
import Vuelidate from 'vuelidate'
createApp(App).use(Vuelidate)
createApp(App).use(router).mount('#app')
and my form components looks like this
<template>
<form methos="post" v-on:submit.prevent="submit">
<input type="text" v-model.trim="$v.indate.$model" :class="{'is-invalid':
validationStatus($v.indate)}" class="form-control mt-2 mb-2" placeholder="DD/MM/YYYY">
<div v-if="!$v.indate.required" class="invalid-feedback">Inward date is required.</div>
</form>
</template>
<script>
import {required} from 'vuelidate/lib/validators'
export default {
name: 'FormInward',
validations: {
indate: {required}
},
data: function(){
return {
indate: ''
}
},
methods: {
validationStatus: function(validation){
return typeof validation != "undefined" ? validation.$error : false;
},
submit: function() {
this.$v.$touch();
if (this.$v.$pendding || this.$v.$error) return;
console.log(this.$v);
}
}
}
</script>
but i cant use the vuelidate it shows error like "Property "$v" was accessed during render but is not defined on instance."
when i check with "console.log(this.$v)" - it shows "undefined"

Related

Use VeeValidate v4 common validators with cutomize error message

I am trying to use the common validators provided by #vee-validate/rules, it works well but I can't find the way to customize the error message.
Now my error message is : "CompanyName is not valid. " But I want to change the field name from "CompanyName" to "Company name" and change "is not valid" to something related to the rule like "is required".
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import i18n from './i18n'
createApp(App).use(router).use(i18n).mount('#app')
import { defineRule } from 'vee-validate';
import AllRules from '#vee-validate/rules';
Object.keys(AllRules).forEach(rule => {
defineRule(rule, AllRules[rule]);
});
vue file
<template>
<Form #submit="onSubmit" :validation-schema="schema" v-slot="{ errors }">
<div class="form-group">
<span class="lblSectionField">Company Name <span class="lblMandatory">*</span></span>
<Field name="CompanyName" class="form-control"/>
<span class="errorMsg">{{ errors.CompanyName }}</span>
</div>
<Form>
</template>
<script setup>
import { Form, Field } from 'vee-validate';
const schema = {
CompanyName: 'required',
};
</script>
I found the solution
<script setup>
import { localize } from '#vee-validate/i18n';
import { Form, Field, configure } from 'vee-validate';
localize('en', {
fields: {
CompanyName: {
required: 'Company name is required',
},
},
});
const schema = {
CompanyName: 'required',
};
</script>

Watch doesn't get fire/trigger when global property change

I’m very new to Vue and I begin with Vue 3. I was trying to migrate a template from Vue 2 to Vue 3 so I can start with my project.
I have this plugin file.
Sidebar\Index.ts
import SidebarPlugComp from './SidebarPlugComp.vue'
import SidebarLinkPlugComp from './SidebarLinkPlugComp.vue'
// tiny internal plugin store
const SidebarStore = {
showSidebar: false,
sidebarLinks: [],
displaySidebar (value: boolean) {
this.showSidebar = value
}
}
const SidebarPlugin = {
install (app: any) {
app.config.globalProperties.$sidebar = SidebarStore
app.component('side-bar-plug-comp', SidebarPlugComp)
app.component('sidebar-link-plug-comp', SidebarLinkPlugComp)
}
}
export default SidebarPlugin
Also I have a BaseTopNavLay layout file so I can toggle the sidebar with handleSidebarToggle onclick button method
<template>
\\...
<div class="navbar-toggle d-inline" :class="{toggled: $sidebar.showSidebar}">
<button type="button"
class="navbar-toggler"
aria-label="Navbar toggle button"
#click.prevent="handleSidebarToggle">
<span class="navbar-toggler-bar bar1"></span>
<span class="navbar-toggler-bar bar2"></span>
<span class="navbar-toggler-bar bar3"></span>
</button>
\\ ...
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { ModalComp } from '../components'
export default defineComponent({
name: 'BaseTopNavLay',
components: {
ModalComp
},
// ...
methods: {
handleSidebarToggle (): void {
this.$sidebar.displaySidebar(!this.$sidebar.showSidebar)
},
handleHideSideBar (): void {
this.$sidebar.displaySidebar(false)
},
}
})
</script>
And here is the watch in the App.vue file
<template>
<component :is="this.$route.meta.layout || 'div'">
<router-view />
</component>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'Application',
methods: {
toggleNavOpen () {
console.log('here')
let root = document.getElementsByTagName('html')[0]
root.classList.toggle('nav-open')
}
},
/*watch: {
'$sidebar.showSidebar': function(newVal, oldVal) {
console.log(newVal, oldVal)
}
}*/
mounted () {
//#ts-ignore
this.$watch('$sidebar.showSidebar', this.toggleNavOpen)
}
})
</script>
Wherever I test the var this.$sidebar.showSidebar I can access to its value properly. Also, the onclick method is changing the SidebarStore object in Sidebar\Index.ts plugin file.
Can anyone give me a hint what am I missing here? Why the watch doesn't get fired. Thanks in advance.
The problem is that you have not made your $sidebar reactive, and a watch needs to use a reactive variable.
You can keep the store where you have it, but I'd put it into a separate file (store.js) and import where needed, no need to put it on app.config.globalProperties.$sidebar (but that might be a personal preference
// store.js
// using reactive (all values)
export const SidebarStore = Vue.reactive({
showSidebar: false,
sidebarLinks: [],
})
// or using ref (one for each)
// export const showSidebar = Vue.ref(false);
export const displaySidebar = (value: boolean) => {
SidebarStore.showSidebar.value = value;
}
this will make SidebarStore and displaySidebar available anywhere in your code
use like this
<template>
\\...
<div class="navbar-toggle d-inline" :class="{toggled: $sidebar.showSidebar}">
<button type="button"
class="navbar-toggler"
aria-label="Navbar toggle button"
#click.prevent="handleSidebarToggle">
<span class="navbar-toggler-bar bar1"></span>
<span class="navbar-toggler-bar bar2"></span>
<span class="navbar-toggler-bar bar3"></span>
</button>
\\ ...
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { ModalComp } from '../components'
import { SidebarStore, displaySidebar } from '../store'
export default defineComponent({
name: 'BaseTopNavLay',
components: {
ModalComp
},
// ...
methods: {
handleSidebarToggle (): void {
displaySidebar(!SidebarStore.showSidebar)
},
handleHideSideBar (): void {
displaySidebar(false)
},
}
})
</script>

Vue components not loading

I was given this problematic codebase, where the Vue components aren't loading in.
Vue is mounting, but without any components.
This is a Laravel 5.7 app, using blade templates with some Vue added in.
This is the initial code:
import 'babel-polyfill'
import loadClientScripts from './load-client-scripts'
import 'bootstrap-material-design/js/'
// Vue & axios
import Vue from 'vue'
import { axios } from '../axios-config'
import BootstrapVue from 'bootstrap-vue/dist/bootstrap-vue.esm'
import { createLocales } from '../vue-i18n-config'
import Noty from 'noty'
//Components
import signInForm from './components/SignInForm'
import signUpForm from './components/SignUpForm'
import forgotPassForm from './components/ForgotPassForm'
// import RegisterToAgency from './components/RegisterToAgency'
import SendEmailForm from './components/SendEmailForm'
import AgencyServiceCategories from './components/AgencyServiceCategories'
import DropdownWithCheckboxes from './components/DropdownWithCheckboxes'
import LasiCoalitionAgencies from './components/LasiCoalitionAgencies'
import ServiceProviders from "./components/ServiceProviders";
import ServiceProvider from "./components/ServiceProvider";
import vSelect from "vue-select";
window.axios = axios
Vue.component('v-select', vSelect)
// Bootstrap Vue
Vue.use(BootstrapVue)
export function createApp() {
const i18n = createLocales(window.locale)
// Components
Vue.component('sign-in-form', signInForm)
Vue.component('sign-up-form', signUpForm)
Vue.component('forgot-pass-form', forgotPassForm)
// Vue.component('register-to-agency', RegisterToAgency)
Vue.component('send-email-form', SendEmailForm)
Vue.component('agency-service-categories', AgencyServiceCategories)
Vue.component('dropdown-with-checkboxes', DropdownWithCheckboxes)
Vue.component('lasi-coalition-agencies', LasiCoalitionAgencies)
Vue.component('service-providers', ServiceProviders)
Vue.component('service-provider', ServiceProvider)
new Vue({
i18n
}).$mount('#app')
}
sign in form component for example:
<template>
<div>
<b-form
id="sign-in-form"
#submit="onSubmit"
>
<div class="form-group">
<b-form-input
id="sgi-email"
v-model="model.email"
required
name="email"
:state="state('email')"
type="email"
:placeholder="$t('validation.attributes.email_address')"
/>
<b-form-feedback>{{ feedback('email') }}</b-form-feedback>
</div>
<div class="form-group mb-3">
<b-form-input
id="sgi-password"
v-model="model.password"
required="required"
name="password"
:state="state('password')"
type="password"
:placeholder="$t('validation.attributes.password')"
/>
<b-form-feedback>{{ feedback('password') }}</b-form-feedback>
</div>
<div class="form-group my-0">
<a
class="text-opacity forgot-pass-link"
href="#"
>
{{ $t('labels.user.password_forgot') }}
</a>
</div>
</b-form>
</div>
</template>
<script>
console.log('IM HIT')
export default {
name: 'SignInForm',
data() {
return {
model: {
email: '',
password: ''
},
validation: {}
}
},
mounted() {
this.test()
},
methods: {
test() {
console.log("test")
},
feedback(name) {
if (this.state(name)) {
return this.validation.errors[name][0]
}
},
state(name) {
return this.validation.errors !== undefined &&
this.validation.errors.hasOwnProperty(name)
? 'invalid'
: null
},
onSubmit(evt) {
evt.preventDefault()
window.axios
.post('/login', this.model)
.then(response => {
location.href = '/app'
})
.catch(e => {
if (e.response.status === 422) {
this.validation = e.response.data
return
}
})
}
}
}
</script>
Any ideas help!
in the example sign in form, the console does output the "Im hit" that I had placed to ensure that things were loaded.
Thanks
Are you at any point rendering anything with that Vue instance?
Try passing a component to its render function like so:
// lets pretend you've imported a component from some file App.vue up here and called the component simply 'App'
// e.g.: const App = require('./App.vue') or import App from './App.vue';
Vue.use(BootstrapVue)
export function createApp() {
const i18n = createLocales(window.locale)
// Components
Vue.component('sign-in-form', signInForm)
Vue.component('sign-up-form', signUpForm)
Vue.component('forgot-pass-form', forgotPassForm)
// Vue.component('register-to-agency', RegisterToAgency)
Vue.component('send-email-form', SendEmailForm)
Vue.component('agency-service-categories', AgencyServiceCategories)
Vue.component('dropdown-with-checkboxes', DropdownWithCheckboxes)
Vue.component('lasi-coalition-agencies', LasiCoalitionAgencies)
Vue.component('service-providers', ServiceProviders)
Vue.component('service-provider', ServiceProvider)
new Vue({
i18n,
render: createElement => createElement(App) // needs a render function
}).$mount('#app')
}

Uncaught TypeError: Cannot read property 'firstname' of undefined. on loading a component that has an inner component

create.vue
<template>
<div class="content">
<base-input type="text" id="firstname" v-model="firstname"/>
</div>
</template>
<script>
import BaseInput from 'BaseInput.vue'
export default {
data () {
return {
firstname: ''
}
}
}
</script>
create.spec.js
import { shallowMount, createLocalVue } from '#vue/test-utils'
import Create from '/Create.vue'
import VueI18n from 'vue-i18n'
const wrapper = shallowMount(Create)
const vm = wrapper.vm
console.log(vm)
As you see, while loading the template using shallow Mount.
it throws the error,
Uncaught TypeError: Cannot read property 'firstname' of undefined at
webpack:///node_modules/#vue/test-utils/dist/vue-test-utils.js:5652:0
<- index.6fc62f9fc7f0f4a43161.js:9693
You need to add your BaseInput component to your export default. Now vue don't know what BaseInput is (info, if you are using such as Babel or Webpack) . I also changed the data line because there need to be a : after data and function before the () (example). If you do it like this it should work:
<script>
import BaseInput from 'BaseInput.vue'
export default {
components: {
BaseInput
}
data: function() {
return {
firstname: ''
}
}
}
</script>

Vue-cli change object value globally

I have this code in file app.vue :
<template>
<div id="app">
<button v-on:click="component = 'login'">aa</button>
<component v-bind:is="component"></component>
</div>
</template>
<script>
import acceuil from './components/acceuil.vue'
import login from './components/login.vue'
export default {
name: 'app',
components: {
acceuil,
login
},
data(){
return {
component: 'acceuil'
}
}
}
</script>
How can I toggle between acceuil/login in component from a different vue file ?
You need to pass the imported dependency (the object or the name of the component as a string) to v-bind:is. You can do this by returning it in a computed function and pass it to a computed property, which you then can use in the template.
<template>
<div id="app">
<button v-on:click="isLogin = true">Show Login</button>
<component v-bind:is="currentComponent"></component>
</div>
</template>
<script>
import acceuil from './components/acceuil.vue';
import login from './components/login.vue';
export default {
name: 'app',
data () {
return {
isLogin: false
};
},
computed: {
currentComponent () {
return this.isLogin ? login : acceuil;
}
},
};
</script>
See also the documentation of dynamic components in the official docs.