Reset component data on click (Without $vm.forceUpdate()) - javascript

I have the following data in an application form component.
data() {
return {
manuallyEnterAddress: false,
currentAddress: "",
postcode: undefined,
postcode2: undefined,
address: {
county: "",
town: "",
addressLine1: "",
atAddressFrom: "",
atAddressTo: ""
},
}
}
Once the application for is completed the data will look similar to the code below.
data() {
return {
manuallyEnterAddress: true,
currentAddress: "Some House",
postcode: SK1MPS,
postcode2: SK5N0Q,
address: {
county: "Cheshire",
town: "Chester",
addressLine1: "Random street",
atAddressFrom: "01/01/91",
atAddressTo: "01/01/2010"
},
}
}
When the form has been completed the user needs a way to reset the application form, returning the the first stepper, with blank fields.
Manually writing each field to reset would be horrific as there's at least ten times the data.
I've tried forceUpdate as shown below with no success.
newApplication() {
$vm.forceUpdate()
}
Is there a way I could use the "newApplication" function to reset all of the data on the component?

In your case there is no need to re-render the vue Component, which is what forceUpdate() will be doing forcefully. I will suggest using an object for modeling your form, lets say, formModel. For Example:
Template:
<form id="app" #submit="checkForm" method="post" novalidate="true">
<label for="name">Name</label>
<input type="text" name="name" id="name" v-model="formModel.name">
<label for="email">Email</label>
<input type="email" name="email" id="email" v-model="formModel.email">
<input type="submit" value="Submit">
</form>
<<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
JS:
let app = new Vue({
el: "#app",
data: {
errors: [],
formModel: {}
},
methods: {
checkForm: function(e) {
let self = this
self.errors = []
if (!self.formModel.name) {
self.errors.push("Name required.")
}
if (!self.formModel.email) {
self.errors.push("Email required.")
} else if (!self.validEmail(self.formModel.email)) {
self.errors.push("Valid email required.")
}
if (!self.errors.length) {
self.initializeForm()
};
e.preventDefault()
},
validEmail: function(email) {
let re = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/
return re.test(email)
},
initializeForm(){
self.formModel = {}
}
}
});
In this manner no matter how many input elements you have in your component you will just need to set the main model object.

Related

How can I check if fields are empty on Send Message button?

<template>
<div>
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" v-model="firstName" placeholder="Enter your name">
</div>
<div class="form-group">
<label for="lastName">Last name</label>
<input type="text" class="form-control" v-model="lastName" placeholder="Enter your last name">
</div>
<div class="form-group">
<label for="message">Type Your message</label>
<textarea class="form-control" v-model="message" rows="3"></textarea>
</div>
<div class="form-group form-check" v-for="number in numbers" :key="number">
<input type="checkbox" :value="number.Broj" v-model="checkedNumbers">
<label class="form-check-label" >{{number.Broj}}</label>
</div>
<button type="submit" class="btn btn-primary" v-on:click="alert" #click="sendMessage">Send message</button>
</div>
</template>
<script>
import http from "../http-common.js";
import userServices from "../services/userServices.js";
export default {
data()
{
return {
firstName: null,
lastName: null,
message: null,
numbers: "",
checkedNumbers: [],
success: 'You have submitted form successfully'
};
},
methods:
{
async sendMessage()
{
await http.post("/message", {firstName: this.firstName, lastName: this.lastName, message: this.message, numbers: this.checkedNumbers});
this.$data.firstName = "",
this.$data.lastName = "",
this.$data.checkedNumbers = [],
this.$data.message = "";
},
alert() {
alert(this.success)
if(event)
alert(event.target.tagName)
},
retrieveNumbers() {
userServices.getNumbers().then(response => {
this.numbers = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
}
},
created() {
this.retrieveNumbers();
}
}
</script>
So I want to add the option of checking input fields when user clicks "Send Message" button. I tried some options but I faield at that. So please I would appretiate if someone would help me. I'm still learning.
I know I have to use v-if and create the method for checking the fields.
So if you would be most kind and help me solve this problem I would be really grateful.
Thank you dev, community <3
Can I please get a concrete answer. Because I'll learn in that way, so please without condescending and "no-answers"
You can do it manually :
<script>
import http from "../http-common.js";
import userServices from "../services/userServices.js";
export default {
data()
{
return {
firstName: null,
lastName: null,
message: null,
numbers: "",
checkedNumbers: [],
success: 'You have submitted form successfully'
};
},
methods:
{
async sendMessage()
{
if(!(this.firstName && this.lastName && this.numbers)) return;
await http.post("/message", {firstName: this.firstName, lastName: this.lastName, message: this.message, numbers: this.checkedNumbers});
this.$data.firstName = "",
this.$data.lastName = "",
this.$data.checkedNumbers = [],
this.$data.message = "";
},
alert() {
alert(this.success)
if(event)
alert(event.target.tagName)
},
retrieveNumbers() {
userServices.getNumbers().then(response => {
this.numbers = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
}
},
created() {
this.retrieveNumbers();
}
}
</script>
Or you can this usefull library
https://vuelidate.js.org/#sub-basic-form
You can simply define a method to check the fields and call that before the HTTP request in the sendMessage method.
You can initialize your data as an empty string "" and have a method like this:
validateForm() {
return this.firstName != "" && this.lastName != "" && this.message != ""
}
Update your sendMessage method to something like this:
async sendMessage() {
const isFormValid = this.validateForm()
if (isFormValid) {
await http.post(....)
...
}
}

Angular5 reactive forms with mailcheck.js

below is HTML code for form
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control"
(blur)="suggestEmail(signupForm.controls['userData'].controls.email.value)"
id="email" formControlName="email">
<span class="help-block" *ngIf="!signupForm.get('userData.email').valid && signupForm.get('userData.email').touched">
please enter a valid email id
</span>
</div>
Below is ts code
constructor(private fb: FormBuilder) {
this.signupForm = this.fb.group({
userData: this.fb.group({
email: [null, [Validators.required, Validators.email]]
})
});
}
ngOnInit() {
}
suggestEmail(email) {
Mailcheck.run({
email: email,
domains: ['gmail.com', 'aol.com', 'hotmail.com', 'yahoo.com', 'rediffmail.com', 'edu', 'msn.com',],
secondLevelDomains: ['domain', 'hotmail'],
topLevelDomains: ["com", "net", "org", "info"],
suggested: function (suggestion) {
console.log(suggestion);
if (suggestion) {
alert(suggestion.full);
console.log(suggestion.full + "dkdjdekjekde")
}
},
empty: function () {
}
});
}
Right now, value of suggestions.full comes in alert if its being called. But I am trying to show suggestions.full in html side, like as a error warning.
Below is link to my stackblitz
stackblitz
To avoid potential problems with access to this within the Mailcheck.run suggested callback, you could save the results of Mailcheck.run, check them and, if appropriate, set an error on your form field.
let check = Mailcheck.run({
email: email,
... other stuff ...
suggested: (suggestion) => {
return suggestion;
},
empty: () => {
return false; // or however you want to handle it...
}
if (check && check.full) {
this.suggestedEmail = check.full;
this.signupForm.get('userData.email').setErrors({ 'has_suggestion': true })
}
// then in your template (using a getter)
<span class="help-block"
*ngIf="f.invalid && f.touched && f.errors?.has_suggestion">
Suggestion: {{suggestedEmail}}
</span>
Please find this stackblitz -- hope it helps!
Instead of using a regular function which will be lost this scope whereas arrow function keeps track of this. Read more about the difference here https://stackoverflow.com/a/34361380/5836034
do something like this
....
suggestion: any;
....
suggestEmail(email) {
Mailcheck.run({
email: email,
domains: ['gmail.com', 'aol.com', 'hotmail.com', 'yahoo.com', 'rediffmail.com', 'edu', 'msn.com',],
secondLevelDomains: ['domain', 'hotmail'],
topLevelDomains: ["com", "net", "org", "info"],
suggested: (suggestion) => {
console.log(suggestion);
if (suggestion) {
alert(suggestion.full);
this.suggestion = suggestion;
console.log(suggestion.full + "dkdjdekjekde")
}
},
empty: function () {
}
});
}
Observe the use of arrow function, to keep track of this scope and also, assigning the value of suggestion to your class variable via
this.suggestion = suggestion
in your template, you can now have access to suggestion like so
<div *ngIf="suggestion">{{suggestion.full}} </div>
Source: https://stackblitz.com/edit/angular-email-checker-bjcrcc

Display data in Vuejs

I need to display only name from request in my form, can't figure out how to do it. I'm just starting with js, need help.
I have tried this {{ request.name }} but doesn't work. {{request}} shows me full data.
const app = new Vue({
el:'#valuation-request',
data() {
return {
step:1,
request:{
name:null,
industry:'{{ $company->industry }}',
valuation_date:null,
similar_comp:null,
total_raised:null,
sales_transactions:null
}
}
},
methods:{
prev() {
this.step--;
},
next() {
this.step++;
}
}
});
If name has a value, it should display as you wrote it. If it's null, nothing will be displayed.
const app = new Vue({
el:'#valuation-request',
data() {
return {
step:1,
request:{
name: null,
industry:'{{ $company->industry }}',
valuation_date:null,
similar_comp:null,
total_raised:null,
sales_transactions:null
}
}
},
methods:{
prev() {
this.step--;
},
next() {
this.step++;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="valuation-request">
{{request.name}}
<hr>
Name: <input type="text" class="uk-input" name="name" v-model="request.name" id="name" placeholder="e.g. John Doe" required>
</div>

Keeping track of added element in an array?

I'm playing around with vue.js and the .vue components, and as newbie, I'm wondering how can I keep track of the element I add in the array.
The situation is the following :
The user add a new element from a form
When he submit, the data are automatically added to a ul>li element, and a POST request is made to the API
When the POST is done, I want to update the specific li with the new data from the server.
The thing is, I can not target the last li because the server can take time to process the request (he do a lot of work), so the user may have added 1, 5, 10 other entries in the meantime.
So how can I do ?
Here's my code so far :
<template>
<form method="post" v-on:submit.prevent="search">
<input type="text" placeholder="Person name" required v-model="name" v-el="nameInput" />
<input type="text" placeholder="Company" required v-model="company" v-el="domainInput" />
<input type="submit" value="Search" class="btn show-m" />
</form>
<ul>
<li transition="expand" v-for="contact in contacts">
<img v-bind:src="contact.avatar_url" width="40px" height="40px" class="cl-avatar" />
<div class="cl-user">
<strong class="cl-name">{{contact.name}} <span class="cl-company">{{contact.company}}</span></strong>
</div>
</li>
</ul>
</template>
<script>
export default {
data () {
return {
contacts: [],
name: null,
company: null
}
},
methods: {
search: function (event) {
this.$http.post('/search', {
name: this.name,
company: this.company
}).then(function (xhr) {
// HERE ! How can I target the exact entry ?
this.contacts.unshift(xhr.data)
})
this.name = ''
this.company = ''
this.contacts.unshift({'name': this.name, 'company': this.company})
},
}
}
</script>
Thank you for your help ! :)
If you know that the name and company fields are unique you could search through the array to find it... otherwise you can just wait to append it to the array until the return function:
search: function (event) {
this.$http.post('/search', {
name: this.name,
company: this.company
}).then(function (xhr) {
this.contacts.unshift(xhr.data)
})
this.name = ''
this.company = ''
},
I finally found a working solution : I use a component instead of <li /> for each entries, and manage the state of these inside the component :
<ul>
<contact-entry v-for="contact in contacts" v-bind:contact="contact"></contact-entry>
</ul>
That way, when I add a new entry in the array (described above), a new instance of the component contact-entry is made.
Inside that component, I did the following :
<script>
export default {
props: ['contact'],
created: function () {
if (this.contact.id === undefined) { // If it's a new contact
this.$http.post('search/name', { // I do the post here
name: this.contact.name,
domain: this.contact.company.name
}).then(function (xhr) {
this.contact = xhr.data // This will update the data once the server has replied, without hassle to find the correct line
})
}
}
}
</script>
That's it ! :) In the parent's component, I removed the xhr request and simplified the method to :
<script>
export default {
data () {
return {
contacts: [],
name: null,
company: null
}
},
methods: {
search: function (event) {
this.name = ''
this.company = ''
this.contacts.unshift({'name': this.name, 'company': this.company})
}
}
}
</script>

Conditional validation in VueJS

I am using VueJS with vue-validator and I have been struggling for hours to do simple conditional validation. The example provided in the documentation does not seem to work, at least not in my case.
What I am trying to accomplish is requiring two input groups (observer_firstName and observer_lastName) if a condition (showObserverEntry) is true and requiring another (role) if it is false.
So, if showObserverEntry is false, role should be required/visible. If showObserverEntry is true, role SHOULD NOT be required or visible, observer_firstName and observer_lastName should be required and visible.
Everything works when the page is loaded and showObserverEntry is set to false, it continues to work when switched to true, but when it goes back to false again validation stops working for role. Peeking at the data output, the validation data changes to validation { } where it initially has data.
Vue instance with other methods removed:
var vm = new Vue({
el: "#scheduleContainer",
validator: {
validates: {
requiredIf: function (val, condition){
return val && condition
}
}
},
data: {
loading: true,
stationId: stationId,
date: initialDate,
dateFormatted: initialDateFormatted,
nextDate: null,
prevDate: null,
entries: [],
requestEntries: [],
roles: [],
roleStaff: [],
showObserverEntry: false,
startPickerDatetime: null,
endPickerDatetime: null,
shiftEntry: {
start: null,
end: null,
role: null,
member: "",
observer: {
firstName: "",
lastName: ""
}
}
},
computed: {
validField: function () {
return this.validation.shiftEntry.observer.firstName.valid &&
this.validation.shiftEntry.observer.lastName.valid
}
},
methods: {
getRoleStaff: function () {
if (this.shiftEntry.role != '' && this.shiftEntry.role != 'observer') {
this.$http.post('/members/schedule/manage/json/roles/staff', {id: this.shiftEntry.role})
.success(function (data) {
this.$set('roleStaff', data.members);
vm.shiftEntry.member = "";
vm.showObserverEntry = false;
vm.shiftEntry.observer.firstName = "";
vm.shiftEntry.observer.lastName = "";
});
} else if (this.shiftEntry.role == 'observer') {
this.showObserverEntry = true;
this.resetFields()
}
else {
this.showObserverEntry = false;
this.roleStaff = [];
}
},
resetFields: function () {
this.roleStaff = [];
this.shiftEntry.role = "";
this.shiftEntry.member = "";
this.shiftEntry.observer.firstName = "";
this.shiftEntry.observer.lastName = "";
},
conditionalField: function (response, type) {
return response === type
}
}
});
Form fields:
<div class="form-group"
v-if="conditionalField(showObserverEntry, false)"
v-class="has-error: validation.shiftEntry.member.invalid">
<label for="member">Member:</label>
<select name="member"
id="member"
v-model="shiftEntry.member"
options="roleStaff"
v-attr="disabled: !roleStaff.length"
class="form-control"
v-validate="requiredIf: conditionalField(showObserverEntry, false)">
<option value="">Select Member</option>
</select>
</div>
<div class="form-group"
v-if="conditionalField(showObserverEntry, true)"
v-class="has-error: validation.shiftEntry.observer.firstName.invalid">
<label for="observer_firstName">First Name:</label>
<input type="text"
id="observer_firstName"
class="form-control"
v-model="shiftEntry.observer.firstName"
v-validate="requiredIf: conditionalField(showObserverEntry, true)">
</div>
<div class="form-group"
v-if="conditionalField(showObserverEntry, true)"
v-class="has-error: validation.shiftEntry.observer.lastName.invalid">
<label for="observer_lastName">Last Name:</label>
<input type="text"
id="observer_lastName"
class="form-control"
v-model="shiftEntry.observer.lastName"
v-validate="requiredIf: conditionalField(showObserverEntry, true)">
</div>
It is because a bug in Vue.js. Reason: If we remove one or more v-model based on certain condition(v-if), then it will make all other validation to deactivate.
Refer the issue :https://github.com/vuejs/vue-validator/issues/69

Categories

Resources