Dynamic name for react-final-form Field - react-final-form

I have 2 forms. When I choose an option on 1st form, the 2nd form is added to the page with the parameters retrieved from backend. Now how can I set the parameter names as react-final-form Field names?
I could not find a way to do this. Where to pass the parameter names?
<Form
onSubmit={onSubmit}
validate={validate}

React Final Form calls your onSubmit function with the values from all the fields in your form. It's totally up to you to transmit the values to your server.
If you're asking how to build the second form, you just add the fields you need to add. So, say you got back from the server that you needed three fields: [ 'name', 'startTime', 'endTime' ]. You'd just loop through that array and add the fields.
<Form onSubmit={onSubmit}>({handleSubmit}) => (
<form onSubmit={handleSubmit}>
{fieldsFromServer.map(fieldName => (
<div key={fieldName}>
<label>{fieldName}</label>
<Field name={fieldName} component="input"/>
</div>
))}
</form>
)}<Form>
Does that help? You don't have to "pass parameters to the form", you just add the Field components that you need.

Call the FinalForm like
<FinalFieldArrayForm onSubmit={this.handleSubmitTemplate} fieldsFromServer={parameters} />
and FinalForm is
import React from "react";
import ReactDOM from "react-dom";
import { Form, Field } from 'react-final-form'
import arrayMutators from 'final-form-arrays'
import { FieldArray } from 'react-final-form-arrays'
import "./styles.css";
const FinalForm = ({onSubmit, fieldsFromServer}) => (
<Form
onSubmit={onSubmit}
mutators={{
// potentially other mutators could be merged here
...arrayMutators
}}
render={({
handleSubmit,
form: {
mutators: { push, pop }
},
pristine,
form,
submitting,
values
}) => (
<form onSubmit={handleSubmit}>
<div className="buttons">
<button type="button" onClick={() => push('records', undefined)}>+</button>
<button type="button" onClick={() => pop('records')}>-</button>
<button type="button" onClick={form.reset} disabled={submitting || pristine}>Reset</button>
</div>
<FieldArray name="records">
{ ({fields}) => (
<div>
{fields.map( (name, index) => (
<div key={`${name}.${index}`}>
<label>{index + 1}</label>
{fieldsFromServer.map( param => <Field key={`${name}.${param}`} name={`${name}.${param}`} component="input" placeholder={`${name}.${param}`} /> )}
<button type="button" onClick={() => fields.remove(index)}>-</button>
<button type="button" onClick={() => fields.insert(index+1)}>+</button>
</div>
))}
</div>
)}
</FieldArray>
<div className="buttons">
<button type="submit" disabled={submitting || pristine}>Submit</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
)
const rootElement = document.getElementById("root");
ReactDOM.render(<FinalForm onSubmit={() => (<div/>)} fieldsFromServer={["firstName", "lastName"]} />, rootElement);

Related

TypeError: Cannot read property 'message' of undefined ---using react-hook-form

I am trying to display an error message when nothing is typed inside the message input form, but when I load the page I get this error 'TypeError: Cannot read property 'message' of undefined'. I am using react-hook-forms. This is my code down below.
import { Button } from "#material-ui/core";
import { Close } from "#material-ui/icons";
import React from "react";
import { useForm } from "react-hook-form";
import "./SendMail.css";
const SendMail = () => {
const { register, handleSubmit, watch, errors } = useForm();
const onSubmit = (formData) =>{
console.log(formData)
}
return (
<div className="sendMail">
<div className="sendMail__header">
<h3>New Message</h3>
<Close className="sendMail__close" />
</div>
<form onSubmit={handleSubmit(onSubmit)}>
<input name='to' placeholder="To" type="text" {...register('to',{required:true})}/>
<input name="subject" placeholder="Subject" type="text" {...register('subject',{required:true})} />
<input
name="message"
placeholder="Message..."
type="text"
className="sendMail__message"
{...register('message',{required:true})}
/>
{errors.message && <p>To is required!!</p>}
<div className="sendMail__send">
<Button
className="sendMail__send"
variant="contained"
color="primary"
type="submit"
>
Send
</Button>
</div>
</form>
</div>
);
};
export default SendMail;
Since v7 the errors object moved to the formState property, so you need to adjust your destructering:
const { register, handleSubmit, watch, formState: { errors } } = useForm();

Automatic "for" and "id"

Because we cannot assume our components are singletons: I am trying to automatically handle giving htmlFor to a label and field. We see below I use useMemo and lodash uniqueId to memoize a unique id for the form on initial render. I had to give useMemo and empty array as second argument so it never re-calculates the id. Is there some automated way to handle this in final-form?
import React, { useMemo } from 'react';
import { Form, Field } from 'react-final-form';
import { uniqueId } from 'lodash';
function TaskForm() {
const id = useMemo(() => uniqueId('_form'), []);
const getFor = name => name + id;
return (
<>
<h3>Create a task</h3>
<Form onSubmit={onSubmit}>
{({ handleSubmit, pristine, invalid, ...rest }) => {(
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor={getFor('firstName')}>First Name</label>
<Field name="firstName" id={getFor('firstName')} component="input" placeholder="First Name" />
</div>
<button type="submit" disabled={pristine || invalid}>Submit</button>
</form>
)}}
</Form>
</>
);
}

Unable to access mutator functions in Wizard form page while using react-final-form

I am trying to create a Wizard form using react-final-form by referring to this code https://codesandbox.io/s/km2n35kq3v. For my use case I need some mutator functions to be used inside my form fields. This example illustrates how to do that - https://codesandbox.io/s/kx8qv67nk5?from-embed.
I am not sure how to access mutator functions in my form steps when I am using a wizard form instead of a single page form.
I tried to combine both the examples by modifying the <Form> component rendered by Wizard.js to pass in the mutators. However I cannot access these mutators in the Wizard form pages.
In Wizard.js
return (
<Form
mutators={{
// potentially other mutators could be merged here
...arrayMutators,
}}
render={({
handleSubmit,
submitting,
values,
pristine,
invalid,
form: {
mutators: {push, pop, remove},
},
}) => {
return (
<form onSubmit={handleSubmit}>
Another file index.js
<Wizard
initialValues={{ employed: true, stooge: "larry" }}
onSubmit={onSubmit}
>
<Wizard.Page>
<FieldArray name="customers">
{({ fields }) =>
fields.map((name, index) => (
<div key={name}>
<label>Cust. #{index + 1}</label>
<Field
name={`${name}.firstName`}
component="input"
placeholder="First Name"
/>
<span
onClick={() => fields.remove(index)}
style={{ cursor: "pointer" }}
>
❌
</span>
</div>
))
}
</FieldArray>
</Wizard.Page>
</Wizard>
It errors out - remove is undefined in index.js
Look at this working example: https://codesandbox.io/s/znzlqvzvnx
changes I have made:
Wizard.js
static Page = ({ children, mutators }) => {
if(typeof children === 'function'){
return children(mutators);
}
return children;
};
...
<form onSubmit={handleSubmit}>
{
// activePage
<activePage.type {...activePage.props} mutators={mutators} />
}
...
index.js (only first <Wizard.page>)
<Wizard.Page>
{
({ upper }) => (
<React.Fragment>
<div>
<label>First Name</label>
<Field
name="firstName"
component="input"
...
</div>
</React.Fragment>
)
}
</Wizard.Page>

Form validation on non form field angular2

im quite new with angular2, but i seem to manage ok for a beginner. However, i'm stuck on some validation issues. i want to validate a component that is not a form field (e.g. input, select e.t.c).
I'm using a bootstrap dropdown which uses an unsorted list.
dropdownButtons.html
<div class="btn-group" dropdown>
<button type="button" class="btn btn-default" dropdownToggle >
{{ selected ? selected : 'Type...'}}
</button>
<ul class="dropdown-menu" dropdownMenu>
<li *ngFor="let value of values;let i = index" (click)="onChange(value)">
{{value.label}}
</li>
</ul>
</div>
dropdownButtons.component.ts
import {Component, EventEmitter, Output, Input, Injectable} from '#angular/core';
import { DROPDOWN_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
#Component({
selector: 'dropdown-buttons',
template: require('./dropdownButtons.html'),
directives: [DROPDOWN_DIRECTIVES]
})
#Injectable()
export class DropdownButtons {
#Input()
values: DropdownValue[] = [{ "value": "RSS", "label": "RSS" },{ "value": "REST", "label": "REST" }];
#Input()
selected : string;
#Output()
select: EventEmitter<DropdownValue>;
constructor() {
this.select = new EventEmitter();
}
onChange(type) {
this.select.emit(type);
}
}
export class DropdownValue {
value:string;
label:string;
constructor(value:string,label:string) {
this.value = value;
this.label = label;
}
}
My form looks like this.
<form (ngSubmit)="onSubmit()" #refererform="ngForm">
<div class="form-group">
<label for="inputUrl">Url</label>
<input type="text" class="form-control" id="inputUrl" placeholder="Url" required
[(ngModel)]="model.url" name="url">
</div>
<div class="form-group">
<dropdown-buttons [(selected)]="model.type" (select)="onSelect($event)" ></dropdown-buttons>
</div>
<div class="form-group" ng-show="showDetails" *ngIf="isShown()">
<label for="header">Header</label>
<textarea placeholder="Default Input" class="form-control" id="header"
[(ngModel)]="model.header" name="header"></textarea>
</div>
<div class="form-group" ng-show="showDetails" *ngIf="isShown()">
<label for="payload">Payload</label>
<textarea placeholder="Default Input" class="form-control" id="payload"
[(ngModel)]="model.payload" name="payload"></textarea>
</div>
<button type="submit" class="btn btn-danger" >Submit</button>
</form>
I tried to use ngModel (using required in the tags) and the FormGroup option, where i define some formcontrols. It works fine with form controls, but i can't seem to figure out how i validate non form components, is it even possible?
thanks in advance.

Gridmvc filtering without query in url

I'm using GridMvc and I'm filtering data. I'd like to hide filter query in the url like http://www.mypage.com/Overview?Name=yyy
My form is defined as:
<form class="form-inline" method="POST" action="#Url.Action("Filter", Request.QueryString)">
<div class="form-group>
#Html.LabelFor(c => c.Name)
#Html.TextBoxFor(c => c.Name, new { placeholder = "Filter", #class = "form-control" })
<button type="submit" class="btn btn-default"><i class="glyphicon glyphicon-search"></i> Search</button>
</div>
</form>
And the action
[HttpPost]
public ActionResult Filter(FilterModel model)
But I always see the query. It's possible to hide query string?
You cound hide your query if you put all you data in hidden fields instead of Request.QueryString.
I mean if your Request.QueryString looks like param1=test1&param2=test2 you should render you view like this:
<form class="form-inline" method="POST" action="#Url.Action("Filter")">
<input type="hidden" name="param1" value="test1" />
<input type="hidden" name="param2" value="test2" />
<div class="form-group>
#Html.LabelFor(c => c.Name)
#Html.TextBoxFor(c => c.Name, new { placeholder = "Filter", #class = "form-control" })
<button type="submit" class="btn btn-default"><i class="glyphicon glyphicon-search"></i> Search</button>
</div>
</form>
MVC binding will bind all hidden values on POST according to name property of this hidden inputs.
You should just fill inputs value (replace test1 and test2 with your values from Request.QueryString)

Resources