ReactDOM.findDOMNode() return null with refs - reactjs

ReactDOM is not working with refs.
I want to sting html <b>abcd</b> append to body of modal, but it's not working.
when I check console.log() of modal and modalBody, it return null.
My code in under:
class Header extends Component {
constructor(props) {
super(props);
this.state = {
this.state.modalSendResult: false
};
}
_open() {
this.setState({
modal: !this.state.modal
});
if (!this.state.modal) {
this.appendNode();
}
}
appendNode() {
let modal = ReactDOM.findDOMNode(this.refs.modal)
modalBody = ReactDOM.findDOMNode(this.refs.body);
ReactDOM.render(
<b>abcde</b>, modalBody
);
}
render() {
return (
<Button onClick={this._open.bind(this)}
className="btn btn-primary btn-primary-1 mr-1">
<i className="fa fa-paper-plane-o" aria-hidden="true"></i> Open
</Button>
<Modal ref="modal" isOpen={this.state.modal} toggle={this._open}
className={'modal-primary modal_customer'}>
<ModalHeader toggle={this._open}>
Danh sách kết quả gửi
</ModalHeader>
<ModalBody className="modal-send" ref="body">
</ModalBody>
</Modal>
);
}
}
Please help me!

Take a look at ReactDOM. You can avoid having to call findDOMNode by setting up your refs as specified here: Refs and the DOM.
I think in your case it would look something like
<Modal
ref={(modal) => { this.modal = modal; }}
isOpen={this.state.modal}
toggle={this._open}
className={'modal-primary modal_customer'}
>
<ModalHeader toggle={this._open}>
Danh sách kết quả gửi
</ModalHeader>
<ModalBody
className="modal-send"
ref={(body) => { this.body = body; }}
/>
</Modal>
Then you should be able to reference them with
this.modal
this.body
Alternatively, you could pass the content you want for your ModalBody component as a prop.
<ModalBody
className="modal-send"
content="abcde"
ref={(body) => { this.body = body; }}
/>
And render in your ModalBody component:
render() {
return (
<b>{this.props.content}</b>
);

Related

How do I call an event for another component in React?

I've been working in react for about.. 2 days. 3/4's of that was me trying to get react to work with my current Asp.net MVC WebApp.
I have 2 classes. Everything is working fine, but I want the handleScan of Camera to call the handleHideClick() of ShowScanner. Whats the proper way to do that?
Here is my code:
import React from 'react';
import QrReader from 'react-qr-reader';
import { unmountComponentAtNode, render } from "react-dom";
class Camera extends React.Component {
state = {
result: 'No result'
}
handleScan = data => {
if (data) {
this.setState({
result: data
});
scanDataProcessor(this.state.result);
unmountComponentAtNode(document.getElementById('root'));
// *** Replace unmount above with a call to execute: ShowScanner.handleHideClick()
}
}
handleError = err => {
console.error(err)
}
render() {
return (
<div id="scanner" class="">
<QrReader
delay={300}
onError={this.handleError}
onScan={this.handleScan}
style={{ width: '100%' }}
/>
</div>
)
}
}
class ShowScanner extends React.Component {
constructor(props) {
super(props);
this.handleShowClick = this.handleShowClick.bind(this);
this.handleHideClick = this.handleHideClick.bind(this);
this.state = { showCamera: false }
}
handleShowClick() {
this.setState({ showCamera: true });
render(<Camera />, document.getElementById('root'));
}
handleHideClick() {
this.setState({ showCamera: false });
unmountComponentAtNode(document.getElementById('root'));
}
render() {
const showCamera = this.state.showCamera;
let button;
if (showCamera) {
return (
<button id="btnScan" type="button" class="btn btn-primary p-1" onClick={this.handleHideClick}>
<i class="bi bi-qr-code-scan"></i>
<br />Scan
</button>
);
} else {
return (
<button id="btnScan" type="button" class="btn btn-primary p-1" onClick={this.handleShowClick}>
<i class="bi bi-qr-code-scan"></i>
<br />Scan
</button>
);
}
}
}
render(<ShowScanner />, document.getElementById('scanBtn'));
At the very least, I need to reset the button so that when they click it, it remounts the Camera component without them having to click it twice.
Thanks in advance!

Why React-Semantic-UI Transition not animating the Component?

I am having a Component which is a Modal alert. For animating the Modal, I am using the Transition from semantic-ui-react. But only a few animations(pulse,bounce, flash) are working and that too only while mounting of Component, and not working while I close the Modal. Also the duration property is also not working.
class Alert extends React.Component {
state = {
open: true
};
close = () => {
this.setState({
open: false
});
};
render() {
const { open } = this.state;
return (
<Transition animation="fade" duration={1000} visible={open}>
<Modal
size="mini"
closeOnDimmerClick={false}
closeOnEscape={false}
open={this.state.open}
onClose={this.close}>
<Modal.Content>
<p>
Hello user
</p>
</Modal.Content>
<Modal.Actions>
<Button color="blue" onClick={this.close}>
Ok
</Button>
</Modal.Actions>
</Modal>
</Transition>
);
}
}
Why such weird behavior? What am I doing wrong?
Modal is unmounting way before Transition can animate it, one way would be to let Transition unmount the Modal:
class Alert extends React.Component {
state = {
open: true
};
close = () => {
this.setState({
open: false
});
};
render() {
const { open } = this.state;
return (
<Transition
animation="fade"
duration={1000}
unmountOnHide={true}
visible={open}
>
<Modal
size="mini"
closeOnDimmerClick={false}
closeOnEscape={false}
open={true}
onClose={this.close}
>
<Modal.Content>
<p>Hello user</p>
</Modal.Content>
<Modal.Actions>
<Button color="blue" onClick={this.close}>
Ok
</Button>
</Modal.Actions>
</Modal>
</Transition>
);
}
}
I hope it helps!

How to display the products in modal body

I struck in the code that trying to display the products in modal body but not displaying. when i click on image it showing in console but not getting an idea how to display products in modal body. For to display in modal i used react-bootstrap. modal pop up is displaying when i click on image and it displaying header and footer. But in modal body i want to display the product details which i clicked. can any one help ..
import React, { Component } from "react";
import { Grid, Row, Col, Image, Button, Modal } from "react-bootstrap";
import AddToCartView from "./AddToCartView";
// import ProductView from './ProductView';
class ProductList extends Component {
constructor(props){
super(props);
this.state = {
show : false
}
}
handleShow = (item) => {
this.getProductDetails(item);
this.setState({
show : true
})
}
handleClose = () => {
this.setState({
show : false
})
}
getProductDetails = (prod) => {
// console.log(id,'clicked');
console.log(prod);
console.log(prod.title);
console.log(prod.id);
console.log(prod.price);
// let click = document.getElementsByTagName(Image.id);
// console.log(click);
// const { viewProducts } = this.props
// console.log(viewProducts);
// viewProducts.map((prod,id) => {
// console.log(prod.ptype);
// })
}
// console.log(viewProducts,'viewProducts');
render(){
const { viewProducts } = this.props;
return (
<div className="list-container">
<div className="mobile-list">
<h3> Showing { viewProducts.length } mobiles </h3>
</div>
<Grid>
<Row>
{viewProducts.map((item, key) => (
<Col xs={8} md={4} lg={4} key={item.id}>
<figure>
<Image onClick={() => this.handleShow(item) } src={item.image}
thumbnail />
<figcaption>{item.title}</figcaption>
<figcaption>
<label>Rs. </label>
{item.price}
</figcaption>
</figure>
<Button bsStyle="primary" onClick={this.props.onChange}>
<i className="fa fa-shopping-cart" />
Add
</Button>
<hr />
</Col>
))}
</Row>
</Grid>
<Modal show={this.state.show} onHide={() => this.handleClose()}>
<Modal.Header closeButton>
<Modal.Title>Product Details</Modal.Title>
</Modal.Header>
<Modal.Body>
{/* <ProductView displayProductView= { (item) =>
this.props.displayProductDetails(item) }/> */}
</Modal.Body>
<Modal.Footer>
<Button onClick={() => this.handleClose()}>Close</Button>
</Modal.Footer>
</Modal>
</div>
);
};
}
export default ProductList;
You are aware the ProductView component is commented out within the Modal Body right?
I'm not seeing where you pass the item to ProductView. Most likely your ProductView is getting nothing to display. Maybe you could change render of ProductView to just render a 'Hello' to see if that is the case.

Modal isn't opening as expected

class Posts extends Component {
constructor(){
super();
this.state = {
modalIsOpen:false
};
this.openModal = this.openModal.bind(this);
this.afterOpenModal = this.afterOpenModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
openModal() {
console.log("got here?")
this.setState({modalIsOpen: true});
}
afterOpenModal() {
// references are now sync'd and can be accessed.
this.subtitle.style.color = '#f00';
}
closeModal() {
this.setState({modalIsOpen: false});
}
render() {
const keys = generateKey(new Date().getTime())
var dictionary = this.props.posts
const postItemsArr = Object.keys(dictionary).map(post=>dictionary[post])
const number = 0
const postItems = postItemsArr.map(
post=>(
<Jumbotron key={generateKey(post.positiontitle) + generateKey(post.businessId)} >
<div className="position">{post.positiontitle}</div><br></br>
<BusinessName businessnameType={post.businessname} /><br></br>
<JobDescription jobDescription={post.description_sanitized} /><br></br>
<p>
<Modal isOpen={this.state.modalIsOpen}
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
style={customStyles}
contentLabel="Example"
>
<h2 ref={subtitle => this.subtitle = subtitle}>Hello</h2>
<button onClick={this.closeModal}>close</button>
<div>I am a modal</div>
<form>
<input />
<button>tab navigation</button>
<button>stays</button>
<button>inside</button>
<button>the modal</button>
</form>
</Modal>
<button onClick={this.openModal}>Open Modal</button>
</p>
</Jumbotron>
)
)
return (
<div>
<h1> Jobs Listings </h1>
{postItems }
</div>
);
}
}
Inside my Jumbotron, my modal doesn't seem to be opening, why?
It looks like it gets to the state openModal()
but doesn't actually open the modal when the user clicks on
<button onClick={this.openModal}>Open Modal</button>
Also; should I create a separate component called Modal; what would be best practices?
Overall I'm trying to trigger the modal object for a respective list item in the list.
I would create a new presentational component called modal, then use that when you need it, rather than do what you're trying to do now, which is pass an open/close state. The Modal can be a simple presentational component that just accepts props. By doing it this way, you create reusability.
function Modal(props) {
return (
<div className={props.css.awesomeLayout}>
{props.aProp}
</div>
)
}

How to make 'this' refer to App, not modal

In my EditRecipeForm component, when editing text in the modal, I get Uncaught TypeError: this.setState is not a function , because this refers to the modal window, and not the "app", the thing I don't understand is how to get this to be correct, so that editing the field value updates actually works.
(I removed code not directly related), full demo available here: http://codepen.io/pdewouters/pen/adLpvQ
const Button = ReactBootstrap.Button,
Accordion = ReactBootstrap.Accordion,
Panel = ReactBootstrap.Panel,
Modal = ReactBootstrap.Modal,
Input = ReactBootstrap.Input,
ButtonToolbar = ReactBootstrap.ButtonToolbar,
ButtonInput = ReactBootstrap.ButtonInput,
ListGroup = ReactBootstrap.ListGroup,
ListGroupItem = ReactBootstrap.ListGroupItem
class App extends React.Component {
constructor(props){
super(props)
this.state = {
showModal: false,
showEditModal: false,
recipes: [],
recipeName: '',
ingredients: '',
editRecipeNameInputVal: '',
editIngredientsInputVal: '',
recipeToEdit: {recipeName:'',ingredients:''}
}
}
closeEditModal(){
this.setState({ showEditModal: false })
}
openEditModal(recipe){
this.setState({showEditModal:true,recipeToEdit:recipe})
}
handleRecipeEditInputChange(value){
this.setState({editRecipeNameInputVal: value})
}
handleIngredientsEditInputChange(value){
this.setState({editIngredientsNameInputVal: value})
}
render(){
return(
<div className="container">
<div className="page-header">
<h1>Recipes</h1>
</div>
<div className="row">
<div className="col-md-12">
<EditRecipeForm
showModal={this.state.showEditModal}
closeModal={this.closeEditModal.bind(this)}
handleSubmit={this.handleEditFormSubmit.bind(this)}
handleRecipeEditInputChange={this.handleRecipeEditInputChange.bind(this)}
handleIngredientsEditInputChange={this.handleIngredientsEditInputChange.bind(this)}
recipe={this.state.recipeToEdit}
handleRecipeEditInputChange={this.handleRecipeEditInputChange}
handleIngredientsEditInputChange={this.handleIngredientsEditInputChange} />
<RecipeList recipes={this.state.recipes}
handleDeleteRecipe={this.handleDeleteRecipe.bind(this)}
handleOpenEditModal={this.openEditModal.bind(this)}
/>
</div>
</div>
</div>
)
}
}
class RecipeList extends React.Component {
handleOpenEditModal(recipe,event) {
this.props.handleOpenEditModal(recipe)
}
render(){
let recipes = this.props.recipes.map((recipe,index)=>{
return (
<Panel header={recipe.recipeName} eventKey={index}>
<IngredientsList ingredients={recipe.ingredients} />
<ButtonToolbar>
<Button bsStyle="danger" onClick={this.props.handleDeleteRecipe.bind(null,index)}>Delete</Button>
<Button bsStyle="primary" onClick={this.handleOpenEditModal.bind(this,recipe)}>Edit</Button>
</ButtonToolbar>
</Panel>
)
})
return (
<Accordion>
{recipes}
</Accordion>
)
}
}
class EditRecipeForm extends React.Component {
handleRecipeEditInputChange(e){
this.props.handleRecipeEditInputChange(e.target.value)
}
handleIngredientsEditInputChange(e){
this.props.handleIngredientsEditInputChange(e.target.value)
}
render(){
return(
<Modal show={this.props.showModal} onHide={this.props.closeModal}>
<Modal.Header closeButton>
<Modal.Title>Edit recipe</Modal.Title>
</Modal.Header>
<Modal.Body>
<form onSubmit={this.props.handleSubmit}>
<Input type="text"
label="Recipe"
placeholder="blueberry pancakes"
value={this.props.recipe.recipeName}
onChange={this.handleRecipeEditInputChange.bind(this)} />
<Input type="textarea"
label="Ingredients"
placeholder="milk,sugar,flour,butter,blueberries"
value={this.props.recipe.ingredients}
onChange={this.handleIngredientsEditInputChange.bind(this)} />
<ButtonInput type="submit" value="Save changes" />
</form>
</Modal.Body>
<Modal.Footer>
<Button onClick={this.props.closeModal}>Close</Button>
</Modal.Footer>
</Modal>
)
}
}
React.render(<App />, document.querySelector('.app'))
It looks like you're passing the handleRecipeEditInputChange and handleIngredientsEditInputChange prop callbacks twice and the second time you are not binding to the component instance.
<EditRecipeForm
showModal={this.state.showEditModal}
closeModal={this.closeEditModal.bind(this)}
handleSubmit={this.handleEditFormSubmit.bind(this)}
handleRecipeEditInputChange={this.handleRecipeEditInputChange.bind(this)}
handleIngredientsEditInputChange={this.handleIngredientsEditInputChange.bind(this)}
recipe={this.state.recipeToEdit}
handleRecipeEditInputChange={this.handleRecipeEditInputChange}
handleIngredientsEditInputChange={this.handleIngredientsEditInputChange} />
The second props will overwrite the first ones, so try deleting the second ones.

Resources