Vue.js not updating template when changing child objects - vue.js

I'm extending laravel spark and wanted to try to validate registration before actually sending it off.
All data is handled nicely and correctly from the server but the errors do not pop-up.
The code being used for validation is as following:
module.exports = {
...
methods: {
...
validate(field, value) {
var formData = {
field: field,
value: value
};
var form = new SparkForm(formData);
Spark.post('/register_validate', form).then(response => {
this.registerForm.addSuccess(field);
}).catch(errors => {
this.registerForm.addError(field, errors[field]);
});
}
}
};
After, i extended SparkForm and added these methods (successes is just a copy of errors, used to display validation success messages):
/**
* SparkForm helper class. Used to set common properties on all forms.
*/
window.SparkForm = function (data) {
...
this.addError = function(field, errors) {
form.successes.remove(field);
form.errors.add(field, errors);
},
this.addSuccess = function(field) {
form.errors.remove(field);
form.successes.add(field, true);
}
};
And finally i added some methods on the SparkFormErrors.
/**
* Spark form error collection class.
*/
window.SparkFormErrors = function () {
...
this.add = function(field, errors) {
this.errors[field] = errors;
};
this.remove = function(field) {
delete this.errors[field];
}
};
In the console no errors are shown and in the network tab i can see the correct messages coming true, also when i add a console log in for example the response callback i can see the actual errors or success messages. But they are not drawn on screen.
For completeness i'll include the important content of the template blade file:
#extends('spark::layouts.app')
#section('content')
<spark-register-stripe inline-template>
<!-- Basic Profile -->
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
{{ trans('auth.register.title') }}
</div>
<div class="panel-body">
<!-- Generic Error Message -->
<div class="alert alert-danger" v-if="registerForm.errors.has('form')">
#{{ registerForm.errors.get('form') }}
</div>
<!-- Registration Form -->
<form class="form-horizontal" role="form">
<!-- Name -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('name')}">
<label class="col-md-4 control-label">{{ trans('user.name') }}</label>
<div class="col-md-6">
<input type="name" class="form-control" name="name" v-model="registerForm.name" autofocus #blur="validate('name', registerForm.name)">
<span class="help-block" v-show="registerForm.errors.has('name')">
#{{ registerForm.errors.get('name') }}
</span>
</div>
</div>
<!-- E-Mail Address -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('email')}">
<label class="col-md-4 control-label">{{ trans('user.email') }}</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" v-model="registerForm.email" #blur="validate('email', registerForm.email)">
<span class="help-block" v-show="registerForm.errors.has('email')">
#{{ registerForm.errors.get('email') }}
</span>
</div>
</div>
<!-- Password -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('password')}">
<label class="col-md-4 control-label">{{ trans('user.password') }}</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password" v-model="registerForm.password" #blur="validate('password', registerForm.password)">
<span class="help-block" v-show="registerForm.errors.has('password')">
#{{ registerForm.errors.get('password') }}
</span>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button class="btn btn-primary" #click.prevent="register" :disabled="registerForm.busy">
<span v-if="registerForm.busy">
<i class="fa fa-btn fa-spinner fa-spin"></i>{{ trans('auth.register.submitting') }}
</span>
<span v-else>
<i class="fa fa-btn fa-check-circle"></i>{{ trans('auth.register.submit') }}
</span>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</spark-register-stripe>
#endsection
Any bright mind seeing what i'm missing/forgetting?

Related

How to display validation summary below the input controls?

I have the following form:
<form asp-controller="Manage" asp-action="RemoveDetails" method="post" class="form-horizontal">
#if (Model.RequirePassword)
{
<div id="password-container">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" class="form-control" id="password" autocomplete="current-password" aria-required="true" />
<small>
<span asp-validation-for="Password" class="text-danger"></span>
</small>
</div>
</div>
</div>
}
<div class="col-6">
<hr class="mt-2 mb-3">
<button type="submit" class="btn btn-style-1 btn-danger">Confirm</button>
</div>
<div class="row">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
</div>
</form>
If I leave the password empty, a validation message (the model uses DataAnnonations) is displayed right below the control. This is fine.
If I enter the wrong password, the Post action validates it and adds an error to the ModelState. This error is displayed below the form.
Is it possible to display such model errors below the relevant controls?
Try this code in Controller: ModelState.AddModelError("Password", "validation summary error."); The error message won't display in <div asp-validation-summary="ModelOnly"></div>, but it can display error message in #Html.ValidationSummary(false, "", new { #class = "text-danger" }).
<form asp-controller="Home" asp-action="RemoveDetails" method="post" class="form-horizontal">
<div id="password-container">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" class="form-control" id="password" autocomplete="current-password" aria-required="true" />
<small>
#*<span asp-validation-for="Password" class="text-danger"></span>*#
#Html.ValidationSummary(false, "", new { #class = "text-danger" })
</small>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="Description"></label>
<input asp-for="Description" class="form-control" id="description" autocomplete="current-password" aria-required="true" />
<small>
<span asp-validation-for="Description" class="text-danger"></span>
</small>
</div>
</div>
</div>
<div class="col-6">
<hr class="mt-2 mb-3">
<button type="submit" class="btn btn-style-1 btn-danger">Confirm</button>
</div>
<div class="row">
<div asp-validation-summary="ModelOnly"></div>
</div>
</form>
[HttpPost]
public IActionResult RemoveDetails(RemoveDetail rdl)
{
if(ModelState.IsValid)
{
var pwd = rdl.Password;
//do something here and find the password is wrong
//code below won't display error message in <div asp-validation-summary="ModelOnly" class="text-danger">
//but can display error message in #Html.ValidationSummary(false, "", new { #class = "text-danger" })
ModelState.AddModelError("Password", "validation summary error.");
return View(rdl);
}
return View(rdl);
}

Preventing developer message to user frontend

I am developing a website with different pages, and among those pages,
I have a contact form that send message to the backend, the email id is unique, I need to display an error message to the front end that if a user enter the email that exist to then it has to display a message the email is taken. How can I go to achieve this. Here is my code
Controller
<?php
namespace App\Http\Controllers\Frontend;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Contact;
use Illuminate\Support\Carbon;
class FrontendPages extends Controller
{
public function About(){
return view('frontend.pages.about');
}//end method
public function Service(){
return view('frontend.pages.services');
}//end method
public function Blog(){
return view('frontend.pages.blog');
}//end method
public function Contact(){
return view('frontend.pages.contact');
}//end method
public function StoreMessage(Request $request){
Contact::insert([
'name' => $request->name,
'email' => $request->email,
'subject' => $request->subject,
'message' => $request->message,
'created_at' =>Carbon::now(),
]);
if ($request->email == 'email') {
return response()->json(['email exist']);
}
$notification = array(
'message' => 'Thank for being in touch we will get back to you soon',
'alert-type' => 'success'
);
return redirect()->back()->with($notification);
}
}
my form
#extends('frontend.main_master')
#section('main')
#php
$footersetup = App\Models\Footer::find(1)->first();
#endphp
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- ======= Breadcrumbs ======= -->
<section id="breadcrumbs" class="breadcrumbs">
<div class="container mt-3">
<div class="d-flex justify-content-between align-items-center">
<h2>Contact</h2>
<ol>
<li>Home</li>
<li>Contact</li>
</ol>
</div>
</div>
</section>
<!-- End Breadcrumbs -->
<!-- ======= Contact Section ======= -->
<section id="contact" class="contact">
<div class="container">
<div class="row mt-5">
<div class="col-lg-4">
<div class="info">
<h4>Location:</h4>
<div class="address">
<i class="bi bi-geo-alt"></i>
{!! $footersetup->address !!}<br /><br />
</div>
<div class="email">
<i class="bi bi-envelope"></i>
<h4>Email:</h4>
<p>
{{$footersetup->email}}<br />{{$footersetup->email1}}
</p>
</div>
<div class="phone">
<i class="bi bi-phone"></i>
<h4>Call:</h4>
<p>{{$footersetup->phone}}</p>
</div>
</div>
</div>
<div class="col-lg-8 mt-5 mt-lg-0">
<form
action="{{route('store.message')}}"
method="post"
role="form"
>
#csrf
<div class="row">
<div class="col-md-6 form-group">
<input
type="text"
name="name"
class="form-control"
id="name"
placeholder="Your Name"
required
/>
</div>
<div class="col-md-6 form-group mt-3 mt-md-0">
<input
type="email"
class="form-control"
name="email"
id="email"
placeholder="Your Email"
required
/>
</div>
</div>
<div class="form-group mt-3">
<input
type="text"
class="form-control"
name="subject"
id="subject"
placeholder="Subject"
required
/>
</div>
<div class="form-group mt-3">
<textarea
class="form-control"
name="message"
rows="5"
placeholder="Message"
required
></textarea>
</div>
<div class="my-3">
</div>
<div class="text-center">
<button type="submit" class="btn btn-success">Send Message</button>
</div>
</form>
</div>
</div>
</div>
</section>
<!-- End Contact Section -->
#endsection

Why my vuex store state chnage when i try to chnage the data using the method in my component?

I am making a small appliaction that allow the user to tell about their web application.
But In the Update component what I am doing is:
When a component is created.
Fetching the app from vue x store
Setting the values in the data property
And from data property taking it to the template
But the problem is when I try to update the stack of an app via methods addTechToStack by pushing the new value at the end of the app_stacks list it also changes the data of vuex state
Here is the code
<template>
<div>
<div class="section">
<div class="box">
<h1 class="title is-4 has-text-centered">Update App</h1>
<hr class="has-background-black" />
<form method="POST" #submit.prevent="">
<div class="field">
<label class="label">App Name:</label>
<div class="control">
<input
class="input"
type="text"
placeholder="Enter App Name"
v-model="updated.app_name"
/>
</div>
</div>
<div class="field">
<label class="label">App Subtitle:</label>
<div class="control">
<input
class="input"
type="text"
placeholder="Enter App Subtitle"
v-model="updated.app_subtitle"
/>
</div>
</div>
<div class="field">
<label class="label">App Url:</label>
<div class="control">
<input
class="input"
type="text"
placeholder="Enter App Url"
v-model="updated.app_url"
/>
</div>
</div>
<div class="field">
<label class="label">App Category:</label>
<div class="control">
<div class="select">
<select v-model="updated.app_category">
<option value="" disabled>Select Category</option>
<option
v-for="(category, index) in categoreis"
:key="index"
:value="category"
>{{ category }}</option
>
</select>
</div>
</div>
</div>
<div class="field">
<label class="label">App Description:</label>
<textarea
class="textarea"
placeholder="Description of your app"
v-model="updated.app_description"
></textarea>
</div>
<!-- IMP:Stack section -->
<div class="field">
<label class="label">App Stacks:</label>
<div class="field has-addons">
<div class="control">
<input
class="input"
type="text"
placeholder="Find Technology"
v-model="updated.stackTech"
id="stackTech"
/>
</div>
<div class="control">
<button class="button is-info" #click="addTechToStack">
Add
</button>
</div>
</div>
</div>
<div class="box">
<label class="label">Stacks:</label>
<span
class="tag is-medium mr-3"
v-for="(tech, index) in updated.app_stacks"
:key="index"
>{{ tech }}
<button
class="delete is-small"
#click="removeStack(index)"
></button>
</span>
</div>
<!-- Stack section ends -->
<div class="field is-grouped">
<p class="control">
<a class="button">
Cancel
</a>
</p>
<p class="control">
<button
type="submit"
class="button is-primary"
v-on:click="submitUpdate"
>
Update
</button>
</p>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Update",
data() {
return {
currentApp: null,
categoreis: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"],
// Contains the updated value
updated: {
app_name: "",
app_subtitle: "",
app_description: "",
app_url: "",
app_category: "",
app_stacks: "",
stackTech: "",
},
};
},
methods: {
removeStack(index) {
console.log("Removed");
this.updated.app_stacks.splice(index, 1);
console.log(this.currentApp);
console.log(this.updated.app_stacks);
},
addTechToStack() {
this.updated.app_stacks.push(this.updated.stackTech);
console.log(this.currentApp.stacks);
console.log(this.updated.app_stacks);
},
submitUpdate() {
// Check if user has updated any content
if (
this.currentApp.app_name == this.updated.app_name &&
this.currentApp.subtitle == this.updated.app_subtitle &&
this.currentApp.app_url == this.updated.app_url &&
this.currentApp.category == this.updated.app_category &&
this.currentApp.description == this.updated.app_description &&
this.currentApp.stacks.toLocaleString()==this.updated.app_stacks.toLocaleString()
) {
console.log("Cannot Update Beasue every vlaue is the same");
console.log(this.currentApp.description);
console.log(this.updated.app_description);
console.log(this.currentApp.stacks);
console.log(this.updated.app_stacks);
} else {
console.log("Updated");
console.log(this.currentApp.description);
console.log(this.updated.app_description);
}
},
},
created() {
// const current = this.$store.state.your_apps[this.$route.params.index];
this.currentApp = this.$store.state.your_apps[this.$route.params.index];
this.updated.app_name = this.currentApp.app_name;
this.updated.app_subtitle = this.currentApp.subtitle;
this.updated.app_url = this.currentApp.app_url;
this.updated.app_category = this.currentApp.category;
this.updated.app_description = this.currentApp.description;
this.updated.app_stacks = this.currentApp.stacks;
console.log(this.currentApp);
}
};
</script>
The problem is you're assigning a reference the same object (array) to a different variable.
So this.updated.app_stacks === this.currentApp.stacks are both references to the same array. So if you mutate one, you mutate the other.
To avoid this, you'll have to create a copy of this array in order to create a new reference and detach both array.
If you array is hosting primitive values (i.e. not arrays or objects), you can make a shallow copy. There are a lot of ways to do so, here is one:
this.updated.app_stacks = [...this.currentApp.stacks];
Side note: in your data() initialisation, this.updated.app_stacks should be an empty array, not an empty string. It doesn't change anything since you overwrite it in created, but it's kind of confusing when reading the code.

On form button click success, form validations fire again

Hopefully this is a newbie question.
I am using Vuelidate to validate my form and the form validations works fine, when the “send email” button is clicked.However on success, instead of showing me the successful message, the system shows that all the form controls have errors(This is because I have bound the name, email, message controls to their corresponding empty data elements).
What am I missing?
How can I fix this issue?
Contact.vue
<template>
<div>
<section class="slice slice-lg" id="sct_contact_form">
<div class="container">
<div class="mb-5 text-center">
<span class="badge badge-soft-info badge-pill badge-lg">
Contact
</span>
<h3 class=" mt-4">Send us a message</h3>
</div>
<div class="row justify-content-center">
<div class="col-lg-8">
<form>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Name</label>
<input class="form-control" type="text" placeholder="Name" v-model="user.name" id="name" name="name" :class="{ 'is-invalid': submitted && $v.user.name.$error }" >
<div v-if="submitted && !$v.user.name.required" class="invalid-feedback">Name is required</div>
</div>
</div>
</div>
<div class="row align-items-center">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Email</label>
<input class="form-control" type="email" placeholder="email#example.com"
v-model="user.email" id="email" name="email" :class="{ 'is-invalid': submitted && $v.user.email.$error }" >
<div v-if="submitted && $v.user.email.$error" class="invalid-feedback">
<span v-if="!$v.user.email.required">Email is required</span>
<span v-if="!$v.user.email.email">Email is invalid</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Message</label>
<textarea class="form-control" data-toggle="autosize" placeholder="Tell us a few words ..." rows="3" style="overflow: hidden; overflow-wrap: break-word; resize: none; height: 96.9922px;"
v-model="user.message" id="message" name="message" :class="{ 'is-invalid': submitted && $v.user.message.$error }" ></textarea>
<div v-if="submitted && $v.user.message.$error" class="invalid-feedback">
<span v-if="!$v.user.message.required">Message is required</span>
<span v-if="!$v.user.message.minLength">Message must be at least 6 characters</span>
</div>
</div>
</div>
</div>
<div class="text-center mt-4">
<button type="button" class="btn btn-dark rounded-pill" v-on:click="SendEmail()">Send your message</button>
<span class="d-block mt-4 text-sm">We'll get back to you in 24-48 h.</span>
<div v-if="submitted" class="valid-feedback">
<span v-if="!$v.user.name.$error && !$v.user.email.$error && !$v.user.message.$error">Your email was send successfully. We'll get back to you in 24-48 h.</span>
</div>
</div>
</form>
</div>
</div>
</div>
</section>
</div>
</template>
import { Email } from '../api/email.js';
import { required, email, minLength, sameAs } from "vuelidate/lib/validators";
export default {
name: "Contact",
components:{
},
data() {
return {
user: {
name: "",
email: "",
message: ""
},
submitted: false
};
},
validations: {
user: {
name: { required },
email: { required, email },
message: { required, minLength: minLength(6) }
}
},
methods: {
SendEmail() {
this.submitted = true;
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
var nameWithEmailText="Email message from: "+ this.user.name + "\nEmail message: " + this.user.message;
var subject="Email from contact us page in common membership website";
Meteor.call('email.send', this.user.email, subject, nameWithEmailText);
this.user.name='';
this.user.email='';
this.user.message='';
}
}
}
You should wait for the Meteor.call() to complete, then reset the validation state.
For example
Meteor.call('email.send', this.user.email, subject, nameWithEmailText, (error, result) => {
this.user.name = ''
this.user.email = ''
this.user.message = ''
this.$v.$reset()
})

Validate specific amount of input fields with vee-validate

I want to validate varios steps in a wizard, without validating all inputs, when clicking on the next button. When clicking on the next button it should fire the function to validate the input fields of the first step. Then in the next step the input fields of the second step and so on. The next button is no submit button.
<tab-content title="Company" icon="fas fa-building" :before-change="validateThirdStep">
<div class="col-md-8 offset-md-2">
<label class="col-form-label text-md-right">Do you have a chicken?</label>
<div class="form-goup row">
<div class="col-md-7">
<input type="radio" name="dsb" id="radios" value="yes" v-model="pickeddsb">Yes
<input type="radio" name="dsb" id="radios" value="no" v-model="pickeddsb">No
</div>
</div>
</div>
<div class="form-group" v-if="pickeddsb=='yes'">
<div class="col-md-8 offset-md-2">
<h4>Data</h4>
</div>
<div class="col-lg-8 m-auto">
<!-- Name -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('name') }}</label>
<div class="col-md-7">
<input
v-model="namedsb"
v-validate="'required|namedsb'"
:class="{ 'has-error': errors.has('namedsb') }"
type="text"
name="namedsb"
>
{{ errors.first('namedsb') }}
</div>
</div>
<!-- Firm -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('companyname') }}</label>
<div class="col-md-7">
<input
v-model="firm"
v-validate="'required|firmdsb'"
:class="{ 'has-error': errors.has('firmdsb') }"
class="form-control"
type="text"
name="firmdsb"
>
{{ errors.first('firmdsb') }}
</div>
</div>
<!--Telephone-->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{$t('telephone')}}</label>
<div class="col-md-7">
<input
v-model="telephonedsb"
v-validate="'required|telephonedsb'"
:class="{ 'has-error': errors.has('telephonedsb')}"
class="form-control"
type="tel"
name="telephonedsb"
>
{{ errors.first('telephonedsb') }}
</div>
</div>
<!-- Email -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('email') }}</label>
<div class="col-md-7">
<input
v-model="emaildsb"
v-validate="'required|emaildsb'"
:class="{ 'has-error': errors.has('emaildsb') }"
class="form-control"
type="email"
name="emaildsb"
>
{{ errors.first('emaildsb') }}
</div>
</div>
</div>
</div>
</tab-content>
export default {
data() {
return {
namedsb: "",
telephonedsb: "",
emaildsb: "",
namere: "",
telephonere:"",
emailre: "",
}
},
methods: {
validateThirdStep: function() {
this.$validator.validate('namedsb', this.namedsb);
this.$validator.validate('firmdsb', this.firmdsb);
this.$validator.validate('telephonedsb', this.state);
this.$validator.validate('emaildsb', this.emaildsb);
}
}
}
It's fairly easy with the built-in scopes of VeeValidate, you can read about it on this page: enter link description here
A simple explanation is to add a specific scope for each tab/step, by adding this on the fields:
data-vv-scope="step1"
And then use this method when pressing the button for validation:
methods: {
validateForm(scope) {
this.$validator.validateAll('step1').then((result) => {
if (result) {
alert('Form Submitted!');
}
});
}
}