reactjs parent trigger child component - javascript

I have a parent component, which is basically a Form.
export default class Parent extends Component{
submitInput(event){
...call Children
}
render(){
return(
<div>
<form className="form-horizontal" onSubmit= {this.submitInput.bind(this)}>
{this.props.children}
<button type="submit">Submit</button>
</div>
</form>
</div>);
}}
The children can be different types of inputs all with a common function called validate().
Here is one example of a child
export default class Child extends Component{
validate(){
..validate stuff
}
render(){
return(
<div className="form-group">
<textarea ref={this.props.name} />
</div>
);
}
}
On Submission of the parent Component I want validate all Child inputs using their validate() function.
How can I do that?
Thanks in advance

Clone the entire children with new ref prop using React.cloneElement. On submit use the refs to access the child's methods.
See the example below. If more elaboration needed, please comment.
Hope this helps!
class Form extends React.Component{
submitInput(){
this.childrenClone.forEach((el) => {
var r = el.ref //use the ref to access the child's methods
this.refs[r].validate()
})
}
render() {
this.childrenClone = React.Children.map(this.props.children,
(child) => React.cloneElement(child, {
ref: Math.random().toString(36).slice(-5) //add a random string as a ref
})
)
return <div>
<form className="form-horizontal" onSubmit={this.submitInput.bind(this)}>
{this.childrenClone}
<button type="submit">Submit</button>
</form>
</div>
}
}
class Child extends React.Component{
validate(){
console.log('validate textarea') //on validate log this
}
render() {
return <div className="form-group">
<textarea />
</div>
}
}
class ChildInput extends React.Component{
validate(){
console.log('validate Input') //on validate log this
}
render() {
return <div className="form-group">
<input type="text" />
</div>
}
}
class Parent extends React.Component{
render(){
return <Form>
<Child/>
<Child/>
<ChildInput/>
<ChildInput/>
</Form>
}
}
ReactDOM.render(<Parent/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Related

Component is not updating on Button Click, React

I have a parent component 'Menu' and a child component 'DishDetails'. The child component returns a Card on Button Click. It works for the first time when i click on the button. The component is not updated while i again click on button. The Component should update after clicking on the Button.
Parent Component
import React,{Component} from 'react';
import DishDetails from './DishDetails'
import { Card,CardImg,CardImgOverlay,CardTitle,CardBody,CardText} from 'reactstrap'
class Menu extends Component{
//The class base component must have a constructor with super statment
constructor(props){
super(props);
this.state ={
dishSelection:null
}
}
//Method when the user click on the image
onDish(dish){
this.setState({dishSelection:dish})
}
renderDish(dish){
if(dish!=null){
return(
<DishDetails dish = {dish}></DishDetails>
)
}
else{
return(
<div></div>
)
}
}
//The component should implement the render method
render(){
//Declare a variable for the defining the list
const media = this.props.dishes.map((dish)=>{
return(
<div className='col-12 col-md-5 m-2'>
<Card onClick={()=>this.onDish(dish)} key={dish.id}>
<CardImg src={dish.image} alt={dish.name} />
<CardImgOverlay>
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
)
})
return(
<div className='container'>
<div className='row'>
{media}
</div>
<div className='row'>
<div className = 'col-12'>
{this.renderDish(this.state.dishSelection)}
</div>
</div>
</div>
)
}
}
export default Menu;
Child Component
import React , {Component} from 'react'
import {Card,CardImg,CardImgOverlay,CardTitle} from 'reactstrap'
class DishDetails extends Component{
constructor(props){
super(props)
this.state = {
dish : this.props.dish
}
}
render(){
//const dish = this.props.dish;
console.log(this.state.dish.name)
return(
<div>
<div className = 'col-12 col-md-5'>
<Card key={this.state.dish.id}>
<CardImg src={this.state.dish.image} alt={this.state.dish.name} />
<CardImgOverlay>
<CardTitle>{this.state.dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
<div>
</div>
</div>
)
}
}
export default DishDetails;
Constructor fires for the first time only. Don't make copy of props in state if you don't need to change the value inside child component. Change this.state.dish to this.props.dish in child component.
class DishDetails extends Component{
render(){
return(
<div>
<div className = 'col-12 col-md-5'>
<Card key={this.props.dish.id}>
<CardImg src={this.props.dish.image} alt={this.state.dish.name} />
<CardImgOverlay>
<CardTitle>{this.props.dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
<div>
</div>
</div>
)
}
}
export default DishDetails;
Or if you still want to update the state on any change in parent component then you should have a look at this link :-
https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

Passing props from one component to another in ReactJS returns undefined

I am a newbie in React and I am trying to pass props from one React component to another. Please consider my code below and tell me what could I possibly doing wrong.
As you will notice, I am trying to do so with this.props.value, but all I got in the console is "undefined". I managed to run the code by putting all HTML elements in one component and it was working perfectly fine.
class Editor extends React.Component {
constructor(props) {
super(props);
this.state = {
input: defaultTxt
};
this.inputChanges = this.inputChanges.bind(this);
}
inputChanges(e) {
this.setState({
input: e.target.value
});
}
render() {
return (
<div>
<div id="editorBar">
Editor
<i className="fa fa-expand expand" />
</div>
<textarea
id="editor"
style={editorStyle}
value={this.state.input}
onChange={this.inputChanges}
placeholder={defaultTxt}
/>
</div>
);
}
}
//preview
class Previewer extends React.Component {
render() {
return (
<div>
<div id="previewerBar">
Preview
<i className="fa fa-expand expand" />
</div>
<div
id="preview"
style={viewerStyle}
dangerouslySetInnerHTML={{ __html: this.props.value }}
/>
</div>
);
}
}
//wrapper
class Wrapper extends React.Component {
render() {
return (
<div id="wrapper">
<Editor />
<Previewer />
</div>
);
}
}
const defaultTxt = `Some default text`;
ReactDOM.render(<Wrapper />, document.getElementById('root'));
It should look like this:
class Editor extends React.Component {
render() {
return (
<div>
<div id="editorBar">
Editor
<i className="fa fa-expand expand" />
</div>
<textarea
id="editor"
style={editorStyle}
value={this.props.input}
onChange={this.props.inputChanges}
placeholder={defaultTxt}
/>
</div>
);
}
}
//preview
class Previewer extends React.Component {
render() {
return (
<div>
<div id="previewerBar">
Preview
<i className="fa fa-expand expand" />
</div>
<div
id="preview"
style={viewerStyle}
dangerouslySetInnerHTML={{ __html: this.props.value }}
/>
</div>
);
}
}
//wrapper
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
input: defaultTxt
};
this.inputChanges = this.inputChanges.bind(this);
}
inputChanges(e) {
this.setState({
input: e.target.value
});
}
render() {
return (
<div id="wrapper">
<Editor input={this.state.input} inputChanges={this.inputChanges}/>
<Previewer value={this.state.input}/>
</div>
);
}
}
const defaultTxt = `Some default text`;
ReactDOM.render(<Wrapper />, document.getElementById('root'));
The idea is that the Wrapper component will be the one which hold the state and control the state change. The Editor and Previewer are its children which receive data to display and invoke the callback prop.
If two components share state lift the state to the parent component - in this case Wrapper. And since neither of the two children components have state they can be coded as stateless functions.
function Editor({ text, handleChange }) {
return (
<div>
<div id="editorBar">Editor
<i className="fa fa-expand expand" />
</div>
<textarea id="editor" value={text} onChange={handleChange} />
</div>
);
}
function Previewer({ text }) {
return (
<div>
<div id="previewerBar">Preview
<i className="fa fa-expand expand"></i>
</div>
<div id="preview" dangerouslySetInnerHTML={{__html: text}}></div>
</div>
);
}
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state={ input: props.defaultText }
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({ input: e.target.value });
}
render() {
return (
<div id="wrapper">
<Editor text={this.state.input} handleChange={this.handleChange} />
<Previewer text={this.state.input} />
</div>
);
}
}
const defaultText = 'Some default text';
ReactDOM.render(<Wrapper defaultText={defaultText} />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

How to totally disable a react component?

I have a react component which has some buttons and text inputs. I want to totally disable all the things inside this component until some other works are complete. How to make the entire inner component disabled?
You can add disabled props and use CSS to disable div
const MyComponent = ({disabled}) => {
return (
<div style={disabled ? {pointerEvents: "none", opacity: "0.4"} : {}}>
<h1> Text</h1>
<input type="text"/>
<input type="password"/>
<button>Login</button>
</div>
)
}
Better to use form and fieldset, and put all the input/button elements inside that. You can disable all of them by setting the property disabled to fieldset.
Refer MDN Doc for more details.
Working example:
class App extends React.Component {
constructor () {
super()
this.state = { disable: false }
}
toggleDisable = () => this.setState(prevState => ({disable: !prevState.disable}))
buttonClick = (e) => {
e.preventDefault();
console.log('button clicked');
}
render (){
return (
<div>
<button className='toggle' onClick={this.toggleDisable}>Toggle Disable</button>
<form>
<fieldset disabled={this.state.disable}>
<input />
<button onClick={this.buttonClick}>Button</button>
</fieldset>
</form>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
.toggle {
margin-bottom: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app' />
All you need to do is add a disabled prop on the component and pass it on to the inner fields like
<MyComponent disabled={shouldComponentBeDisabled} {...otherProps} />
and in implementation
const MyComponent = ({disabled}) => {
return <div>
<button disabled={disabled}>someBtn</button>
<input type="text" disabled={disabled}/>
</div>
}
You can use disabled prop pattern to save the day.
const App = () => {
return (
<div>
<SomeComponent disabled />
</div>
);
};
const SomeComponent = ({ disabled = false }) => {
return (
!disabled && (
<div>
<h2>Disable SomeComponent to see magic happen!</h2>
</div>
)
);
};

How do i execute alert() in parent component after onClick in child component

In here, i'm passing data from child to parent and i am able to pass it through but i want alert function to execute only after onClick event is triggered in the child component but it is executing everytime onSubmit event is fired, it looks like there is a requirement of some life cycle method in order to make it work but i'm not getting it. Can someone help me with this please
Parent
onList(list) {
alert(list);
}
render() {
return (
<div>
<form>
<input type='textarea'
onKeyPress={this.handleSubmit}
/>
<Child {...this.state} sendList={this.onList}/>
</form>
</div>
)
}
Child
{
this.props.listArr.map((list,index) => {
return(
<div key={index}>
<li>{list}
<div>
<button className="btn btn-primary btn-xs glyphicon glyphicon-pencil" onClick={this.props.sendList(list)} />
</div>
</li>
</div>
)})
}
change to:
<Child {...this.state} sendList={(...args) => this.onList(...args)} />, to preserve the function context.
then, in Child just call that method as this.props.sendList()
You can use event.preventDefault() on button click so the form doesn't get submitted.
const Child = ({ sendList, list }) =>
<div>
<button onClick={(event) => sendList(event, list)}>Click</button>
</div>
class Parent extends React.Component {
constructor() {
super()
this.onList = this.onList.bind(this)
}
onList(event, list) {
event.preventDefault()
console.log('onList', list)
}
render() {
return (
<form>
<Child sendList={this.onList} list={[]} />
</form>
)
}
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Onclick event handler with passing this in reactjs

My component is as below:
import React, {PropTypes} from 'react';
export default class Viewdesc extends React.Component {
render() {
return (
<div className="col-md-12 slide-row">
<div className="col-md-12 overview-about-property">
<div className="expandabletext less">
<div className="col-md-12" dangerouslySetInnerHTML={{__html: this.props.record.ABOUT}}></div>
</div>
<div className="showmore"> Show More </div>
</div>
</div>
);
}
}
I want to call function say showmorefunct() passing clicked handler like this in jquery. How can I do this?
You can bind you function and pass params which you want, if you want to. You can do something like :
class Test extends React.Component {
handleClick(param, e){
console.log(e);
console.log(param);
}
render(){
return (
<div className="showmore" onClick={this.handleClick.bind(this, "Some param if you need it")}> Show More </div>
)
}
}
React.render(<Test />, document.getElementById('container'));
Here is fiddle.
UPDATE
http://jsfiddle.net/jwm6k66c/1517/
I don't quite really understand your question, but I imagine you want this-
import React, {PropTypes} from 'react';
export default class Viewdesc extends React.Component {
constructor(props) {
super(props)
this.showMoreFunct = this.showMoreFunct.bind(this)
}
showMoreFunct() {
alert('Show more clicked!')
}
render() {
return (
<div className="col-md-12 slide-row">
<div className="col-md-12 overview-about-property">
<div className="expandabletext less">
<div className="col-md-12" dangerouslySetInnerHTML={{__html: this.props.record.ABOUT}}></div>
</div>
<div className="showmore"> <span onClick={this.showMoreFunct}>Show More</span> </div>
</div>
</div>
);
}
}
You can replace span with a or button. You just need to specify the function you want to call to onClick prop. React will call it automatically when the user clicks on that span.

Categories

Resources