Use Vuelidate for post, data sends to server without validate - vue.js

I want to send the data from the validation check. validity includes only checking the field, that is, checking 4 fields for the presence of data and after that the data should be sent to the server. but by connecting vuelidate, the data is transferred to the server without checking for validity.
<form #submit.prevent="submitHandler" action="contacts" method="post">
<div class="form-group">
<input type="text" id="name" v-model="$v.name.$model" :class="{invalid: ($v.name.$dirty && !$v.name.required)}" />
<label class="name">Fullname</label>
<div class="error" v-if="$v.name.$dirty && !$v.name.required">Name is required</div>
</div>
</form>
methods: {
submitHandler() {
console.log(this.$v.name);
if (this.$v.$invalid) {
this.$v.$touch()
return
}
},

Related

testing api sending OPTIONS method and getting 405 error [duplicate]

This question already has an answer here:
FastAPI's RedirectResponse doesn't work as expected in Swagger UI
(1 answer)
Closed 5 months ago.
Im new to vue and nuxt, im using this ones to connect them to my API made with fastapi, and whenever i try to create an account via my API with the vue form i get this error
127.0.0.1:52137 - "OPTIONS /user HTTP/1.1" 405 Method Not Allowed
I've seen that sometimes axios sends an OPTION method to "test" the api if i get it.. But how do i solve this problem ?
Im new to this so do not hesitate to ask me more files/code.
Here is the Post method that im trying to reach and my registration page on VUE.
#app.post("/user", response_model=_schemas.UserBis)
async def create_user(user: _schemas.UserIn, db: _orm.Session = fastapi.Depends(_services.get_db)):
db_user_email = await _services.get_user_by_email(email=user.email, db=db)
if db_user_email:
raise fastapi.HTTPException(
status_code=400, detail="User with that email already exists"
)
db_user_username = await _services.get_user_by_username(username=user.username, db=db)
if db_user_username:
raise fastapi.HTTPException(
status_code=400, detail="User with that email already exists"
)
db_user_pseudo = await _services.get_user_by_pseudo(pseudo=user.pseudo, db=db)
if db_user_pseudo:
raise fastapi.HTTPException(
status_code=400, detail="User with that pseudo already exists"
)
user = await _services.create_user(user=user, db=db)
return _schemas.UserBis(data=user)
VUE:
<template>
<section class="section">
<div class="container">
<div class="columns">
<div class="column is-4 is-offset-4">
<h2 class="title has-text-centered">Register!</h2>
<Notification :message="error" v-if="error"/>
<form method="post" #submit.prevent="register">
<div class="field">
<label class="label">Username</label>
<div class="control">
<input
type="text"
class="input"
name="username"
v-model="username"
required
/>
</div>
</div>
<div class="field">
<label class="label">Pseudo</label>
<div class="control">
<input
type="text"
class="input"
name="pseudo"
v-model="pseudo"
required
/>
</div>
</div>
<div class="field">
<label class="label">Email</label>
<div class="control">
<input
type="email"
class="input"
name="email"
v-model="email"
required
/>
</div>
</div>
<div class="field">
<label class="label">Password</label>
<div class="control">
<input
type="password"
class="input"
name="password"
v-model="password"
required
/>
</div>
</div>
<div class="control">
<button type="submit" class="button is-dark is-fullwidth">Register</button>
</div>
</form>
<div class="has-text-centered" style="margin-top: 20px">
Already got an account? <nuxt-link to="/login">Login</nuxt-link>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
import Notification from '~/components/Notification'
export default {
components: {
Notification,
},
data() {
return {
username: '',
pseudo: '',
email: '',
password: '',
error: null
}
},
methods: {
async register() {
try {
await this.$axios.post('user', {
username: this.username,
pseudo: this.pseudo,
email: this.email,
password: this.password
})
await this.$auth.loginWith('local', {
data: {
email: this.email,
password: this.password
},
})
this.$router.push('/')
} catch (e) {
this.error = e.response.data.message
}
}
}
}
</script>
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Any non simple POST request triggers a pre flight check (OPTIONS request) to confirm the action is supported. Your API will need to be modified to allow these requests.
I found a slution to my problem here: https://stackoverflow.com/a/66460861/18428648
Allowing all origins solved my problem, just added a few lines of code to my FastAPI API.

Laravel + vue: Error message only showing the first letter of the sentence

I'm just starting to learn laravel+vue. I was able to follow a tutorial from this yt: https://www.youtube.com/watch?v=JZDmBWRPWlw. Though it seems outdated, I was still able to follow his steps. I'm using the laravel-mix 6.0.6 and vue 2.6.12.
Using inspect element>network, I can see that I'm throwing the correct error message in array.
{"component":"Users\/Create","props":{"app":{"name":"Laravel"},"errors":{"name":"The name field is required.","email":"The email field is required."}},"url":"\/users\/create","version":"207fd484b7c2ceeff7800b8c8a11b3b6"}
But somehow it is not displaying the complete error message. Right now it just show the first letter of the sentence. LOL. Sample error message is: The email field is required and it will just display the letter "T". Below is my Create.vue. Basically it is just a user create form with simple validation.
Create.vue
<template>
<layout>
<div class="container">
<div class="col-md-6">
<div v-if="Object.keys(errors).length > 0" class="alert alert-danger mt-4">
{{ errors[Object.keys(errors)[0]][0] }}
</div>
<form action="/users" method="POST" class="my-5" #submit.prevent="createUser">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" placeholder="Name" v-model="form.name">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" id="email" placeholder="Email" v-model="form.email">
</div>
<div class="form-group">
<label for="name">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password" v-model="form.password">
</div>
<button type="submit" class="btn btn-primary">Create User</button>
</form>
</div>
</div>
</layout>
</template>
<script>
import Layout from '../../Shared/Layout'
export default {
props: ['errors'],
components: {
Layout,
},
data() {
return {
form: {
name: '',
email: '',
password: '',
}
}
},
methods: {
createUser() {
this.$inertia.post('/users', this.form)
.then(() => {
// code
})
}
}
}
</script>
Edit:
I have this error on my console
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property
'then' of undefined"
found in
---> at resources/js/Pages/Users/Create.vue
Your error call is probably getting only the first letter due to [0]. Try to change to:
{{ errors[Object.keys(errors)[0]] }}
Strings can also be read as arrays. If you do this:
$a = "TEST";
echo $a[0];
That would print only T.
That is probably the problem.

ASP.NET Core 2.2. Razor Pages - How to populate a form control based on another field

I have a form control "ConnectorType" which I turned into a dropdown list with pre-defined values (just 3qty currently)
When the user selects and item from this dropdown list, depending on the value selected I then want to populate another text box form control underneath.
To better explain, please see image below:
Example, if TCP Server IN is selected then the form control underneath (textbox)should automatically say "Inbound"
Ideally this text box should also have an attribute/configuration that prevents the user from entering their own text, grayed out perhaps. Once the create form is submitted, the textbox that contains this value "Inbound" will then be added to the SQL Table using Enitity Framework.
The solution requires that this field dynamically changes each time a new item is selected from the list.
Current code for the drop down list:
Page Model Class:
public IEnumerable<SelectListItem> ConnectorTypeList { get; private set; } // temp
public IActionResult OnGet()
{
// prepare the list in here
ConnectorTypeList = new SelectListItem[]
{
new SelectListItem ("TCP Server IN", "TCP Server IN"),
new SelectListItem ("TCP Server OUT", "TCP Server OUT"),
new SelectListItem ("SMTP Server IN", "SMTP Server IN")
};
return Page();
}
Page View:
<div class="form-group">
<label asp-for="ConnectorModel.ConnectorType" class="control-label"></label>
<select asp-for="ConnectorModel.ConnectorType" class="form-control" asp-items="#Model.ConnectorTypeList"></select>
<span asp-validation-for="ConnectorModel.ConnectorType" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConnectorModel.DataFlow" class="control-label"></label>
<input asp-for="ConnectorModel.DataFlow" class="form-control" />
<span asp-validation-for="ConnectorModel.DataFlow" class="text-danger"></span>
</div>
Note the current form-control I'm wanting to modify is the "ConnectorModel.DataFlow" in the above page view code. At the moment it's just a simple textbox that the user can enter their own choice of text.
I'm going round in circles having read up on page handlers etc. It seems there is a onchange event but unsure how to implement this and somehow link it back to the page model class, run a method then postback the result. I'm not looking for a JQuery script as it seems this should not be required in the newer framework, not sure I just don't want a complicated long solution given I will be using a lot of these throughout the app. Thanks in advance...
The easiest way is to use onchange() on your <select> tag and assign data to input using js.(Add id attribute for <select> and <input> before)
If you would like to prevent the user from entering their own text, just use readonly attribute for you input.
<input asp-for="DataFlow" id="dataFlow" class="form-control" readonly/>
The Sample Page View:
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="ConnectorModel.ConnectorType" class="control-label"></label>
<select asp-for="ConnectorModel.ConnectorType" id="connectorTypeList" class="form-control" asp-items="#Model.ConnectorTypeList" onchange="assignData()">
<option>Select ConnectorType</option>
</select>
<span asp-validation-for="ConnectorModel.ConnectorType" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConnectorModel.DataFlow" class="control-label"></label>
<input asp-for="ConnectorModel.DataFlow" id="dataFlow" class="form-control" readonly />
<span asp-validation-for="ConnectorModel.DataFlow" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
#section Scripts{
<script>
function assignData() {
var contentType = $("#connectorTypeList").val();
if (contentType == "TCP Server IN") {
$("#dataFlow").val("Inbound");
}
}
</script>
}

Vue.js and Vee Validate - How to update error message with error from an API

I am trying to set the error message from the vee-validate to one from an API.
<div class="col-md-12">
<label for="company-contact-name" class="label-input">Company Contact Name</label>
<input v-validate="validations.user.name" v-model="data.user.name" id="company-contact-name" class="form-control" type="text" name="name" placeholder="Enter contact name" />
<div id="name-error" class="msg-error text-danger">{{ errors.first('name') }}</div>
</div>
<div class="col-md-12">
<label for="email" class="label-input">E-mail address</label>
<input v-validate="validations.user.email" v-model="data.user.email" id="email" class="form-control" type="email" name="email" placeholder="Enter e-mail" />
<div id="email-error" class="msg-error text-danger">{{ errors.first('email') }}</div>
</div>
So, If the API returns an email error, I would like to edit the above "errors.first('email')" to the API error. Then, when the user starts to correct the field, the Vee Validate would show its configured errors.
This is an example of a possible array of errors:
[
{id: "name", title: "Name is invalid. It should have only letters"},
{id: "name", title: "Name is too short. It should have more than three characters"},
{id: "email", title: "Email has already been taken"}
]
What can be done to handle the API error messages?
Thanks for your time and attention.
Perhaps something like this - create a new validator which checks whether the API has returned an error message and if yes - returns that error message. Then use this new validator as a first validator for your field, but also add the built-in validator for email addresses.
<input
v-validate="api_email|email"
v-model="user.email"
id="email"
class="form-control"
type="email"
name="email"
placeholder="Enter e-mail" />
<script>
import { Validator } from 'vee-validate';
export default
{
data()
{
api_error: '',
user:
{
email: ''
}
},
mounted()
{
Validator.extend('api_email',
{
getMessage: this.emailError,
validate: this.validateEmail
});
},
methods:
{
validateEmail(value, args)
{
return !this.api_error;
},
emailError(field, args)
{
return this.api_error;
}
}
}
</script>
UPDATE
If you want to support an array of errors then perhaps you can do it like this
<div id="email-error" class="msg-error text-danger" v-for="err in [errors.first('email')].concat(array_with_api_errors.map(item => item.title))">{{ err }}</div>

v-on:model="form.email" expects a function value, got undefined

Vue.js 2 - I am trying to bind form inputs but I always get the erro message ( on all inputs ..)
v-on:model="form.email" expects a function value, got undefined
<form id="registrationForm">
<div class="form-group">
<input type="email" name="email" id="email" #model="form.email" placeholder="enter your email address">
</div>
<button #click="sendRegistration" type="submit" class="btn btn-primary btn-gradient submit">SEND</button>
</form>
and the script
data: function() {
return {
form: {
...
email: '',
...
}
}
},
methods: {
sendRegistration: function() {
console.log('sending form')
return false
}
},
You're getting some things mixed up. Attributes starting with v-on:, often abbreviated as #, are used to register event listeners on elements. #click="sendRegistration" will for example register the sendRegistration method defined on your Vue instance as a handler for that element's click event.
What you're trying to accomplish has nothing to do with event handling. The attribute you need is called v-model and binds an <input>'s value to a value saved on your Vue instance.
<input type="email" name="email" id="email" #model="form.email">
should be
<input type="email" name="email" id="email" v-model="form.email">