Why doesn't it work when sameAs is used in vuelidate? - vue.js

fieldName not found to vuelidate of sameAs method.
sameAs(blabla)
blabla = 'internalFormData.password', 'internalFormData.password.value', 'this.internalFormData.password', 'this.internalFormData.password.value', 'password', 'this.password', 'password.value'
-----------script----------
data () {
return {
internalFormData: {
password: '',
repassword: ''
}
}
},
validations: {
password: {
value: {
required,
minLength: minLength(8)
}
},
repassword: {
value: {
required,
minLength: minLength(8),
sameAs: sameAs('internalFormData.password')
}
}
}
},
---------------template--------------
<error
v-if="!$v.internalFormData.repassword.value.sameAs"
>
비밀번호가 일치하지 않습니다.
<error>
The error won't go away.

Your validations structure should mirror object(s) in data, thus it should be:
validations: {
internalFormData: {
password: {
required,
minLength: minLength(8)
},
repassword: {
required,
minLength: minLength(8),
sameAs: sameAs('internalFormData.password')
}
}
}

You need to point out your nested attribute with a function.
Like this :
data(){return {
password :{
new: '',
newRepeated:''
}
}},
validations : {
password: {
new : {required},
newRepeated : {
required,
sameAs : sameAs( function(){return this.password.new} )
}
}
}
I would also suggest you to take a look at this closed issue.
https://github.com/vuelidate/vuelidate/issues/252

Example for vue3:
validations () {
return {
admin: {
type: {
required
},
email: {
required,
email
},
password: {
required,
minLength: minLength(10)
},
confirmPassword: {
required,
sameAs: sameAs(this.admin.password)
}
}
}
}

Simple example with composition api:
import { useVuelidate } from '#vuelidate/core'
import { email, required, sameAs } from '#vuelidate/validators'
const form = {
email: '',
confirm_email: '',
}
const rules = {
email: { required, email },
confirm_email: { required, sameAs(computed(()=> form.email))) },
}
const v$ = useVuelidate(rules, form)

Replace this line:
sameAs: sameAs('internalFormData.password')
With
sameAs: sameAs(this.internalFormData.password)
The parameter should not be a string but rather the actual attribute using 'this'
I am not sure whether the validations not being identical to the data internalFormData will affect how it works bu I suggest you ensure they match to fit as shown below:
validations: {
internalFormData: {
password: {
required,
minLength: minLength(8)
},
repassword: {
required,
minLength: minLength(8),
sameAs: sameAs(this.internalFormData.password)
}
}
}

You must be use .value
sameAs: sameAs('internalFormData.value.password')

Related

Accessing validation property outside the current scope in vuelidate/VueJS?

Given the following component in Vue 2 using vuelidate from property validation:
<template>
// template stuff here...
</template>
<script>
import { validationMixin } from "vuelidate";
import { required, requiredIf } from "vuelidate/lib/validators";
export default {
name: "ParentComponent",
mixins: [validationMixin],
data() {
return {
selected: false,
user: {
email: null,
password: null,
},
};
},
validations: {
selected: { required },
user: {
email: { required: requiredIf((vm) => vm.selected) },
password: { required: requiredIf((vm) => vm.selected) },
},
},
};
</script>
The properties user.email and user.password are required, but only if the validation for selected passes successfully. However, this approach does not seem to work, probably because selected is not part of the user validation object.
Is there a way to access this validation property? Something like this...
validations: {
selected: { required },
user: {
email: { required: requiredIf((vm) => vm.$parentVm.selected) },
password: { required: requiredIf((vm) => vm.$parentVm.selected) },
},
},
Just like that. Demo https://codesandbox.io/s/green-darkness-90fjs.
requiredIf good solution for resolve this problem

Can't be blank - Password - Loopback 4 - JWT authentication

When I want to signup on the loopback API Explorer with a JWT authentication and this json format:
{
"id": "string",
"nom": "string",
"prenom": "string",
"email": "string",
"sexe": true,
"dateNaissance": "string",
"password": "strifsvng"
}
I had that error message :
{
"error": {
"statusCode": 422,
"name": "ValidationError",
"message": "L'instance `User` n'est pas valide. Détails : `password` can't be blank (value: undefined).",
"details": {
"context": "User",
"codes": {
"password": [
"presence"
]
},
"messages": {
"password": [
"can't be blank"
]
}
}
}
}
Here the link of the documentation's loopback I've used.
You can see here the user modal :
import {Entity, model, property} from '#loopback/repository';
#model()
export class User extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'string',
required: true,
})
nom: string;
#property({
type: 'string',
required: true,
})
prenom: string;
#property({
type: 'string',
required: true,
})
dateNaissance: string;
#property({
type: 'string',
required: true,
})
sexe: string;
#property({
type: 'string',
required: true,
})
email: string;
#property({
type: 'string',
required: true,
})
password: string;
constructor(data?: Partial<User>) {
super(data);
}
}
export interface UserRelations {
// describe navigational properties here
}
export type UserWithRelations = User & UserRelations;
and the user controller :
// import {inject} from '#loopback/core';
import {inject} from '#loopback/core';
import {
Credentials,
MyUserService,
TokenServiceBindings,
User,
UserRepository,
UserServiceBindings,
} from '#loopback/authentication-jwt';
import {authenticate, TokenService} from '#loopback/authentication';
import {model, property, repository} from '#loopback/repository';
import {get, getModelSchemaRef, post, requestBody} from '#loopback/rest';
import {SecurityBindings, securityId, UserProfile} from '#loopback/security';
import {genSalt, hash} from 'bcryptjs';
import _ from 'lodash';
#model()
export class NewUserRequest extends User {
#property({
type: 'string',
required: true,
})
password: string;
}
const CredentialsSchema = {
type: 'object',
required: ['email', 'password'],
properties: {
email: {
type: 'string',
format: 'email',
},
password: {
type: 'string',
minLength: 8,
},
},
};
export const CredentialsRequestBody = {
description: 'The input of login function',
required: true,
content: {
'application/json': {schema: CredentialsSchema},
},
};
export class UserController {
constructor(
#inject(TokenServiceBindings.TOKEN_SERVICE)
public jwtService: TokenService,
#inject(UserServiceBindings.USER_SERVICE)
public userService: MyUserService,
#inject(SecurityBindings.USER, {optional: true})
public user: UserProfile,
#repository(UserRepository) protected userRepository: UserRepository,
) {}
#post('/users/login', {
responses: {
'200': {
description: 'Token',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
token: {
type: 'string',
},
},
},
},
},
},
},
})
async login(
#requestBody(CredentialsRequestBody) credentials: Credentials,
): Promise<{token: string}> {
// ensure the user exists, and the password is correct
const user = await this.userService.verifyCredentials(credentials);
// convert a User object into a UserProfile object (reduced set of properties)
const userProfile = this.userService.convertToUserProfile(user);
// create a JSON Web Token based on the user profile
const token = await this.jwtService.generateToken(userProfile);
return {token};
}
#authenticate('jwt')
#get('/whoAmI', {
responses: {
'200': {
description: '',
schema: {
type: 'string',
},
},
},
})
async whoAmI(
#inject(SecurityBindings.USER)
currentUserProfile: UserProfile,
): Promise<string> {
return currentUserProfile[securityId];
}
#post('/signup', {
responses: {
'200': {
description: 'User',
content: {
'application/json': {
schema: {
'x-ts-type': User,
},
},
},
},
},
})
async signUp(
#requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(NewUserRequest, {
title: 'NewUser',
}),
},
},
})
newUserRequest: NewUserRequest,
): Promise<User> {
const password = await hash(newUserRequest.password, await genSalt());
const savedUser = await this.userRepository.create(
_.omit(newUserRequest, 'password'),
);
await this.userRepository.userCredentials(savedUser.id).create({password});
return savedUser;
}
}
I don't know why there are that error as I write something in the password.
Thank you in advance :)

Child element not updating props after change in data coming from apollo in nuxt/vue

UPDATE: the main issue seems to be that the props only get updated once. They should change when this.campaign.name becomes available.
I want to dynamically update the title and breadcrumb data fields and show them on the page. Currently page page shows undefined or null. How can I fix this?
I tried to create a computed value but it only seems to update once (after head and breadcrumb data is already showed). A method does not work since I don't have anything to trigger the method.
What is the correct way to fix this?
I am using nuxt generate to deploy the app.
export default {
components: { PageHeader },
middleware: 'authenticated',
data() {
return {
title: 'Campaigns' + this.campaignName,
breadcrumb: [
{
text: 'Campaigns',
href: '/'
},
{
text: this.campaignName,
href: '/'
}
],
campaign: ''
}
},
apollo: {
campaign: {
prefetch: true,
query: campaignQuery,
variables() {
return { id: this.$route.params.id }
}
}
},
computed: {
campaignName() {
return this.campaign && this.campaign.name
}
},
head() {
return {
title: this.title
}
}
}
</script>
Your computed property campaignName returns undefined cuz this.campaign.name is not defined
campaignName() {
if(this.campaign && this.campaign.name) return "Campaigns" + this.campaign.name;
return "default value";
}
Then you can use it directly in head
head() {
return {
title: this.campaignName
}
}
The solution was putting the data elements directly as a computer property. (so no recalculation)
export default {
components: { PageHeader },
middleware: 'authenticated',
data() {
return {}
},
apollo: {
campaign: {
prefetch: true,
query: campaignQuery,
variables() {
return { id: this.$route.params.id }
}
}
},
computed: {
title() {
return this.campaign && `Campaign: ${this.campaign.name}`
},
breadcrumb() {
return [
{
text: 'Campaign',
href: '/'
},
{
text: this.campaign && this.campaign.name,
href: '/'
}
]
}
},
head() {
return {
title: this.title
}
}
}
</script>

Transpiled GraphQL with Babel is throwing error "Cannot call class as function"

I am trying to get running GraphQL server. I have simple schema in GraphQL
import {
GraphQLObjectType,
GraphQLInt,
GraphQLString,
GraphQLList,
GraphQLSchema
} from 'graphql'
import db from './models'
const user = new GraphQLObjectType({
name: "user",
description: 'This represents a user',
fields: () => {
return {
id: {
type: GraphQLInt,
resolve(user) {
return user.id
}
},
firstName: {
type: GraphQLString,
resole(user) {
return user.firstName
}
},
lastName: {
type: GraphQLString,
resole(user) {
return user.lastName
}
},
email: {
type: GraphQLString,
resole(user) {
return user.email
}
},
createdAt: {
type: GraphQLString,
resole(user) {
return user.createdAt
}
},
updatedAt: {
type: GraphQLString,
resole(user) => {
return user.updatedAt
}
}
}
}
})
const Query = new GraphQLObjectType({
name: 'Query',
description: 'This is root Query',
fields: () => {
return {
users: {
type: GraphQLList(user),
args: {
id: {
type: GraphQLInt
},
email: {
type: GraphQLString
}
},
resolve(root, args) {
return db.user.findAll({where: args})
}
}
}
}
})
const Schema = new GraphQLSchema({
query: Query
})
export default Schema
I am transpile it with babel into ES5, but every time when I try run it with express
import GraphHTTP from 'express-graphql'
import Schema from './schema'
app.use('/grapql', GraphHTTP({
schema: Schema,
pretty: true,
graphiql: true
}))
I am getting this error
\node_modules\graphql\type\definition.js:41
function _classCallCheck(instance, Constructor) { if (!instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }                                                             
TypeError: Cannot call a class as a function
I check it again and again if i have some typing error but i didnt find enything.
instead of type: GraphQLList(user) use type: new GraphQLList(user)
GraphQLList is a class and you have to create it's instance and use, but you have called it as a function.
const Query = new GraphQLObjectType({
name: 'Query',
description: 'This is root Query',
fields: () => {
return {
users: {
type: new GraphQLList(user),
args: {
id: {
type: GraphQLInt
},
email: {
type: GraphQLString
}
},
resolve(root, args) {
return db.user.findAll({where: args})
}
}
}
}
})

How to map a nested Vuelidate validation object with computed properties in VueJS?

I have a tabs container with multiple forms. Some of the fields in all forms have some complex logic that I didn't want to repeat on each form, so I created a custom component that is used in all forms. I'm trying to use Vuelidate to validate all of my forms but since those field names are the same, and of course have the same validation logic, the Vuelidate validation object is the same in all forms, meaning, if I fill in the email field in formA, then all forms with that same field will also validate correctly, even though the rest of the forms haven't been filled in at all.
I tried to wrap my validations inside an object named as the forms, and this seems to separate all validation logic correctly, but, I have other setup there that prevents me from using data attributes and I use computed attributes instead. As far as I know, the validations object must match the way we access fields data, like, data() { formA: { email } } would match to validation object validations: { formA: { email } }, the problem is, since I'm not using data properties, I don't know how to map computed properties.
This is what I have:
export default {
components: { PhoneField, TopNote, SubmitButton, NameFieldsGroup, EmailField },
validations: {
formA: {
firstName: { required },
lastName: { required },
email: {
required,
email
},
phone: {
required,
length: minLength(10)
}
}
},
created() {
this.$store.commit('setFormValidation', this.$v);
},
data() {
return {}
},
computed: {
firstName: function() {
return this.$store.getters.formState.firstName;
},
lastName: function() {
return this.$store.getters.formState.lastName;
},
email: function() {
return this.$store.getters.formState.email;
},
phone: function() {
return this.$store.getters.formState.phone;
}
}
};
I've been messing around with this for the past several days, but can't figure it out. Anyone can suggest a solution for this?
Figured it out. Not sure why it works but it does now. The fix is to use Vuex's mapState like this:
import { mapState } from 'vuex';
export default {
components: { PhoneField, TopNote, SubmitButton, NameFieldsGroup, EmailField },
validations: {
formA: {
firstName: { required },
lastName: { required },
email: {
required,
email
},
phone: {
required,
length: minLength(10)
}
}
},
created() {
this.$store.commit('setFormValidation', this.$v);
},
data() {
return {}
},
computed: {
...mapState(['formA']),
firstName: function() {
return this.$store.getters.formState.firstName;
},
lastName: function() {
return this.$store.getters.formState.lastName;
},
email: function() {
return this.$store.getters.formState.email;
},
phone: function() {
return this.$store.getters.formState.phone;
}
}
};