How to use custom resuable components as input fields in react - javascript

I have a situation here where I have created a reusable component which is responsible for creating input fields and label. I want to use this component throughout to build a complete form having a single row with two columns (with this custom input field)
I use the following code
Form.jsx
<GridRow>
<InputField type="text"label="First Name"/>
<InputField type="text"label="Last Name" />
</GridRow>
GridRow.jsx
render() {
return (
<div>
<Container>
<Row>
<Col sm={6}>
{this.props.children}
</Col>
<Col sm={6}>
{this.props.children}
</Col>
</Row>
</Container>
</div>
);
Inputfield.jsx
const InputField = ({label, type}) => (
<div>
{label}
<input
type={type}
style={{ padding: "4px", border: "none", borderBottom: "1px solid #ccc", width: "90%"}}
/>
</div>
);
Here Form.jsx is using GridRow.jsx as component which has a child component inputfield.jsx
I want the two columns to be different in the same row.
I'm getting the below output
Following is the desired output. How can i get this output
As in the image the first row is

I think you should try this:
form.jsx:
<Row>
<Col><input /></Col>
<Col><input /></Col>
</Row>
grdiRow.jsx:
<Container>
{this.props.child}
</Container>

Related

Avoid elements to move separately on browser resize in a React Form

I'm struggling with the following form done in React:
import React, { Component } from 'react';
import ImageGallery from 'react-image-gallery';
import { Container, Row, Col, InputGroup, Button, FormControl, Form } from 'react-bootstrap';
const images = [
{
original: '/assets/images/products/colgantes.png',
thumbnail: '/assets/images/products/colgantes#0.25x.png',
},
{
original: '/assets/images/products/corazones.png',
thumbnail: '/assets/images/products/corazones#0.25x.png',
},
{
original: '/assets/images/products/take-me-to-the-beach.png',
thumbnail: '/assets/images/products/take-me-to-the-beach#0.25x.png',
},
];
class DetailedProduct extends Component {
render() {
return (
<>
<Container fluid>
<Row >
<Col md={{ span: 4, offset: 3 }} sm={{ span: 12, offset: 0}} >
<ImageGallery
items={images}
showNav=""
showFullscreenButton=""
showBullets=""
showPlayButton=""
thumbnailPosition="left"
/>
</Col>
<Col md={3} sm={12} className="text-xs-center text-md-left" >
<h1>Product</h1>
<h3>$500</h3>
<p>Lorem Ipsum is simply dummy text from the printing and typeseting industrys</p>
<Form>
<Row >
<Col sm={12} md={8} >
<Form.Group controlId="color" >
<Form.Label>Color</Form.Label>
<Form.Control as="select" custom>
<option>Rojo</option>
<option>Negro</option>
<option>Azul</option>
</Form.Control>
</Form.Group>
</Col>
<Col sm={12} md={4} className="inline-block">
<Form.Group controlId="cantidad" >
<Form.Label>Cantidad</Form.Label>
<InputGroup >
<InputGroup.Prepend>
<Button variant="outline-secondary" >+</Button>
</InputGroup.Prepend>
<FormControl
placeholder="1"
aria-label="quantity"
aria-describedby="basic-addon2"
/>
<InputGroup.Append>
<Button variant="outline-secondary" >-</Button>
</InputGroup.Append>
</InputGroup>
</Form.Group>
</Col>
</Row>
</Form>
</Col>
</Row>
</Container>
</>
);
}
}
export default DetailedProduct;
The problem I have is that when I resize the Browser Window, the appended buttons in the input, start to move down to a different row separately, breaking the [+ 1 -] block. I've tried applying different CSS to the form group but I can't find a way to tighten them together so that if they move, they move in a block and the following thing doesn't happen:
You can try adding the rule for the minimum size:
min-width: 150px;
150px is an example size.
Unfortunately I don't know the width size that input should have.
To the class that contains the three elements, input-group, in that case. I advise you to add a class and apply additional styles to that.
Thanks, I was able to fix it by using the right flex column sizes for the scren resolution, sm={12} md={6} lg={4} - That did the trick

How to get data from an object with arrays/strings and then pass that data to a React component

I'm trying to pass information from one component to another via props in ReactJS. I'm trying to access the inside of an array that has a string of information (picture included), and then I'm trying to get that information accessible to my return() function in the component so I can use it in a modal.
This is the component that I passed the props into:
class OfferActionPreviewModal extends Component {
constructor(props) {
super(props);
this.state = {
success: false,
action: [],
offerActions: []
};
this.toggleSuccess = this.toggleSuccess.bind(this);
}
toggleSuccess() {
this.setState({
success: !this.state.success
});
}
componentDidMount() {
this.renderAdvertiserForm();
}
renderAdvertiserForm = () => {
const {
offerAction,
offerActionTriggers,
triggers,
offer
} = this.props;
console.log(offerActionTriggers);
return (
<form>
<ModalHeader toggle={this.toggleSuccess}>
{offerAction.name} - <em>{offerAction.id}</em>
</ModalHeader>
<ModalBody>
<div>
<Row>
<Col lg={6}>
<Label>Post Name</Label>
<Field
name='offerActions.name'
type='text'
component={renderField}
/>
</Col>
<Col lg={6}>
<Label>Post Method</Label>
{offerAction.postMethod}
</Col>
</Row>
<br />
<Row>
<Col lg={12}>
<Label>URL</Label>
{offerAction.url}
</Col>
</Row>
<br />
</div>
<br />
</ModalBody>
</form>
);
};
render() {
return (
<div className='animated'>
<Modal
isOpen={this.state.success}
toggle={this.toggleSuccess}
className='modal-info'
>
{this.renderAdvertiserForm()}
</Modal>
</div>
);
}
}
export default connect()(OfferActionPreviewModal);
I'm trying to access inside the OfferActionTriggers, to the OfferActionCriteria part of the object, and I've included an image of the object for reference.
Thanks for all help in advance.
You can use Nested Object Destructuring for this purpose like this
const {offerAction:{OfferActionCriteria,offerActionPost:{url,name,id,postMethod}}} =
this.props; to access the OfferActionCriteria object. inside renderAdvertiserForm function.
renderAdvertiserForm = () => {
const {offerAction:{OfferActionCriteria,offerActionPost:{url,name,id,postMethod}}} = this.props;
console.log(OfferActionCriteria);
return (
<form>
<ModalHeader toggle={this.toggleSuccess}>
{name} - <em>{id}</em>
</ModalHeader>
<ModalBody>
<div>
<Row>
<Col lg={6}>
<Label>Post Name</Label>
<Field
name='name'
type='text'
component={renderField}
/>
</Col>
<Col lg={6}>
<Label>Post Method</Label>
{postMethod}
</Col>
</Row>
<br />
<Row>
<Col lg={12}>
<Label>URL</Label>
{offerAction.url}
</Col>
</Row>
<br />
</div>
<br />
</ModalBody>
</form>
);
};

How to control the position of the text in the selector in antd UI?

I am using antd's selector, I want to add a prompt to the left of the selection box to indicate what this selector is used to select. I tried to use the label tag in the select tag, but this will give an error. I also thought about using pseudo-elements, but that didn't work. Do you know how to do it. The effect I want is as follows. The left side of the selection box is the prompt word, and the right side is the selection result of the selector.
There is no build-in way, you need to compose it from other components.
For example: using CheckBox, Dropdown, Menu and layout components like Row and Col
const data = ['Jack', 'Lucy', 'Momo', 'Alex'];
export default function App() {
const [selected, setSelected] = useState('Jack');
const menu = (
<Menu onSelect={({ key }) => setSelected(key)}>
{data.map(item => (
<Menu.Item key={item} value={item}>
{item}
</Menu.Item>
))}
</Menu>
);
return (
<FlexBox>
<FlexBox>
<h3>All Checkboxed</h3>
<Select defaultValue="Jack">
{data.map(uniqueValue => (
<Select.Option value={uniqueValue} key={uniqueValue}>
<Checkbox>{uniqueValue}</Checkbox>
</Select.Option>
))}
</Select>
</FlexBox>
<FlexBox>
<h3>Side By Side</h3>
<Checkbox disabled>
<Select defaultValue="Jack">
{data.map(uniqueValue => (
<Select.Option value={uniqueValue} key={uniqueValue}>
{uniqueValue}
</Select.Option>
))}
</Select>
</Checkbox>
</FlexBox>
<FlexBox>
<Card size="small" style={{ width: 120 }}>
<Row type="flex" gutter={10}>
<Col>
<Checkbox disabled />
</Col>
<Col>
<Dropdown overlay={menu} trigger={['click']}>
<Row type="flex" style={{ alignItems: 'center' }} gutter={10}>
<Col>{selected}</Col>
<Col>
<Icon type="down" />
</Col>
</Row>
</Dropdown>
</Col>
</Row>
</Card>
</FlexBox>
</FlexBox>
);
}

React-Bootstrap <Row> incorrect height

I am trying to create a two column layout, with the left column a fixed height, and the right column containing another Grid with multiple rows.
However, the first row in the second column is always the height of the left column.
Here's the output:
Here is my code:
class App extends Component {
render() {
return (
<div>
<Grid fluid >
<Row>
<Col xs={2} style={{ padding: '0px', backgroundColor: 'lightblue', height: '200px' }}>
Column 1 <br/>I am a 200 px tall column</Col>
<Col xsOffset={2}>
<Grid>
<Row style={{backgroundColor: 'red'}}>
Column 2 <br/> Why am I so tall???
</Row>
<Row style={{backgroundColor: 'green'}}>
I am too far down!
</Row>
<Row style={{backgroundColor: 'lightgray'}}>
Me, too!
</Row>
</Grid>
</Col>
</Row>
</Grid>
</div>
);
}
}
And a fiddle: https://jsfiddle.net/TimoF/dwLhb1fz/
Replace xsOffset={2} with xs={10}
Why was it happening?
According to Bootstrap Grid System, adjacent <div> with pseudo class .row::before is having display:table,by default.
Had to dive deep into Bootstrap CSS ;)
Hence it will force adjacent <div> to be of equal height. Check this
In your case, it's not necessary to give offset, and it's more convenient to replace xsOffset={2} with xs={10}.
Hence it will work fine as it's standard Bootstrap's way.
var { Grid, Row, Col } = ReactBootstrap
class App extends React.Component {
render() {
return (
<Grid fluid >
<Row>
<Col xs={2} style={{ backgroundColor: 'lightblue', height: '200px' }}>
Column 1 <br/>I am a 200 px tall column</Col>
<Col xs={10}>
<Row>
<Grid>
<Row style={{backgroundColor: 'red',height:'auto'}}>
Column 2 <br/> Why am I so tall???
</Row>
<Row style={{backgroundColor: 'green'}}>
I am too far down!
</Row>
<Row style={{backgroundColor: 'lightgray'}}>
Me, too!
</Row>
</Grid>
</Row>
</Col>
</Row>
</Grid>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('container')
);
<script src="https://unpkg.com/react#16.2.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.2.0/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-bootstrap/0.32.1/react-bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
Check this Fiddle

ReactJs requires a wrapper div which breaks the layout

I have the following React code:
render() {
return (
<NavItem dropdown toggleOnHover className='collapse-left'>
<DropdownButton nav>
<Icon bundle='fontello' glyph='bullhorn' />
{this.getBadge()}
</DropdownButton>
<Menu alignRight ref='bullhorn-menu' id='notifications-menu' className='double-width' alwaysInactive>
<MenuItem header>
<Entity entity='Notifications' />
</MenuItem>
{this.state.notifications.map((item, index) => {
return (
<Notification notification={item} key={index} />
)
})}
<MenuItem noHover>
<Grid collapse style={{marginBottom: -10}}>
<Row>
<Col xs={12} collapseLeft collapseRight>
<Button block className='notification-footer-btn left-btn'>MARK ALL READ</Button>
</Col>
</Row>
</Grid>
</MenuItem>
</Menu>
</NavItem>
)
}
The code above doesn't work, because it throws:
react-with-addons.js:9729 Uncaught TypeError: Cannot read property 'toUpperCase' of undefined
However, when I surround the map() statement with a div, it works, but that breaks the layout.
The Notification component just returns something like this:
<MenuItem href='/'>
<Grid>
<Row>
<Col xs={2} className='avatar-container' collapseRight>
<div><img src='/imgs/avatars/avatar22.png' width='40' height='40' alt='sarah_patchett' /></div>
<div className='text-center'>
<BLabel bsStyle='info'>NEW</BLabel>
</div>
</Col>
<Col xs={10} className='notification-container' collapseLeft collapseRight>
<div className='time'>
<strong className='fg-darkgray50'><Icon bundle='fontello' glyph='chat-5'/><em><Entity entity='notificationsTimeFirst' /></em></strong>
</div>
<div className='message-header'>
<strong className='fg-darkgreen45'>Sarah Patchett sent you a private message</strong>
</div>
<div className='message-details fg-text'>
<span>{"Hey Anna! Sorry for delayed response. I've just finished reading the mail you sent couple of days ago..."}</span>
</div>
</Col>
</Row>
</Grid>
</MenuItem>
Can someone tell me how to just loop over my array and render the Notification component, without the surrounding div?
Currently it is not possible to return multiple components like that, so you need to wrap them in something.
Why don't you just change the style of the container so that it doesn't break the layout?
For example:
<div style={{ display: "inline" }}>
{this.state.notifications.map((item, index) => {
return (
<Notification notification={item} key={index} />
)
})}
</div>
Alternatively, you could do this:
let menuItems = [
<MenuItem header key="header">
<Entity entity='Notifications' />
</MenuItem>
].concat(notifications);
return <Menu>
{ menuItems }
</Menu>;
Now the contents of the menu is an array, so every item needs a key.

Categories

Resources