How to bind values to dynamic controls in react - reactjs

I am loading form controls dynamically by making 2 api calls. First api to get form control's list and second api to get data for the controls loaded previously.
First half works fine and i am able to load controls dynamically,
schema:
[{ id: 1, input: 'TextBox'},
{ id: 2, input: 'TextArea'}]
code:
fields.map((type: any, i: any) => {
switch (type.input) {
case 'TextBox':
return (<input type="text" id={type.id}> />)
case 'TextArea':
return (<textarea itemType="text" id={type.id}> />)}});
Above code works fine and I am able to create form controls.
Next part is binding value to the dynamic controls, I make another API call to get data and I should map id field and bind data
schema:
[{ id: 1, value: 'testTextBox'},
{ id: 2, value: 'testTextArea'}]
How can I bind data to the controls now?
I have tried using state, but not able to achieve that.
or i can update first schema and add value key to it after i get second api response
something like below,
fields = [{ id: 1, input: 'TextBox', value: 'testTextBox'},
{ id: 2, input: 'TextArea', value: 'testTextArea'}]
Please suggest how to loop and add value key to fields array?

use:
setState({})
create the controls binded to state as:
(<input type="text" id={type.id}> value={this.state.id}/>)
upon receiving the values set it in the state as:
this.setState({id: value});

Related

How can i add more than one new Column to a React-Data-Grid?

Hi for A Project i need the user to select the Columns that should be displayed in the React Data Grid. Some Columns might be preset ,others may be added later. However i tryed, it won´t work for more than one added Column eventhough the state is set accordingly and no error is displayed
The new Column will be Selcted by a Selector.This will than be added to the State of the tableclass.
If tried passing it down by props which forced the render method but it did not updated the columns more than once either.
I used different/same keysets. Sames will be recognised if it was the first new Column.
I tried to debug it wether there is any Reason to classify nextColumns as not changed but it did´t bring me any closer.
The state.columns while in render()
0: {key: "date", name: "Date"} ->Preset
1: {key: "date", name: "Date1"} ->Added and created
2: {key: "ffd", name: "Testfdg2"}->Added to state not created
3: {key: "test", name: "Test3"} ->Not created
4: {key: "test", name: "Test4"}
5: {key: "test", name: "Test5"}
6: {key: "test", name: "Test6"}
length: 7
__proto__: Array(0)
ComponentCall
<ReactDataGrid
columns={this.state.columns}
rowGetter={i => this.handleRowGetter(i)}
rowsCount={this.rowsCount()}
minHeight={500}
minColumnWidth={10}
onGridSort={(sortColumn, sortDirection)=>this.gridSort(sortColumn, sortDirection)}
toolbar={
<Toolbar enableFilter={true}
/>}
onAddFilter={this.handleFilterChange}
onClearFilters={this.handleOnClearFilters}
onRowDoubleClick={(click,row) =>{this.handleClick(click,row)}}
/>
So the Goal would be to create all the Columns according to the State
If more Code is nessesary i´l gladly provide it
Greeting Jonathan
From docs:
key: A unique key to distinguish each column
You need to use different values for key. So each key is uniq
Ok solved it
in line ca. 5804 in react-data-grid.js
if (!ColumnMetrics.sameColumns(this.props.columns, nextProps.columns,this.props.columnEquality) || nextProps.minWidth !== this.props.minWidth) {
var columnMetrics = this.createColumnMetrics(nextProps);
this.setState({ columnMetrics: columnMetrics });
}
this.props.columns will be the same as next props.columns thus columnMetrics will not be updated.
in line ca. 6500 in react-data-grid.js
this.setupGridColumns = function () {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0]:_this2.props;
var columns = props.columns;
if (_this2._cachedColumns === columns) {
return _this2._chachedComputedColumns;
}
further more _this2._cachedColumns will be the same as props.columns thus cachedComputedColumns is returned
So no real update to the ColumnMetrics -> No Visual Update. Even though props and state are set right.
So excluding the if and changing the return statement will let u add new Columns to your Table

How to reuse subresource data for referenced inputs in React-admin?

In react-admin documentation the use of ReferenceArrayInput is for this kind of data structure:
{
id: 1,
groups: [1, 2, 3]
}
And then:
<ReferenceArrayInput source="groups" reference="groups" allowEmpty>
<SelectArrayInput optionText="name"/>
</ReferenceArrayInput>
Using a custom json data provider, it will be make this request:
https://example.com/api/groups/?ids=[1,2,3]
or if the API doesn't support WHERE IN, it will be do individual calls for each id:
https://example.com/api/groups/1
https://example.com/api/groups/2
https://example.com/api/groups/3
But if I have the following data structure:
{
id: 1,
name: "Pepito Perez",
groups: [
{ id: 1, name: "HR"},
{ id: 2, name: "IT"},
{ id: 3, name: "FINANCE"}
]
}
I have the name field already, so I don't want make additional requests.
When I go to the edit view react-admin performs almost 70 requests unnecessary.
How can I avoid that? there's a way to reuse the data?
Also is tricky use ReferenceArrayInput component with an array of objects, I have to add a nonsense format prop to make it works: format={v => (v ? v.map(i => (i.id ? i.id : i)) : [])}
Guess it's related to the first problem.
Thanks in advance!
If the choices is not meant to be fetched, ReferenceInput is not what you want. You need only a SelectInput with programmatic setted choices. You can achieve that with FormDataConsumer:
<FormDataConsumer>
{({ formData, ...rest }) =>
<SelectArrayInput
source="selectedGroups"
optionText="name"
choices={formData.groups}
{...rest}
/>
}
</FormDataConsumer>
Note a different source, probably setting as groups, equal to choices "source", after first selected group, would result in a re-render, letting choices values equal to the single selected group.
That's almost exactly the use case of FormDataConsumer in documentation:
https://marmelab.com/react-admin/Inputs.html#linking-two-inputs

reactjs pre-select radio button

I have a section in Client`s panel to agree (or not) to receive promo emails.
I set this as a choice of two radio buttons, yes or no.
Technically everything is working just fine, I can store proper information in the DB but the initial state of radio buttons is not showing. The proper value is being sent ot its 'parent' but it seems it's not passed down to the actual form.
What I would like to achieve is the initial radio button being checked (true, false):
The info is being sent (in line 52, [PROMO_CONSENT]: promo_consent):
[PROMO_CONSENT_FORM]: {
label: _t(panelMessages.promos),
data: Promo,
form: {
formId: PROMO_CONSENT_FORM,
data: {
[PROMO_CONSENT]: promo_consent
}
}
}
but then it doesn't seems to show anywhere else. To manage the states of radiobuttons, component FormChoiceGroup is being called component: FormChoiceGroup,.
[PROMO_CONSENT_FORM]: {
formId: [PROMO_CONSENT_FORM],
endpoint: '/accounts/set_promo/',
fields: [
{
name: PROMO_CONSENT,
label: _t(panelMessages.promoLabel),
component: FormChoiceGroup,
type: 'radio',
isRequired: false
}
]
}
It's a lot of code, if anyone feels like going through it, I'd appreciate it.
Block:
Panel main block
Form:
Panel form, the part of consent starts at line 96
ChoiceGroup:
Component to manage radio buttons
I had to send NOT a boolean value, but turn it into a string, to send literal "true" or "false" and not true/false.
I set up a const that checked the status of the variable and then assigned it with literal values:
const val = this.state.formData[field.name] == false ? "false" : "true";
This simple thing did the trick.

Accessing the value of a child component redux-form

I have a form created using redux-form and have a requirement for display and filtering based on selections within the child objects of the form (being mapped using a FieldArray). The form data json structure is something like:
{
name: "my form",
selection: "1"
date: "02/02/2020",
children:
[{
childName: "child2",
childSelection: "1",
grandchildren: [{
grandchild: "3"
}]
},
{
childName: "child2",
childSelection: "1",
grandchildren: [{
grandchild: "2"
}]
}
]
}
On the actual form I have a dropdown list for the field selection, childSelection and grandchild
const mapStateToProps = (state) => {
const selector = formValueSelector(FORM_NAME);
const selection= selector(state, "selection")
...
I want to be able to filter the grandchildren dropdown whenever childSelection changes, amongst other UI requirements.
I understand that redux-form fires an onChange event, and I have written a selector like the above to capture the change of selection for the top level which works well, but when it comes to the child/grandchild - how do I know which item has changed to effect the filter (ie pass the child selection into the selector for the dropdown that drives the grandchildren list?

ReactJS: where to put validation logic in a form with "nested" composite components?

I'm new to ReactJS and am unsure about the best place to put validation logic that is needed both by nested child components in my form, and the overall "parent" form component itself. Here is a over-simplified example that illustrates my question...
I have a object like this that represents a pet owner:
{
name: 'Jon Arbuckle',
pets: [
{ name: 'Odie', type: 'dog' },
{ name: 'Garfield', type: 'cat' }
]
}
I'm using a composite component called <PetOwnerForm> to render a form for editing this data. <PetOwnerForm> renders something like this:
<input type="text" value={name} />
<PetList value={petOwner.pets} />
<PetList> is a composite component that renders this:
<PetListItem value={this.props.value[i]} /> // Render this for each pet...
// buttons for adding/deleting pets
<PetListItem> renders something like this:
<input type="text" value={this.props.value.name} />
<PetTypePicker value={this.props.value.type} />
Lastly, <PetTypePicker> renders a <select> with <option>s for pet types.
<PetTypePicker> needs to know how to validate the selected type so it can display an inline error message (e.g., ensure that a value is selected).
However, <PetOwnerForm> also needs to know how to validate the pet type because it needs to know how to validate the entire object (on load, each time the form is updated, and before submitting the data back to the server). If any field is invalid, the "Save" button should be disabled.
So where, for example, should the "is a valid pet type selected?" logic go? (Bear in mind that this is a trivial example; in reality I have many fields like this and nested composite components).
The options I see so far are:
A) Replicate the validation logic for pet type (or whatever field) both in <PetOwnerForm> and <PetTypePicker>. This might just be a matter of calling the same, shared validation function in both places:
//PetOwnerForm.js:
validate(petOwnerObj) {
Util.isPetTypeValid(petOwnerObj.pets[i]) // for each pet
// validate the other properties in petOwnerObj...
}
//PetTypePicker.js:
validate(petType) {
Util.isPetTypeValid(petType)
}
B) Use custom PetOwner, Pet, and PetType models that have their own validators. This way you can always ask a model to validate itself, regardless of where it is. Maybe this would look something like this:
{
name: { value: 'Jon Arbuckle', isValid: ()=>{...} },
pets: [
{
name: { value: 'Garfield', isValid: ()=>{...} },
type: { value: 'cat', isValid: ()=>{...} }
},
...
]
}
C) Modify PetOwnerForm.js go recurse the pet owner object, validating each value, and setting an 'errors' property that child components can reference, resulting in an object like this:
{
name: { value: 'Jon Arbuckle asdfasdfasdf^^', errors: ['Too many characters', 'Contains invalid character']] },
pets: [
{
name: { value: '', errors: ['Required value missing'] },
type: { value: 'tree', errors: ['Invalid pet type'] }
},
...
]
}
Which option is recommended for React apps (or is there another option)?
It's a nice elaborate question. This question is not specific to ReactJS applications. It applies to all frameworks that follow component model.
Following are my recommendations:
Differentiate between action driven validation and data format validation.
Low level components are aware of data format they accept, so they must validate for it. For example, postal-code, email, phone, SSN etc have fixed formats and their corresponding components must validate for the right input format.
Low level components are not aware of actions being performed on the overall data. For example, selection of pet-owner-type can be mandatory for "create" pet-owner action but can be optional for "save draft" action. So, low level components which are not aware of end action must not perform action driven validations.
Action driven validation must be performed by the higher level component aware of action, for example PetOwnerForm. Such validation result must be notified to low level components so that they can display appropriate errors. Every low level component must have an error state to support it.

Resources