Use VeeValidate v4 common validators with cutomize error message - vue.js

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>

Related

Dynamic import of SVG icon components

I'm trying to import SVG icons for each item in a v-for loop, with the filename changing depending on the item's id. The icons are loading, but I get the following error for each icon imported.
Is there a better way to approach this?
Uncaught (in promise) TypeError: Failed to resolve module specifier '~/assets/img/flags/ar.svg'
<template>
<NavigationItem v-for="item in topCountries">
<template #icon>
<component :is="getIcon(item.id)" />
</template>
<NavigationItem />
</template>
<script setup>
const getIcon = (id) => defineAsyncComponent(() =>
import(`~/assets/img/flags/${id}.svg`));
</script>
You can have a look at https://nuxt.com/modules/nuxt-svgo module.
This module allows to import SVG.
npm i --save nuxt-svgo
Add it as a module dependency in your nuxt.config file
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt'
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: ['nuxt-svgo']
})
Import SVG icons as follow:
<script setup lang="ts">
const getIcon = (id: string) => defineAsyncComponent(() => import(`#/assets/svg/${id}.svg`));
</script>
<template>
<div v-for="item in ['icon1', 'icon2']">
<component :is="getIcon(item)" />
</div>
</template>
Note that if you use Typescript, you will have to create a custom.d.ts file to fix import error
// custom.d.ts
declare module '*.svg' {
import type { DefineComponent } from 'vue'
const component: DefineComponent
export default component
}
calls each icon from the data. uses font awesome icons. you can also add svgs between the i tags
<template>
<ul>
<!-- list rendering -->
<li v-for="item in items">
<span class="icon">
<i :class="[faClass(item.icon)]"
aria-hidden="true"></i>
</span>
</li>
</ul>
</template>
<script>
export default {
name: "navbarMobile",
data() {
return {
//listItems
items: [
{
icon: 'home',
},
{
icon: 'wrench',
},
{
icon: 'project-diagram',
},
{
icon: 'cogs',
},
{
icon: 'phone',
}
]
}
},
methods: {
faClass(icon) {
return `fa fa-${icon}`;
}
}
}
</script>
Us the component name instead of the component path. Also, don't forget to import SVG components and add ?inline at the end of the name.
<template>
<NavigationItem v-for="item in topCountries">
<template #icon>
<component :is="item.icon" />
</template>
<NavigationItem />
</template>
<script setup>
import Eye from '~/assets/img/flags/Eye.svg?inline';
import Balls from '~/assets/img/flags/Balls.svg?inline';
const topCountries = [
{ icon: 'Eye' },
{ icon: 'Balls' }
]
</script>

vue graphql composition api :data binding

//This is my HomeView
<template>
<div class="home">
<div class="error" v-if="error">Error: {{error.message}}</div>
<div v-else> <BlogList :allBlogs="allBlogs" /> </div>
</div>
</template>
<script>
import { useQuery, useResult } from '#vue/apollo-composable'
import gql from 'graphql-tag'
import BlogList from '../components/BlogList.vue'
// # is an alias to /src
const ALL_BLOGS = gql`
query{
allBlogs{
id
title
author
body
yearPublished
}
}`
export default {
name: 'HomeView',
components: { BlogList },
setup() {
const {result, error } = useQuery(ALL_BLOGS)
// We use use result for nested queries
const allBlogs = useResult(result, null, data => data.allBlogs)
return { allBlogs, error}
}
}
</script>
<style></style>
//This is my BLogList
<template>
<div v-for="blog in allBlogs" :key="blog.id">
<SingleBlog :blog='blog' />
</div>
</template>
<script>
import SingleBlog from '../components/SingleBlog.vue'
export default {
props: ['allBlogs'],
components: { SingleBlog },
}
</script>
<style></style>
//This is my SingleBlog
<template>
<router-link :to="{name: 'Details', params: {id: blog.id}}"><h1>{{blog.title}}</h1></router-link>
<p>{{snippet}}</p>
</template>
<script>
import { computed } from '#vue/runtime-core'
export default {
props: [ 'blog' ],
setup(props) {
const snippet = computed(() => {
return props.blog.body.substring(0,100) + '....'
})
return { snippet }
}
}
</script>
<style></style>
//This is my Details view
<template>
{{blog.title}}
</template>
<script>
import { useQuery, useResult } from '#vue/apollo-composable'
import gql from 'graphql-tag'
export default {
props: ['id'],
setup(props) {
const {result, error} = useQuery(gql`
query allBlogs($id: ID!){
allBlogs(id: $id){
id
title
author
body
yearPublished
}
}
`, props)
const blog = useResult(result)
return {blog, error }
}
}
</script>
<style></style>
In the above code everything works fine, until i get to Details view. The fetching graphql api (django backend) for list of blog I've created works fine. However, trying to see the detail of the blog which has been router-linked to Singleblog is not working. I tried to use the example provided on vue apollo site.
Does anyone have any idea what might be the problem is with my code at Details.vue?

Vue vuelidate $v is not defined

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"

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')
}

Element doesn't show

I'm trying to use the color picker from element-ui (http://element.eleme.io/#/en-US/component/color-picker). However it doesn't show up... Any clues about whats wrong?
<template>
<div class="color">
<span class="demonstration">Color picker</span>
<el-color-picker v-model="color"></el-color-picker>
</div>
</template>
<script>
import Vue from 'vue'
import ColorPicker from 'element-ui'
Vue.use(ColorPicker)
export default {
name: 'color',
data () {
return {
color: '#20a0ff'
}
}
}
</script>
Import the default-theme css too:
<template>
<div class="color">
<span class="demonstration">Color picker</span>
<el-color-picker v-model="color"></el-color-picker>
</div>
</template>
<script>
import Vue from 'vue'
import ColorPicker from 'element-ui'
import 'element-ui/lib/theme-default/index.css'
Vue.use(ColorPicker)
export default {
name: 'color',
data () {
return {
color: '#20a0ff'
}
}
}
</script>
Reference: http://element.eleme.io/#/en-US/component/quickstart#import-element