This is my component with an AntD Form in it.
import React, { PureComponent } from 'react';
import { Form, Input, Button } from 'antd';
import './home-page.scss';
class HomePageContainer extends PureComponent {
render() {
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 14 }
};
const buttonItemLayout = {
wrapperCol: { span: 14 }
};
return (
<div className='contact-company-container'>
<div className='contact-company-card-container'>
<div className='contact-company-card'>
<p>some text</p>
<p>another text</p>
<Form layout='inline'>
<Form.Item label='Pnone Number' {...formItemLayout}>
<Input placeholder='+77 926 12' />
</Form.Item>
<Form.Item label='Email' {...formItemLayout}>
<Input />
</Form.Item>
<Form.Item {...buttonItemLayout}>
<Button>Отправить</Button>
</Form.Item>
</Form>
</div>
</div>
</div>
);
}
}
export default HomePageContainer;
How do I put the two Inputs and the Button on the same (horizontal) level? That is I want them right to each other with no gaps.
Tried setting both labelCol and wrapperCol to { span: 24 } that leaves the Button on the next line.
This is how I currently solved it. Based on the 'Advanced Search' example on https://ant.design/components/form.
Maybe it wasn't the best solution to put an empty ( ) label above the Button. Suggestions are welcome.
class HomePageContainer extends PureComponent {
render() {
const formItemLayout = {
labelCol: { span: 24 },
wrapperCol: { span: 24 }
};
const buttonItemLayout = {
labelCol: { span: 24 },
wrapperCol: { span: 24 }
};
return (
<div className='contact-company-container'>
<div className='contact-company-card-container'>
<div className='contact-company-card'>
<p>abcdef</p>
<p>ghjklu</p>
<Form layout='inline'>
<Row gutter={24}>
<Col span={8}>
<Form.Item label='phone' {...formItemLayout}>
<Input placeholder='+77 926 12' />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label='email' {...formItemLayout}>
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label=' ' {...buttonItemLayout}>
<Button>Send</Button>
</Form.Item>
</Col>
</Row>
</Form>
</div>
</div>
</div>
);
}
}
Related
I am trying to use react hook form for user input to upload file
import "./styles.css";
import { useForm, Controller } from "react-hook-form";
import {
Col,
Row,
Form,
FormGroup,
InputGroup,
Input,
Container,
Button
} from "reactstrap";
export default function App() {
const onSubmit = (data) => {
console.log(data);
};
const { control, handleSubmit } = useForm();
return (
<Container>
<Form onSubmit={handleSubmit(onSubmit)}>
<Row className="m-3">
<Col>
<FormGroup row className="mr-md-1">
<InputGroup className="mb-3">
<Controller
name="itemlist2"
control={control}
render={({ field: { ref, ...field } }) => (
<Input
{...field}
type="file"
required
innerRef={ref}
onChange={(e) => {
field.onChange(e.target.files);
}}
/>
)}
/>
</InputGroup>
</FormGroup>
</Col>
</Row>
<Button color="primary" className="mr-1">
{"Save Changes"}
</Button>
</Form>
</Container>
);
}
Check on https://codesandbox.io/s/affectionate-moon-dmn8q
I get
I'm not very familiar with reactstrap, but i think you have to omit the value prop which is part of field. You can’t set the
value of an input with type="file". Check this answer for more infos.
<Controller
name="itemlist2"
control={control}
render={({ field: { value, ...field } }) => (
<Input
{...field}
type="file"
required
innerRef={field.ref}
onChange={(e) => {
field.onChange(e.target.files);
}}
/>
)}
/>
The issue is due to the fact that you are using a controlled input and not passing value to render it out on onSubmit.
Use { field: { value, ...field } } as props to the render method and it will set the 'value' property on 'HTMLInputElement' otherwise it will only pass an empty string which is in conflict with a file type data.
It should be like this <input type="file" value="c:/js.txt"/> but you are doing like this <input type="file"/>
Complete Code:
import "./styles.css";
import { useForm, Controller } from "react-hook-form";
import {
Col,
Row,
Form,
FormGroup,
InputGroup,
Input,
Container,
Button
} from "reactstrap";
export default function App() {
const onSubmit = (data) => {
console.log(data);
};
const { control, handleSubmit } = useForm();
return (
<Container>
<Form onSubmit={handleSubmit(onSubmit)}>
<Row className="m-3">
<Col>
<FormGroup row className="mr-md-1">
<InputGroup className="mb-3">
<Controller
name="itemlist2"
control={control}
render={({ field: { value, ...field } }) => (
<Input
{...field}
type="file"
required
innerRef={field.ref}
onChange={(e) => {
field.onChange(e.target.files);
}}
/>
)}
/>
</InputGroup>
</FormGroup>
</Col>
</Row>
<Button color="primary" className="mr-1">
{"Save Changes"}
</Button>
</Form>
</Container>
);
}
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();
I'm building a simple html form using "react-hook-form" library: https://react-hook-form.com/
I've incorporated "react-bootstrap-typeahead" into the html form but haven't been able to register this component with 'useForm' hook. Hence, "react-bootstrap-typeahead" input data is ignored during onSubmit.
"react-bootstrap-typeahead" doesn't provide a "name" prop which makes it difficult to register the component.
I've read the 'useForm' documentation on the different options for registering this type of components but still don't understand how to achieve this: https://react-hook-form.com/get-started#Registerfields
Does anybody have faced such challenge before?
It would be great to see a working example to get a better idea on how to implement "react-bootstrap-typeahead" + "react-hook-form" in my application. Thanks!
Here's my sample code:
import useForm from 'react-hook-form';
import { Typeahead } from 'react-bootstrap-typeahead';
import 'react-bootstrap-typeahead/css/Typeahead.css';
const myForm = (props) => {
const { register, handleSubmit, errors } = useForm();
const onSubmit = data => {
// api post request with form data
})
};
const mydata = [ "one", "two", "three" ];
return (
<>
<form onSubmit={handleSubmit(onSubmit)} >
<div className="form-group">
{/* Here I'm registering text input using ref: */}
<input type="text" className="form-control" name="name" ref={register({ required: true })} />
</div>
<div className="form-group mb-0">
{/* How can I register the below component with useForm? */}
<Typeahead
id="multiple-typeahead"
clearButton
multiple
options={mydata}
/>
</div>
<button type="submit">Save</button>
</form>
</>
);
}
This is how i was able to register the component:
import useForm from 'react-hook-form';
import { useForm, Controller } from "react-hook-form";
import 'react-bootstrap-typeahead/css/Typeahead.css';
const myForm = (props) => {
const { register, handleSubmit, errors, control } = useForm();
const onSubmit = data => {
// api post request with form data
})
};
const mydata = [ "one", "two", "three" ];
return (
<>
<form onSubmit={handleSubmit(onSubmit)} >
<div className="form-group">
<input type="text" className="form-control" name="name" ref={register({ required: true })} />
</div>
<div className="form-group mb-0">
<Controller
as={Typeahead}
control={control}
name="typeahead_component"
rules={{ required: true }}
id="multiple-typeahead"
clearButton
multiple
options={mydata}
defaultValue=""
/>
</div>
<button type="submit">Save</button>
</form>
</>
);
}
I am building a SPA per the guidance provided in John Papa's Jumpstart.
When I create the model, it has
modelObservable().entityAspect.entityState.isAdded() = true;
I update the text, dropdown and
modelObservable().entityAspect.entityState.isAdded() = false;
in my Datacontext:
var createProject = function (position) {
return manager.createEntity(entityNames.project,
{
positionId : position.id(),
start : position.start(),
memberId : position.memberId()
});
};
which is called from my add viewModel:
define(['services/datacontext', 'durandal/plugins/router', 'durandal/system', 'durandal/app', 'services/logger', 'services/uiService'],
function (datacontext, router, system, app, logger, ui) {
var model = ko.observable();
var position = ko.observable();
var hourTypes = ko.observableArray([]);
var isSaving = ko.observable(false);
// init
var activate = function (routeData) {
logger.log('Add View Activated', null, 'add', true);
var positionId = parseInt(routeData.id);
initLookups();
return datacontext.getPositionById(positionId, position).then(**createProject**);
};
var initLookups = function () {
logger.log('initLookups', null, 'add', true);
hourTypes(datacontext.lookups.hourTypes);
};
// state
**var createProject = function () {
return model(datacontext.createProject(position()));
}**
var addNewProject = function () {
if (position == undefined || position().id() < 1) {
console.log('callback addNewProject');
setTimeout(function () {
addNewProject();
}, 1000);
} else {
datacontext.addProject(position(), model);
console.log(model().id());
return;
}
}
var **save** = function () {
isSaving(true);
**datacontext.saveChanges()**
.then(goToEditView).fin(complete);
function complete() {
isSaving(false);
}
function goToEditView() {
isSaving(false);
var url = '#/Projects/';
router.navigateTo(url + model().id());
}
};
var vm = {
activate: activate,
hourTypes: hourTypes,
isAdded: isAdded,
model: model,
save: save,
title: 'Details View'
};
return vm;
});
the html
<section data-bind="with:model">
<h1 data-bind="text: name"> <i class="icon-asterisk" data-bind="visible: hasChanges" style="font-size: 30px;"></i></h1>
<div class="errorPanel"></div>
<div id="overview" class="project" >
<div class="row">
<div class="span4">
<label class="requiredLabel">Name*</label>
<input type="text" name="name" data-bind="value: name" style="width: 27em;" class="required" placeholder="Project Name" required validationMessage="Project Name required" /><span class="k-invalid-msg" data-for="title"></span>
</div>
</div>
<div class="row">
<div class="span3"><label class="requiredLabel">Start*</label></div>
<div class="span3"><label class="requiredLabel">End</label></div>
</div>
<div class="row">
<div class="span3"><input name="start" data-bind="shortDate: start" class="date required" required="required" placeholder="mm/dd/yyyy" style=" width:142px"></div>
<div class="span3"><input name="end" data-bind="shortDate: end" class="date" placeholder="mm/dd/yyyy" style=" width:142px"><span class="k-invalid-msg" data-for="end"></span></div>
</div>
<br/>
<div class="row">
<div class="span3"><label for="hourType" class="requiredLabel">Measure As*</label></div>
<div class="span2"><label for="hoursPerWeek" class="requiredLabel">Hours/Week</label></div>
<div class="span2"><label for="totalHours" class="requiredLabel">Total Hours</label></div>
</div>
<div class="row">
<div class="span3">
<select id="hourType" data-bind="options: $parent.hourTypes, optionsText: 'name', value: hourType" required validationMessage="Measure As required"></select><span class="k-invalid-msg" data-for="hourType"></span>
</div>
<div class="span2">
<input name="hoursPerWeek" type="number" min="1" max="120" required="required" data-bind="value: hoursPerWeek, validationOptions: { errorElementClass: 'input-validation-error' }, enable: hourType().id() == 1" class="hours required"" style="width: 80px;" validationMessage="Hours required"><span class="k-invalid-msg" data-for="projectHours"></span>
<span class="k-invalid-msg" data-for="totalHours"></span>
</div>
<div class="span2">
<input name="totalHours" type="number" min="40" max="2080" required="required" data-bind="value: totalHours, validationOptions: { errorElementClass: 'input-validation-error' }, enable: hourType().id() == 2" class="hours required"" style="width: 80px;" validationMessage="Hours required"><span class="k-invalid-msg" data-for="projectHours"></span>
<span class="k-invalid-msg" data-for="totalHours"></span>
</div>
</div>
<div class="row">
<div class="span4">
<label class="requiredLabel">Description*</label><span class="k-invalid-msg" data-for="description"></span><span id="posMinDesc" style="visibility:hidden"></span>
<textarea id="description" name="description" style="height: 200px; width: 650px;" data-bind="value: description, enabled:true, click: $parent.clearDefaults" rows="4" cols="60" class="richTextEditor k-textbox" required validationMessage="Description required" ></textarea>
</div>
</div>
</div>
<div class="button-bar">
<button class="btn btn-info" data-bind="click: $parent.goBack"><i class="icon-hand-left"></i> Back</button>
<button class="btn btn-info" data-bind="click: $parent.save, enable: $parent.canSave"><i class="icon-save"></i> Save</button>
</div>
</section>
The json breeze sends to my controller is this:
{
"entities": [
{
"Id": -1,
"Description": "poi",
"End": null,
"Gauge": 0,
"Score": 0,
"HourTypeId": 1,
"HoursPerWeek": 45,
"HourlyRate": null,
"TotalHours": null,
"WeightedHours": 0,
"CreditMinutes": 0,
"TotalCompensation": null,
"IsCurrent": false,
"Name": "poi",
"PositionId": 1,
"MemberId": 1,
"Start": "2011-09-01T00:00:00Z",
"undefined": false,
"entityAspect": {
"entityTypeName": "Project:#SkillTraxx.Model",
"defaultResourceName": "Projects",
"entityState": "Modified",
"originalValuesMap": {
"Name": "",
"HourTypeId": 0,
"HoursPerWeek": null,
"Description": ""
},
"autoGeneratedKey": {
"propertyName": "Id",
"autoGeneratedKeyType": "Identity"
}
}
}
],
"saveOptions": {}
}
As you can see, the above is incorrect b/c state is "Modified" and the Id = -1. This throws an error server side. I suppose I could trap the DbUpdateConcurrencyException, unwind the JObject and change "Modified" to added, but that's got code smell all over it.
If anyone can help me find the face-palm moment in all of this, I'm ready.
Thanks for looking!
FACE PALMED IT
I took Jays advice and started stripping away the html then I realize it was my handler.
The update method on shortDate handler was responsible. I wrapped it in an if statement not to send the update if the current state is added.
ko.bindingHandlers.shortDate = {
init: function (element, valueAccessor) {
//attach an event handler to our dom element to handle user input
element.onchange = function () {
var value = valueAccessor();//get our observable
//set our observable to the parsed date from the input
value(moment(element.value).toDate());
};
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var value = valueAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(value);
if (valueUnwrapped) {
element.value = moment(valueUnwrapped).format('L');
if (!viewModel.entityAspect.entityState.isAdded())
{
**viewModel.entityAspect.setModified();**
}
}
}
};
I'm trying to run the code from http://jsfiddle.net/ddole/AC5mP/13/ on my machine and the approach I've use is below or here.
Do you know why that code doesn't work on my machine. Firebug doesn't help me and I can't solve the problem. I think that I need another pair of eyes :(((
In firebug,console tab i don't get any error message. The problem is that I can't get the value of that input from the dialog box, after I press save button. The $('input:last').val() seems to be empty
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Dialog - Modal form</title>
<link type="text/css" href="css/ui-lightness/jquery-ui-1.8.21.custom.css" rel="stylesheet" />
<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.8.21.custom.min.js"></script>
<script type="text/javascript" >
jQuery(function($) {
$('.helpDialog').hide();
$('.helpButton').each(function() {
$.data(this, 'dialog',
$(this).next('.helpDialog').dialog({
autoOpen: false,
modal: true,
width: 300,
height: 250,
buttons: {
"Save": function() {
alert($('.helpText:last').val());
$(this).dialog( "close" );
},
Cancel: function() {
$(this).dialog( "close" );
}
}
})
);
}).click(function() {
$.data(this, 'dialog').dialog('open');
return false;
});
});
</script>
</head>
<body>
<span class="helpButton">Button</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
<span class="helpButton">Button 2</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
<span class="helpButton">Button 3</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
<span class="helpButton">Button 4</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
<span class="helpButton">Button 5</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div> </body>
Refer LIVE DEMO
To display the text on save, I have modified your line alert($('.helpText:last').val()); to this alert($('.helpText', this).val());
I have added one more dependencies on fiddler,
http://code.jquery.com/ui/1.8.21/jquery-ui.min.js
Now its working as expected.
HTML:
<span class="helpButton">Button</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
<span class="helpButton">Button 2</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
<span class="helpButton">Button 3</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
<span class="helpButton">Button 4</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
<span class="helpButton">Button 5</span>
<div class="helpDialog">
<input type="text" class="helpText" />
</div>
JS:
jQuery(function($) {
$('.helpDialog').hide();
$('.helpButton').each(function() {
$.data(this, 'dialog',
$(this).next('.helpDialog').dialog({
autoOpen: false,
modal: true,
width: 300,
height: 250,
buttons: {
Save: function() {
alert($('.helpText', this).val());
$(this).dialog( "close" );
},
Cancel: function() {
$(this).dialog( "close" );
}
}
})
);
}).click(function() {
$.data(this, 'dialog').dialog('open');
return false;
});
});