Update form data based on a method in VueJS - javascript

I am using VueJS and I have a form with two fields. The user is required to enter the first field, and I want the value of second field to be calculated using the value from first field and passing it through a method.
HTML
<div id="app">
<input type="text" v-model="value.label">
<input type="text" v-model="value.slug">
<!-- Slug value to display here -->
<br /><br />
{{value}}
</div>
Javascript
new Vue({
el:'#app',
data:{
value:{
label: '',
slug: '' // This value is calculated by passing label to santiize()
}
},
computed: {
},
methods: {
sanitize (label) {
return label+'something'
}
}
});
The user enters the first field which updates value.label
We need to pass value.label through sanitize() method and update value.slug . This should also immediately show up in the form field.I don't know how to do it. So, if the user types nothing in the form field it will have an automatic value returned as described.
Along with that it would have been awesome, if we allow the user to bypass what the santize function returns, if the user decides to type the slug value himself in the form field. So, if the user decides to type, the typed value will be set.
I created this fiddle for it - https://jsfiddle.net/9z61hvx0/8/

I was able to solve the problem by changing the data structure a bit and adding a watcher to 'label...
new Vue({
el:'#app',
data:{
label:'',
slug: ''
},
computed: {
computedSlug () {
return this.value.label+'Manish'
}
},
watch: {
label: function () {
this.slug = this.sanitize(this.label)
}
},
methods: {
sanitize (label) {
return label+'something'
}
}
});
Any other more sophesticated answers are most welcome :)

Related

Vuelidate "required" ignoring value attributed in JS

I created a wizard form which uses Vuelidate to validate it's fields. The big majority of the fields have only the "required" function, so my validations are something close to this:
validations() {
if (this.currentStep === 0) {
return {
person: {
name: {
required,
},
age: {
required,
},
}
}
} else if (this.currentStep === 1) {
return {
person: {
street: {
required,
},
city: {
required,
},
state: {
required,
},
}
}
The thing is, I am receiving this data from an API, so the user can either fill the fields himself, or let the machine do it for him. When I receive the data, I make this attribution in a function in JS close to the following:
attributeData():
this.person.name = apiData.name;
this.person.age = apiData.age;
this.person.street = apiData.street;
this.person.city = apiData.city;
this.person.state = apiData.state;
If the user types the info, then everything works fine. If I receive the info from the API, then I get the error as if the input was empty.
This is how every field in my HTML is organized:
<b-form-group label="Name">
<b-form-input
v-model="person.name"
type="text"
size="sm"
:class="{
'is-invalid':
submitted && $v.person.name.$error,
}"
></b-form-input>
<div
v-if="submitted && $v.person.name.$error"
class="invalid-feedback"
>
<span v-if="!$v.person.name.required"
>Name is required.</span
>
</div>
</b-form-group>
Any idea of why Vuelidate can't recognize the values when I attribute them directly in JS? I've made this exact same way in another page and it worked. In DevTools even the $model of Vuelidate has the value that came from the API.
This error may occur if you have two elements using the same identifier.
Example:
data: {user_id: null} and setted v-model="user_id" in one input.
And another element input with: id:user_id
Beware if you are not manipulating the value and then it lost the reference, example:
data: {user: {name: null}}
And you filled it by API but latter in created or mounted put something like:
this.user = {}
The reference user.name was gone and validation can't work anymore.

Vue: Check form input is changed by user

I am new to Vue and want to achieve below result.
I have a form of data and a save button, before the page loads, it will fetch database and fill the form data. Because all the form data are filled, the save button is disabled and the user can not click unless the user change some data, then it knows the form data has changed, the save button will no longer be disabled and can be saved.
I know that should use watch property, but actually how I can implement this?
Thank you guys!
The form data is like this
data(){
return {
form: {
firstName: "",
lastName: ""
}
}
}
You can do something as below by having the two different objects actual and modified.
Here I have used underscore js for deep clone or isEqual, so don't forget to import.
computed: {
// Use is property for the save button to enable or disable
isDataChanged: function() {
return _.isEqual(this.actualForm, this.modifiedForm);
}
},
data() {
return {
actualForm: {
firstName: "",
lastName: ""
},
modifiedForm: {
firstName: "",
lastName: ""
}
}
},
methods: {
fetchData: function() {
// get data and assign it to actual form
this.actualForm = responseData;
this.modifiedForm = _.cloneDeep(this.actualForm) // this will create the new instance
}
}
You can use a watch on form like this below. You can also use deep:true if you need to watch nested property within form.
watch: {
form: {
deep: true,
handler(val) {
// Enable save button here. You can also evaluate any other condition to enable
}
}
}

Returning data to nested field from computed

I am creating a blog article creation field, in which each field is gathered into fields: {} object.
data: {
fields: {
title: '',
slug: ''
}
},
I want to take the title and use a slugify method on that value, from which the computed should return the end-slug into the slug input.
This would work on a non-nested field:
computed: {
slug: function () {
return this.slugify(this.fields.title)
}
},
How can I access the nested field from computed?
Inputs:
<input type="text" class="form-control"
v-model="fields.title" placeholder="Enter your title">
<input v-model="fields.slug" type="text" class="form-control" disabled>
I need to use v-model on both inputs.
This works well and i get the slug, the problem is is that the data in fields.slug is not changing. How do I get my computed slug value into my fields.slug?

Understanding the order of properties execution in Vuejs [duplicate]

This question already has answers here:
Access vue instance/data inside filter method
(3 answers)
Closed 2 years ago.
I'm creating a simple Vuejs div component (to show a specific value) which needs to receive: a lists, a placeholder and a value as props. What I'm trying to do is displaying the value with the data from my database, if the user picks a new value from the lists, it should take that new value and display it. However, if the user never picks a new value and the data from the database is empty, it should display the placeholder.
So I have used filters to achieve this. However, it outputs an error: "Cannot read property 'lists' of undefined", which comes from the filters (I know because it outputs no error if I comment out the filters). When I changed the filter to this:
filters: {
placeholderFilter () {
return this.placeholderText || this.placeholder
}
}
It says:""Cannot read property 'placeholderText' of undefined"". So I was wondering if the filters properties executed before the data and props properties. What is the execution order of them? I have attached some of the relevant code down below. Anyway, If you could come up with a better way to achieve this. I would appreciate it!
Here is my component:
<template>
<div>{{ placeholderText | placeholderFilter }}</div>
<li #click="pickItem(index)" v-for="(list,index) in lists" :key="index">{{ list }}</li>
</template>
<script>
export default {
props: {
lists: {
type: Array,
required: true
},
value: {
type: [String, Number],
default: ''
},
placeholder: {
type: String,
default: ''
}
},
data () {
return {
selected: -1,
placeholderText: this.value || this.placeholder
}
},
methods: {
pickItem (index) {
this.selected = index
}
},
filters: {
placeholderFilter () {
return this.lists[this.selected] || this.placeholderText || this.placeholder
}
}
}
</script>
And this is where I use it:
<my-component
placeholder="Please type something"
value="Data from database"
lists="['option1','option2','option3']"
>
</my-component>
Filters aren't bound to the component instance, so they simply don't have access to it through the this keyword. They are meant to always be passed a parameter and to return a transformed version of that parameter. So in other words, they're just methods. They were removed in Vue 3 entirely probably for that reason.
And yeah, what you're looking for here is a computed!

Two way binding in render function in Vuejs

I'm building an application in Vuejs where I'm creating a render function for input fields. I'm emitting an input event to bind with v-model. I can see values are getting assigned while I assign/insert any values, but when I assign the other way i.e. assigning any value to v-model for input fields it shows empty or it shows the placeholder values if it is available
Here is my code:
createElement('input', {
class: 'form-control m-input',
attrs: { type: this.type, placeholder: this.placeholder },
on: {
input: (event) => {
this.$emit('input', event.target.value)
}
}
})
In props I have:
props: {
label: String,
type: String,
placeholder: String,
},
and while declaring components I do:
<nits-input
label="Email"
type="email"
placeholder="Enter your email"
v-model="email"
>
</nits-input>
In data I'm trying to assign the values:
data() {
return {
email: 'test#example.com',
}
},
How can I achieve assigning values to v-model and displaying it inside the respective fields. Help me out with this. Thanks.
v-model is really just shorthand for having a value prop and emitting an input event.
So in addition to your existing props, you need to add a value one:
props: {
label: String,
type: String,
placeholder: String,
value: String
},

Categories