I was using v-model to handle inputs in a form, I had to change it to bind props values, at first input was like
<input type="text" class="form-control" placeholder="" v-model="username">
and now it looks like
<input type="text" class="form-control" placeholder="" v-bind:value="modelData.username" v-on:input="username = $event.target.value">
modelData is coming in props. and it has username.
when Using model, in data, i had defined
data: () => {
return {
username: ""
}
},
and It was working fine, but after changing it to v-bind and v-on,
My question is how I can now get the value of username in methods? as in past, I was getting it as this.username to get the value and also clear it as well but now how I can get username in
methods: {}
I have a button to save input
<button class="btn btn-secondary" type="button" #click="validateFormAndSave($event)">Save</button>
When validateFormAndSave get called I can have this.username right now I cannot get the value? But the Vue Doc says v-model and v-bind:value& v-on:input are the same?
UPDATE:
There can be and cannot be some value already there in username, as it being filled with props value, So v-on:input="username = $event.target.value" don't get the already written value but the only new one you entered? or edit it? Why is it so? is there any method for just to get what anyone typed in there or already been typed?
UPDATE:
This is getting very ambiguous. So for now.
1. I can set v-bind:value, But I cannot get it in methods without editing it.
2. I cannot set this.username = "" and it will not be removed from input as well.
3. #input only get what you newly typed not what already in there
v-model is just syntax sugar for =>
<input :value="modelValue" #input="modelValue = $event.target.value"/>
If you want something else, it's very easy to do. Just change the update side to onInput:
<input
class="form-control"
:value="username"
#input="username = $event.target.value"
>
Then
data: () => {
return {
username: ""
}
},
mounted()
{
this.username = this.modelData.username;
},
methods:{
consoleUsername() {
console.log(this.username);
}
}
The best possible solution can be when you are getting your data from props and also loading it a form for v-models.
Using watch feature of Vue component.
First I added props as
export default {
props: ["vendorModelData"],
and then I pass it through the watch to v-model
watch: {
vendorModelData() {
this.updatePropsValue(this.vendorModelData)
console.log("data updated")
}
},
in this way, it always loads differently when Props get changed. This way I got be using v-model as well as load data from props to it.
I found it useful for me.
Related
I v-model a data in my vue html to validate it in my form , but i also want to use it in other variable too
this is my html
<input class="input-style px-3" :class="{'border-red-error':v$.categoryTitle.$errors.length>0}" type="text"
placeholder="title" :disabled="formIsSending" v-model="DataForValidating .categoryTitle">
this is my js code , but it does not work
const DataForValidating = reactive({
categoryTitle: '',
categorySlug: '',
})
const categoryFormData = {
categoryTitle: DataForValidating.categoryTitle,
categorySlug: DataForValidating.categorySlug,
}
i made categoryFormData reactive too , but it does not work
use #input event and pass a function then store "DataForValidating.categoryTitle"
in another variable
or you can directly use arrow function in #input event to assign that v-model variable to another
i got answer , i need to use watcher
watch:{
'newCategoryData.categoryTitle': function (newVal){
this.categoryFormData.categoryTitle=newVal
},
'newCategoryData.categorySlug': function (newVal){
this.categoryFormData.categorySlug=newVal
},
}
In my project I have antd form which used to add school details. In that form, I have ID field which need to be validated with back-end in onChange when input length = 5, whether that given ID is exists or not.
antd version 4.18.2
Field validations are handled via rules attribute in Form.item.
I use validator function to handle this custom validation.
State values
const [idStatus, setIdStatus] = useState(false); // this value is get by API call.
const [validateStatus, setValidateStatus] = useState("");
Form ID field
<Form form={form} name="form" onFinish={onFinish}>
<Row className="applicationFormContent">
<Col span={8}>
<Form.Item
name="schoolId"
label="School Id"
validateStatus={validateStatus}
rules={[
{
required: true,
message: "Please Provide School ID!"
},
{
len: 5,
message: "School ID must have 5 digits"
},
{
validator: validateId // validator is a function used for custom validation.
}
]}
>
<Input
type={"number"}
maxLength={5}
placeholder="Id - 00000 format"
onChange={(e) => checkSchoolId(e.target.value)}
/>
</Form.Item>
</Col>
</Row>
</Form>
Function triggered in onChange
const checkSchoolId = async (value) => {
try {
if (value.length === 5) {
let response = await checkId(value);
console.log("-----", response.response?.data?.idExists);
setIdStatus(response.response?.data?.idExists);
} else {
setValidateStatus("error");
}
} catch (err) {
console.log(err);
}
};
Validator function used in rules
const validateId = (rule, value) => {
if (idStatus) {
// value return from API call.
setValidateStatus("error");
return Promise.reject("Census Id Already Exist");
} else {
setValidateStatus("success");
return Promise.resolve();
}
};
Problem:
when the input length = 5, I get the value from backend and it updates the state. But validator function is not triggered with that update. Which means Form input is not being re-rendered when update the state variable.
i logged the values and updated values are shown as it is.
But when I type one more number (input-lenght=6), show both validations and then delete one character (now input-length=5), it shows the validation get from back-end value.
how to solve this?
example code sandbox
it's hard to say and please don't leave unlike if it's not true. but when you pass validator method in your rules like below:
validator: validateId
acutely you reference your validator into your method and the data and state that use in this method get initial state from first and never update. for solving this instead of passing reference to validator pass it as arrow-function and also pass your idStatus stat as arguments of method.
something like bellow
validator: (rule, value) => validateId(rule, value, idStatus)
with this approach you force your application to run this method each time want check validator.
There is a method named form.validateFields(['array of input names need to validate']) provided by antd Form for field validations.
With that I was able to re-execute the validation of the schoolId input when response come for idStatus inside a useEffect as below.
useEffect(() => {
// manually validate the field since input is not validated by form once state update.
form.validateFields(['schoolId']);
}, [idStatus]);
With the above way, we can manually trigger validation for particular Form.Item in antd Form wherever we want.
I have a page where users can submit forms. They can choose to add new forms to the page(form 2, 3, 4, 5 of the same form type).
I handle that through:
handleAddPastMainData() {
const pastMainData = this.state.mainData[0].pastMainData;
this.setState({
mainData: {
...this.state.mainData,
pastMainData: pastMainData.push([])
}
})
}
Then I map through pastMainData to display the added form.
What I am having a challenge with is with the handler for saving the data since the form is nested.
My current state is like this:
this.state = {
mainData: [
{pastMainData: []},
]
};
And my handler is:
handleMainInputChange = (event) => {
const name = event.target.name;
const value = target.type === 'checkbox' ? target.checked : target.value;
this.setState(state => {
state.mainData[0].pastMainData[name] = value;
return state
})
};
A sample form input field in my app is:
<Field
label="Main name"
id="pastMainName"
name="pastMainName"
placeholder="Super Awesome FName"
value={state.MainData[0].pastMainData.pastMainName}
onChange={handleMainInputChange}
/>
I assign a key to each form when I map through pastMainData.
So a user can choose to add more than 5 of the above field input and submit.
When the data is submitted, I want the state to look like this:
this.state = {
mainData: [
{pastMainData: [[field1], [field2], [field3]},
]
};
When the user returns, this gives me the option to check number of fields/forms the user has already completed and render them with the saved data.
However, this obviously is not working.
Any way to improve my code and make it more efficient will be very appreciated.
Thanks
Currently when I run the code, on clicking Add Form, it renders the
form but continues to the next page. The call to continue to the next
page is only on the handleSubmit method.
To stop it from continuing to the next page you probably need to e.preventDefault() on that button.
"since the forms are multiple, how do I get the key and use that
particular key in the handleMainInputChange."
Add the key to the Field, or Form. For example:
<Field
key={key}
label="Main name"
id="pastMainName"
name="pastMainName"
placeholder="Super Awesome FName"
value={state.MainData[0].pastMainData.pastMainName}
onChange={handleMainInputChange}
/>
And you should be able to access it like you would any data-attr, if not, you can pass it as a a param to the onChange function.
also, maybe it would be easier to work with a different data structure for your state obj:
this.state = {
forms: {
form1: {},
form2: {},
form3: {},
}
};
may make setting and accessing easier in the long run.
I am having a hard time with antd's form.
I have this select field in this form and I want to get the value from it onChange but somehow not getting it to work properly.
say this is the item for which I want the values
<FormItem
{...formItemLayout}
label={fieldLabels.qcategoryid}
validateStatus={categoryError ? "error" : ""}
help={categoryError || ""}
>
{getFieldDecorator("qcategoryid", {
rules: [{ required: true, message: "Please select Category!" }],
onChange: this.handleCategoryChange
})(<Select>{categoryOptions}</Select>)}
</FormItem>
this is the categoryOptions
if (this.props.categories) {
categoryOptions = this.props.categories.map(item => (
<Select.Option
key={item.categoryid}
value={item.categoryid}
name={item.categoryname}
>
{item.categoryname}
</Select.Option>
));
}
I want both the name of the category and the id
so I created a handleCategoryChange which gets called onChange
and I am able to get the fields I want.
But, it seems that now, I have to click twice on the field to properly select it.
If I click it just once then it does show up in the console. but the field on the form still remains empty. when I click it again, then the field shows up in the form too.
So, what am I doing wrong here.
Ah,yes! Here's the handleCategoryChange function
handleCategoryChange = (value, e) => {
console.log("value is : ", value);
console.log("e : ", e);
this.props.form.setFieldsValue({ qcategoryid: value });
this.setState({
categorySelected: value,
categoryname: e.props.name
});
};
Just to make myself clear.
I need those values before I click submit.
not on submit.
maybe this will help Ant Design form API as of 22nd of May 2022
This was added in v4.20
const Demo = () => {
const [form] = Form.useForm();
const userName = Form.useWatch('username', form);
const { data: options } = useSWR(`/api/user/${userName}`, fetcher);
return (
<Form form={form}>
<Form.Item name="username">
<AutoComplete options={options} />
</Form.Item>
</Form>
);
};
I realize this is super late, but I think this might be what OP was looking for:
https://github.com/react-component/form/blob/3b9959b57ab30b41d8890ff30c79a7e7c383cad3/examples/server-validate.js#L74-L79
To set fields on a form dynamically, e.g. in a child via a callback, you could use
this.props.form.setFields({
user: {
value: values.user,
errors: [new Error('forbid ha')],
},
});
in a parent defined handleSelect method you called from the child on a selected value. you can alternatively use setFieldsValue if you dont want to pass an error field
Try this:
<FormItem
{...formItemLayout}
label={fieldLabels.qcategoryid}
validateStatus={categoryError ? "error" : ""}
help={categoryError || ""}
>
{getFieldDecorator("qcategoryid", {
rules: [{ required: true, message: "Please select Category!" }]
})(<Select onChange={this.handleCategoryChange}>{categoryOptions}</Select>)}
</FormItem>
And on the handleCategoryChange function
handleCategoryChange = (value, e) => {
this.setState({
categorySelected: value,
categoryname: e.props.name
});
};
Basically, changing the onChange from the getFieldDecorator helper to the Select, so it doesn't mess with antd's natural behavior, but gets the value and change on state
I've based this answer on the code to the registration form on their website. Specifically, the handleWebsiteChange function
https://ant.design/components/form/#components-form-demo-register
I have made a helper function to solve this problem, you have to pass the field
name you want to take out from the form and the form object.
const getFieldValue = (fieldName,form) => {
return Form.useWatch(fieldName,form);
}
console.log(getFieldValue("username"))
in above example I had to console updated username value.
demo
A quick response, and hopefully a quick solution. Rather than using onChange you may want to use onSelect/onDeselect handlers, per the documentation (https://ant.design/components/select/):
<Select onSelect={handleCategoryChange} .../>
I have found also that SELECT and other input components, due to their custom html nature operate differently, and so in my forms, I have often created them as dummy fields that are using to alter text/hidden inputs in order to achieve the desired behaviours in complex forms.
Either I am doing something wrong, or the ANT way is mildly annoying.
Hope this helps.
I am trying to set the value of a hidden input with a value of id so that when I submit my form, I have the id. I know that this value is being passed using a param as follows:
<td><router-link :to="{ name: 'editclient', params: { id: client.id }}">Edit</router-link></td>
Then in my EditClient component I have the following hidden input:
<input type="hidden" value="{{this.$route.params.id}}" v-model="id">
The issue is that this won't compile, is there another way to do this?
I can see that the value of my id is set to 1 which is what it should be in this case:
However the issue is that I can't bind this to my hidden input.
Any help is appreciated, thanks
In this case I would probably just use v-model
<input type="hidden" v-model="id">
And then set id either in data or when the route changes.
data(){
return {
id: this.$route.params.id
...
}
}
Just for reference incase someone else hits this issue, I managed to solve this by using a computed attribute in my component:
computed: {
id () {
return this.$route.params.id
}
},