I'm working with React Final Form, and for some reason, when I try to pass initial values to its initialValues prop, it doesn't work if the keys I use are in the format 'key6.value' - the Field with that name stays empty. It does, however, work if the format doesn't have the . in the middle, e.g. 'key6value'.
Why doesn't initialValues work for these nested fields (fields with names that have the .)? And what can I do to make it pass the initialValues?
I've tested this thoroughly to make sure I identified the issue, and the only difference between having the Fields populate and not has been the . in their name attribute.
You'll need to initialize with the actual nested structure. Not like this:
{
'key5.value': 'init value' // ❌
...
}
Like this:
{
key5: {
value: 'init value' // ✅
}
...
}
Does that help?
Related
I've seen typescript solution with universal handle change function, but in my case it works bad. Need help to understand why this happens.
When I add new product - it adds correctly, but when I try to clear Input manually - first rerender it also changes already added content.
Algorithm to see this mistake: fill inputs, add submit and remove one letter from title input - you'll see that it affects already added title in another state, but only on first rerender
Sandbox: https://codesandbox.io/s/restless-dream-do7bqh?file=/src/App.tsx
The below code-sample may be a solution to achieve the desired objective:
In the handleChange method:
setProduct(prev => ({ ...prev, [name]: value }));
Explanation
The prev value of product is taken as-is
Then, using the ... spread-operator all of prev's props are spread
This is now followed with [name] which is a new prop being added with value as the corresponding value
Any existing prop will be replaced.
Suppose name variable has the value 'title' and value is 'Testing 123', then the product object becomes:
product = {
id: previousValueOfId,
price: previousValueOfPrice,
title: 'Testing 123'
}
Here, previousValueOfId and previousValueOfPrice are supposed to be the values.
Why OP's code did not get the desired result
The code is:
setProduct((prev) => {
(prev as any)[name] = value;
const newValue = { ...prev };
return newValue;
});
This takes the prev product, and changes it's [name] prop.
When prev is changed, it may impact UI elements which are rendered using product.
(NOTE: I am still very new to ReactJS & if this is incorrect kindly update appropriately).
First: This is the project link: https://stackblitz.com/edit/angular-kmadq6
So.. I have the testForm with 3 levels of formGroup, and the last formGroup is an array of formGroups.
(File app.component.ts)..
Thus, i want to click on checkbox and enable the price field.
I didn't know how to get the price control from array of this form group.
I know that i can disable it by using [attr.disable]="variable" but is it mixind TemplateDrivenForm with ReactiveForm, but, if don't have any way to disable it from ReactiveForm way, i'll use this.
Thank you!
Use the method "get". See that you can "concatenate" using dots to reach the control and how we use the "index" "i". perhafs this example help you to understand the reason because we use [formGroupName]="i" in .html
checkboxChange(event,i){
const enabled:boolean=this.testForm.get('price.rentPeriods.'+i+'.checked').value
const control=this.testForm.get('price.rentPeriods.'+i+'.price')
if (enabled)
control.enable()
else
control.disable()
}
You could retrieve the inner form array creating a getter for the form group first, and then accessing the array, as follows:
get InnerFormGroup(){ return this.testForm.controls.price as FormGroup; }
get InnerFormArray(){ return this.InnerFormGroup.controls.rentPeriods as FormArray; }
That way, you can access the array controls anywhere on your component:
onCheckboxSelect(){
this.InnerFormArray.controls; //here you can access the array controls and disable/enable them
}
is there a way to detect if there are any valueChanges for the toggle buttons made to form array which has been binded from dynamic array of objects.
Here, i am getting this.agentDetailsList and this.detailsToggle from the api, if i am in edit mode, this.agentDetails array i am binding to the formArray by using this.detailsToggle as this array has been used to bind in the html for looping. Here even though i made changes to the formarray it is not reflecting.
Basically my requirement is that, if there is any change in this formarray toggles before clicking on save, then API must be called, if there are no changes then api request shouldnt be made. Here i am not able to use valueChanges or statusChanges as both are not working.
Help appreciated.
Thanks in advance
TS:
i have used reactive forms, and the values are getting assigned to the html and the reactive forms is due to the array of object. So, what ever action i perform there must be used for comparing objects with the existing object. So i have used one array of object comparison method. But here the previous value is also getting binded to the new value which has been assigned to the form.
I want the newly edited value and the old value as seperate so that i can compare if the object proerty values are diffrent then i can enable for save.
DEMO: DEMO
TS:
saveDetails() {
this.objectsAreSame(this.agentDetailsList, this.detailsToggle)
console.log(this.agentDetailsList);
console.log(this.detailsToggle);
console.log(this.objectsAreSame,"this.objectsAreSame")
}
}
FORM:
private settingsInfoForm() {
if (!this.agentDetailsList) {
// Add
this.agentSettingsInfoForm = this.FB.group({
agentToogles: this.FB.array([this.detailsToggle]),
});
// this.authService.setDetailsData(this.agentSettingsInfoForm);
} else {
// Edit
if (this.agentDetailsList) {
this.detailsToggle = this.agentDetailsList
this.agentSettingsInfoForm = this.FB.group({
agentToogles: this.FB.array([this.detailsToggle]),
})
}
let settingsInfo = this.agentSettingsInfoForm.valueChanges.subscribe(data => {
this.formEdit = true;
console.log('agentSettingsInfoForm', this.formEdit)
})
}
DEMO
the problem is that you has any FormArray.
//this has no sense
this.FB.array([this.detailsToogle])
Do you want to write ?
this.FB.array(this.detailsToggle.map(x=>this.FB.group(x)))
This is a FromArray of FormGroups
Any way, if you only want to change the boolValue, you don't need create a formArray so complex, you can simply
this.FB.array(this.detailsToggle.map(x=>x.boolValue))
this is FormArray of FormControls
When you has an FormArray is for manage a FormArray. You has some too complex as
<input type="checkbox" [checked]="toggleValue.boolValue" (change)="toggleValue.boolValue = $event.target.checked">
when can be like,e.g. is is a FromArray of FormControls
<input type="checkbox" [formControlName]="i">
Really, you need ask you what data you want get and what data you want change. Tip: Before write nothing in your .html write
<pre>
{{agentSettingsInfoForm.?value |json}}
</pre>
I'm trying to integrate some logic into my web application, which is written using React. I have a textArea component, imported from Semantic-UI, in which I'm trying to pull each new line and store into an array. Currently the textArea component only stores data as a string.
render() {
<Form.TextArea key={input.name} name={input.name} label={input.label} value={this.props.values[input.name] || ""} onChange={this.props.onChange}/>;
where value is a string separated by newline like:
test\ntesting\n123
I tried splitting on a every new line, using the code below, which stores the data in an array, like i desire. But this is replacing my attempts to create a new line [pressing ENTER] with a comma in the textArea, which is not my desire for UX.
value={this.props.values[input.name].split('\n')
My textArea component ends up looking something like this:
test,testing,123
where as my desired result is this:
test
testing
123
How can i achieve my desired textArea component UX while still storing the each new line in an array? Many thanks!
If you only want the array to send it to a db or store in localStorage, you don't need to keep it in state. Keep the normal textarea value in state.
onChange={event => this.setState({ text: event.target.value}) }
When you want to send it to db, you can then convert it to array of strings
onSubmit: () => this.postToDb(this.state.text.split('\n'))
The problem is you're trying to assign value of type array to string prop. I guess, somewhere inside of your TextArea component array converted into a string. Since Array.prototype.toString method returns a string representing array items joined by comma, you have comma-separated string.
You need to split your string only when you're sending it to back-end or using for some other logical purposes, but for TextArea component it's better to keep it as is.
It's hard to tell what you're using the array for, and that might have an influence on the answer.
The easiest way would be to not store the text area's contents as an array, and instead store the value normally to state. If you need to e.g. send it as an array to some backend/db, you can then make the transformation when you send the data. For example:
state = {
value: '',
};
...
onChange = (value) => this.setState({ value });
onSubmit = () => {
const myValueArray = this.state.value.split('\n');
// now make your network request with myValueArray
}
If you really need the array in state, one solution could be to simply duplicate your state by setting two state items when your onChange method gets called e.g.
state = {
value: "", // this is the actual text box value with /n characters
valueArray: [], // this is your array where each newline is an item
};
...
onChange = (value) => {
this.setState({ value, valueArray: value.split('\n')} );
};
Alternatively, you can join the array back when it gets passed to your component. The .join() method will join each array item, optionally inserting a string between each item. e.g.
<Form.TextArea ... value={this.props.values[input.name].join('\n')} />;
Note, depending on your use case, this way might have negative implications on performance
does anyone know how to store user text input data into an array of objects in React Native?
[
{
note: ‘some note’,
created_at: 123456789
},
{
note: ‘another observation note’,
created_at: 123456789
}
]
I'm currently just using basic Asyncstorage. I have a text input field for a user to type in notes. It currently saves it as a string in an array. I want to know how to do this but with an array of objects. Also, how would I add the created_at time stamp?
Thank you :-)
Sounds more like a basic JavaScript question. In the context of React, you would simply store the list of notes in the component state (or application state, if using something like Redux).
Define an onChange event handler function for the text input and call setState with:
onSomeInputChange = (text) => {
const note = {
note: text,
created_at: Date.now()
};
this.setState({ notes: [ ...this.state.notes, note ] });
}
The above assumes you have the state variable notes that holds an array of note objects. Using the spread operator, you can copy all the previous notes to a new array and then add the new note. You have to do that because state is immutable and cannot be modified directly.
Then pass that function to the onChange of your text input component:
<TextInput ... onChange={this.onSomeInputchange} />
Other props have been omitted.