I'm having problems setting the initialValue of a FieldArray component in React Final Form. It works when I set it on the Form component, but not on the FieldArray. Please see below CodeSandbox examples:
On FieldArray:
https://codesandbox.io/s/react-final-form-field-arrays-vq9pz
On Form:
https://codesandbox.io/s/react-final-form-field-arrays-v90nn
I would prefer to have it set on the FieldArray, which seems like it should be possible if I look at the documentation here. Has anyone else come across this?
The implementation of initialValue was introduced in version 3.1.3.
Change the version of react-final-form-arrays to 3.1.3 in the sandbox.
You will also need to change the version of react-final-form to 6.5.2
You can define const customer = { firstName: "test", lastName: "test" }; and then use it in here:
<button type="button" onClick={() => push("customers", customer)}>
Add Customer
</button>
Here is CodeSandbox example https://codesandbox.io/s/react-final-form-field-arrays-vmmf3?fontsize=14.
Usually I will create a mutator like this:
<Form
mutators={{
...arrayMutators,
addCustomer: (_, state, { changeValue }) => {
changeValue(state, "customers", (v) => [
...v || [],
{ firstName: 'abc', lastName: 'efg' },
]);
},
}}
...
and change the Add Customer button onClick={() => form.mutators.addCustomer()}
Related
I am using antd Select and react hook form via 'Controller'. I am populating the Select options from a fetched data with structure;
{
{
"id": "232342",
"term": "hello"
}
{
"id": "232342",
"term": "hello"
}
}
the Select component properly displays the term for selection. However, i want to retrieve both the 'id'and 'term' of the selected and use it to populate another json object.
getValues(" ") retrieves the 'id' only. How do i retrieve and access both the 'id' and 'term'.
Here is a portion of code:
import React from 'react'
import { useForm, Controller } from 'react-hook-form'
import { Select } from 'antd'
const { Option } = Select
export default function PatientRegistrationForm({ options }) {
const { register, handleSubmit, getValues, control, formState: { errors } } = useForm({
defaultValues: {
customer: "",
}
})
const children = []
for (const {id, pt: {term}} of options){
children.push(<Option key={id}>{term}</Option>)
}
// Define the retrieved values from the form
const retrievedID = getValues("customer")
// Use the retreived values to populate this object
const customer = {
customerId = retrievedID
customerName = "nothing happens here"
},
return (
<div className="">
<form onSubmit={handleSubmit(onSubmit)} className="">
<section>
<Controller
control={control}
name="customer"
render={({ field }) => (
<Select {...field} defaultValue=""
bordered={true}
filterOption={true}
className="form-control"
>
{ children }
</Select>
)}
/>
</section>
</form>
</div>
);
}
Thanks in advance for your help.
You have to retrieve the option manually using something like:
const retrievedID = getValues("customer")
const retrievedOption = options.find(option => option.id === retrievedID)
const customer = {
customerId: retrievedID,
customerName: retrievedOption.term
}
thank you #sgarcia.dev for your answer. I know its been a while but i want to put it out here incase it helps someone else. It turns out it had little to do with react hook form. Ant design select component has a prop 'labelInValue' which returns an object containing both the label and value.
I have an antd Modal, i am trying to validate a field and provided validation to it. How can i enable/disable the Ok button based on the validation. If the validation is successful then button should be enabled else disabled.
<Form>
<Modal
title={modalHeader}
okText="ADD FIELD"
cancelText="CANCEL"
visible={visible}
onCancel={onCancelHandler}
onOk={() => onAddFieldHandler(fieldName)}
width={600}
okButtonProps={{disabled:true}}
>
<p>Please provide name</p>
<Form.Item
name="fieldName"
rules={[{ required: true, message: 'Please enter name' }]}
>
<FieldNameInput
placeholder="Field name..."
value={fieldName}
onChange={(event) => setFieldName(event.target.value)}
/>
</Form.Item>
</Modal>
</Form>
You can use onFieldsChange from Antd Forms API togehter with geFieldsError and the okButtonProps from Antd Modal API.
const [form] = Form.useForm();
const [buttonDisabled, setButtonDisabled] = useState(true);
return (
<Modal
...
okButtonProps={{ disabled: buttonDisabled }}
>
<Form
form={form}
...
onFieldsChange={() =>
setButtonDisabled(
form.getFieldsError().some((field) => field.errors.length > 0)
)
}
>
Here is a working Stackblitz.
In my case I had Form inside modal and there is onFieldChange prop when you can pass function to perform some operations due to changes on from so you can sth like that:
const SomeModal = ({ visible }) => {
const [form] = Form.useForm();
const [buttonDisabled, setButtonDisabled] = useState(true);
const handleOk = () => form.submit();
const handleAfterClose = () => {
setButtonDisabled(true);
form.resetFields();
}
const handleCancel = () => ...some action to hide modal;
const handleFormFinish = (values) => {
... some logic here
}
return (
<Modal
title={"Some title..."}
visible={visibile}
onOk={handleOk}
onCancel={handleCancel}
afterClose={handleAfterClose}
okButtonProps={{ disabled: buttonDisabled }}
>
<Form
form={form}
layout="vertical"
name="acceptform"
onFinish={handleFormFinish}
initialValues={{
...initial values here
}}
onFieldsChange={() => {
const actualFieldValues = form.getFieldsValue();
const anyError = form.getFieldsError().some((field) => field.errors.length > 0);
.. some logic if error etc..
if (anyError) {
setButtonDisabled(true);
}
else {
setButtonDisabled(false);
}
}}
>
and of course there is need to have some validators on fields
<Form.Item
label={"someLabel"}
id="field"
name="field"
hasFeedback
rules={[
{
type: "string",
validator: async (rule, value) => inputFieldValidate(value, "custom message")
},
]}
>
and validator looks alike:
const inputFieldValidate = async (value, message) => {
if (someCondition)) {
return Promise.reject(message);
}
return Promise.resolve();
};
here is some nice to know that validator isasync and to make it work without any warnings just handle promises
Having the Form inside the Modal, a way to update modal button status would be just running form instance's validateFields, but there are two things to take into account:
This function is a Promise, so the state must update after an await with the validation results.
I've experienced some looping issues when using onFieldsChange (maybe the validation triggers some kind of field update). Instead, onValuesChange has worked good enough for me.
Running the validation into a setTimeout callback seems to be mandatory. Doing it without the setTimeout returns a validation error even when all the fields are valid because of an outOfDate: true. It seems to be because of how the Antd Form update lifecycle works, and waiting until this process has ended (what we can easily achieve with the setTimeout) solves that problem.
A succesful validation returns the form values object, a failed one returns an errorInfo object with the errors list, the outOfDate status and the current form values. You can use the errors list in the latter to get the validation messages returned by Antd to display more descriptive and specific feedback.
In the end, my approach has this structure:
const MyModal = ({onFinish, ...otherProps}) => {
const [canSubmit, setCanSubmit] = useState(false);
const [form] = Form.useForm();
return (
<Modal
{...otherProps}
okButtonProps={{
disabled: !canSubmit
}}
>
<MyFormComponent
form={form}
onFinish={onFinish}
onValuesChange={() => {
setTimeout(() => {
form
.validateFields()
.then(() => {
/*
values:
{
username: 'username',
password: 'password',
}
*/
setCanSubmit(true);
})
.catch((err) => {
/*
errorInfo:
{
values: {
username: 'username',
password: 'password',
},
errorFields: [
{ name: ['password'], errors: ['Please input your Password!'] },
],
outOfDate: false,
}
*/
setCanSubmit(false);
});
});
}}
/>
</Modal>
);
};
Could someone tell me what my form data's string ends at the comma? I'm sending a form with react with a string with foo, bar but only foo is sent in the form data. This has nothing to do with the database as in the chrome dev tools, under network, I see only one value of the string. Here's a image of my actual views:
Only Wordpress, gets submitted. Noticed the ,?
Some code, in React (I'm using react-select):
<form action="/" method="post">
<Select ref="stateSelect" options={skillsOptions} simpleValue multi={this.state.multi} value={this.state.skillsSelectValue} name="skills" onChange={this.skillsUpdateValue} valueKey="value" labelKey="name" loadOptions={this.getContributors} />
</form>
skillsUpdateValue: function(newValueCnd) {
// var str = newValueCnd.split(',');
this.setState({
skillsSelectValue: newValueCnd
});
this.setState({
skills: newValueCnd
});
},
Am I missing something from the form? Using just Rails, all words great.
Edit:
Input options:
var skillsOptions = [
{ value: 'one', name: 'One' },
{ value: 'two', name: 'Two' }
];
So in my PhoneJS web app, I have a dxList widget, with checkboxes on each item. I want to be able to select multiple items, and then do something with them. I'm trying to bind the 'checked' binding to an observable, but I get an 'undefined' error.
Here's the code for the dxTemplate for the list
<div data-options="dxTemplate:{name:'item'}">
<span data-bind="text: $data.information"></span>
<div data-bind="dxCheckBox: { checked: check_boxes }"></div>
</div>
The problem is that check_boxes is in the viewModel, not the item array. I need to access values in the viewModel. I've tried viewModel.check_boxes, but with no success.
Here's the js code:
AppNamespace.otherView = function (params) {
var viewModel = {
my_list: [
{
key: 'Group 1',
items: [
{ information: 'Test 1' },
{ information: 'Test 2'},
{ information: 'Test 3' }
]
}
],
check_boxes: ko.observable(false),
//...etc
Has anyone had any experience with this, and is there a solution?
Thanks!
Knockout provides special properties to access parent binding contexts. In your case both $parent and $root should work.
More on this topic in Knockout docs: Binding context.
Hypothetical example to illustrate a problem I am having using angular-UI select2. Let's say I have a screen where I want to edit a "game" model. A game, among other things has players. I want to be able to set the players via a select2 drop down menu. Here's some example code:
app.js
$scope.getGamePromise().then(function(results) {
$scope.game = results;
console.log(game.players); //prints [{name:'Joe',age: 15},{name:'Sally',age:16}]
});
$scope.players = [
{
name: 'Joe',
age: 15
},
{
name: 'Fred',
age: 14
},
{
name: 'Sally',
age: 16
},
{
name: 'Lucy',
age: 13
}
]
view.html
<select ngModel="game.players" ui-select2 multiple>
<option ng-repeat="player in players" value="player">{{ player.name }}</option>
</select>
When I want to save this 'game' object, I send the game object up to the server. The server is expecting game.players to be an array of objects. However, what is being sent up is a string. I am moderately familiar with angular, and completely new to select2. How can I get my select2 to set game.players as an array of objects instead of strings?
I guess you find another solution or you don't have the problem anymore. Anyway I post it here:
Use
<input>
instead of
<select>
Example:
<input type="hidden" ui-select2="playersCfg" ng-model="players"/>
And following configuration:
$scope.playersCfg = {
multiple: true,
allowClear: true,
data: { results: Player.query(), text: 'name' },
formatResult: function(item) {
return "<div class='select2-user-result'>" + item.name + "</div>";
},
formatSelection: function(item) {
return item.name;
}
};
Player.query()
is a resource which returns a list of player containing a name (name) and an identifier (id)
Hope it would help somebody!