Calling a function from outside of Reactjs class - javascript

I am fairly new to Reactjs and am running into an issue. I am using Griddle to display my data and using a Custom Component as a Column Definition. This custom component is defined outside of the class that contains the Griddle render and contains two buttons - Delete and Edit. I need to be able to click on either button and launch a modal, which I am using React Modal for. If I put a button within the class I can launch the modal as expected, however, when I am trying to launch the modal from one of the Edit or Delete buttons it does not work and I get an error
Uncaught TypeError: M.handleOpenModal is not a function.
Here is the code for the component that uses the Griddle plugin:
const actionComponent = ({ value }) =>
<div>
<i className="fas fa-edit"></i> Edit
<i className="fas fa-times"></i> Delete
</div>
const handleModalOpen = function () {
LinersTable.handleOpenModal();
}
export default class LinersTable extends React.Component {
constructor(props) {
super(props);
this.state = { liners: [], station: '', loading: true, selectedRowId: 0 };
this.modalElement = React.createRef();
this.options = {
defaultSortName: 'title', // default sort column name
defaultSortOrder: 'desc' // default sort order
};
}
handleOpenModal() {
alert();
}
render() {
let contents = this.state.loading ? <p><em>Loading...</em></p> : this.renderLinersTable(this.state.liners);
return <div>
<button className='btn btn-primary' onClick={() => { this.refreshData() }}>Refresh</button>
<a href="LinerReads/Studio" className='btn btn-primary'>Studio View</a>
<a href="LinerReads/Add" className='btn btn-primary'>Add</a>
<LinersStations onChange={this.handleStationChange.bind(this)} />
<ModalWindow ref={this.modalElement} />
{contents}
</div>;
}
renderLinersTable(liners) {
return (
<Griddle
styleConfig={styleConfig}
data={liners}
plugins={[plugins.LocalPlugin]}
components={{ Layout: NewLayout }}>
<RowDefinition>
<ColumnDefinition id="title" title="Title" order={1} width={600} />
<ColumnDefinition id="startDateString" title="Start" order={2} width={200} />
<ColumnDefinition id="endDateString" title="End" order={3} width={200} />
<ColumnDefinition id="linerID" title="Actions" customComponent={actionComponent} width={200} />
</RowDefinition>
</Griddle>
)
}
}
I have tried moving the Custom Component inside the class
handleModalOpen = function () {
this.handleOpenModal();
}
handleOpenModal() {
alert();
}
but it then throws an error
ReferenceError: handleModalOpen is not defined
Uncaught (in promise) ReferenceError: handleModalOpen is not defined
Anyone have a suggestion as to what I am missing or doing incorrect?

Related

how to call components in Reactjs?

class App extends React.Component {
constructor() {
super();
this.state = {
activeTab: "add",
items: [],
}
}
handleClick(activeTab) {
switch (activeTab) {
case 'add': return <Add/>
case 'list': return <List />
case 'pay': return <Pay />
}
}
render() {
return (
<div className="App btn-group">
<Button onClick={this.handleClick.bind(this, 'add')}><Add /></Button>
<Button onClick={this.handleClick.bind(this, 'list')}><List /></Button>
<Button onClick={this.handleClick.bind(this, 'pay')}><Pay /></Button>
</div>
)
}
}
export default App;
I wish through this code in reactjs, When I onClick on an 'add' button it shows me the Add components but unfortunately it does not work. On the other hand in my switch when I do an alert () or a console.log () instead of returning my components; it works well as it should.
the <Add /> List and Pay are components and I have imported into the app.js.
there are several issues with your code.
if you want to show the components based on your active Tab you have to maintain the state variable . I see you have set your initial state activeTab : "add" but trying to render <Add /> component inside a button . that's why it doesn't work as expected . you have to render it separately .
your handleClick function is supposed to do something . not return something. so here if you return your components inside switch that won't work. you can change the state here.
you can use the conditional rendering feature of react to render the desired component based on your active tab as shown below.
here is the complete component code that should solve the problems i mentioned above
class App extends React.Component {
constructor() {
super();
this.state = {
activeTab: "add",
items: [],
}
}
handleClick(activeTab) {
this.setState({activeTab})
}
render() {
return (
<div>
<div className="App btn-group">
<Button onClick={this.handleClick.bind(this, 'add')}> Add </Button>
<Button onClick={this.handleClick.bind(this, 'list')}> List </Button>
<Button onClick={this.handleClick.bind(this, 'pay')}> Pay </Button>
</div>
{this.state.activeTab === 'add' && <Add /> }
{this.state.activeTab === 'list' && <List /> }
{this.state.activeTab === 'pay' && <Pay /> }
</div>
)
}
}
export default App;

cannot read property 'function name' of undefined React js

im working with the modal from https://react-bootstrap.netlify.app/components/modal/ and basically i've managed to display a modal from a button that i click. However inside the modal there's another button that when i click should perform a task i've defined in a function already. Now when i click this button in the modal i get the error cannot read property 'confirm_booking' of undefined Here is my code.
constructor(props){
super(props)
this.state={
setModalShow_available_room: false,
modalShow_available_room: false
}
this.confirm_booking = this.confirm_booking.bind(this)
}
render (){
function Available_room_modal(props) {
return (
<Modal
{...props}
size="sm"
aria-labelledby="contained-modal-title-vcenter"
centered>
<Modal.Body>
<Button block onClick={() => { this.confirm_booking() }} >Confirm</Button>
</Modal.Body>
</Modal>
);
}
return(
<div>
<Button block onClick={() => { this.open_modal() }} >Show modal</Button>
<Available_room_modal
show={this.state.modalShow_available_room}
onHide={() => {
this.setState({ setModalShow_available_room: false })
this.setState({ modalShow_available_room: false })
}} />
</div>
)
}
/**then for my functions **/
/**this opens the modal **/
open_modal() {
this.setState({ setModalShow_available_room: true })
this.setState({ modalShow_available_room: true })
}
/**this is the function assigned to the button inside the modal which throws an error when i click it**/
confirm_booking() {
this.setState({ setModalShow_available_room: false })
this.setState({ modalShow_available_room: false })
}
you are clearly not understanding how react works. Please try to see the react documentation first.
I will try to show you some of your errors:
You can't declare a function inside render method. Render method is just to return JSX code. You could declare a function in the class, return jsx from there and call it from render, that is valid.
<Button block onClick={() => { this.confirm_booking() }} >Confirm</Button>
Here, you are calling this.confirm_booking EVERY time your component is being rendered. You should change it to this:
<Button block onClick={this.confirm_booking}> Confirm </Button>

I want Popup to close, how do I do it?

When I press the AddAction button from the Addaction component, I want the popup to close. ?
in fact, if I reach the onCloseAddActionModal method in my component which is popup from AddAction component, my problem will be solved.
AddAction Component:
class AddAction extends React.Component {
constructor() {
super();
this.state = {
items: [{id:null, actiontype: null}],
error: null,
isLoaded: false,
selectId: null,
}
this.handleCheckChieldElement =
this.handleCheckChieldElement.bind(this); // set this, because you need get methods from CheckBox
}
componentDidMount = () => {
....
}
fetchAdd = (carid, offboardingactiontypeid) => {
...
}
handleCheckChieldElement = (id, e) => {
this.setState({selectId: id})
}
render() {
const items = this.state.items;
return (
<div>
<ul className="popupAddAction">
{
items.map((item) => {
return (
<li className="list" key={item.id}>
<input key={item.id} onClick=
{(e)
=>
this.handleCheckChieldElement(item.id,
e)} type="checkbox" />
{item.actiontype}
</li>
)
})
}
</ul>
<div className="popupAddAction--btn">
<button
onClick=
{ () =>
this.fetchAdd(this.props.id, this.state.selectId)}
className="btn btn-primary
popupAddAction--btn"
>
Add Action
</button>
</div>
</div>
);
}
}
export default AddAction;
Popup Component:
class OffBoarding extends Component {
this.state = {
openAddAction: false
};
onOpenAddActionModal = () => {
this.setState({ openAddAction: true });
};
onCloseAddActionModal = () => {
this.setState({ openAddAction: false });
};
render(){
return{
<div>
<Button className="btn btn-danger commentPlus" onClick=
{this.onOpenAddActionModal}> <FontAwesomeIcon icon=
{faPlus}/></Button>
</div>
{this.state.openAddAction ?
<div style={styles}>
<Modal open=
{this.state.openAddAction} onClose=
{this.onCloseAddActionModal} center>
<AddAction id=
{this.state.carid}
close=
{this.state.openAddAction}/>
</Modal>
</div> : null
}}
}}
You can simply pass the onCloseAddActionModal method as prop while rendering AddAction component from OffBoarding component. And then, you can call that passed function as prop on "Add Action" button click i.e.
So in you popup component, change this:
<AddAction id=
{this.state.carid}
close={this.state.openAddAction}/>
to this (passing function as prop):
<AddAction id=
{this.state.carid}
close={this.state.openAddAction}
closeDialog={this.onCloseAddActionModal}/>
And then in your AddAction component, change this:
<button
onClick={() =>
this.fetchAdd(this.props.id, this.state.selectId)}
className="btn btn-primary popupAddAction--btn">
Add Action
</button>
to this (calling function passed as prop in previous step):
<button
onClick=
{() =>{
this.fetchAdd(this.props.id, this.state.selectId);
this.props.closeDialog();
}}
className="btn btn-primary popupAddAction--btn">
Add Action
</button>
If openAddAction flag is true then only addaction component will display right. Instead of open and close modal add below code to modal and in add action modal in fetch method set openAddAction to false. in your code you have communication from child to parent but you are trying to close modal based on child but modal exist in parent so make a communication to parent to child for that pass function through component
<Modal isOpen = {this.state.openAddAction} center>
<AddAction id= {this.state.carid}
closeModa={this.onCloseAddActionModal} />
</Modal>
In addAction modal you have to add like this
fetchAdd = (carid, offboardingactiontypeid) => {
this.setState({openAddAction:false});
this.props.onCloseAddActionModal();
}
Call this closeModal method in fetchAdd method

onClick fires multiple time in React.js

I have following component.
import React from 'react'
import Profile from './Profile'
import Messages from './Messages'
class ContactContent extends React.Component {
constructor () {
super()
this.state = {
message: ''
}
this.handleOnClick = (e) => {
e.preventDefault()
console.log('send message called')
// this.props.onSendMessage(this.state.message)
}
}
render () {
const { id, name, profile, messages } = this.props.user
return (
<div className='content'>
<Profile
name={id}
profile={profile}
/>
<Messages
messages={messages}
/>
<div className='message-input'>
<div className='wrap'>
<input type='text' placeholder='Write your message...' onChange={(e) => this.setState({ message: e.target.value })} />
{/* <i className="fa fa-paperclip attachment" aria-hidden="true"></i> */}
<button className='' onClick={this.handleOnClick}><i className='fa fa-paper-plane' aria-hidden='true' /></button>
</div>
</div>
</div>
)
}
}
export default ContactContent
when I click on button onclick is called which triggers handleonclick function. but handleonclick is being called like infinit time. this is a weird behavior I have seen this first time any idea what I have done wrong?
Fixed it there was an external javascript file which was creating this issue. Nothing is wrong with the code.
No, you are calling the handleOnClick each time on page load/render load here
So without making this, or to avoid multiple call try to use:
fat arrow call of that function on onClick event.
<button className='' onClick={(e) => this.handleOnClick(e)}><i className='fa fa-paper-plane' aria-hidden='true' /></button>

ReactJS Modal opening multiple times when in a Loop

Hi I am playing around with ReactJS, and found this awesome Modal Component to open Videoes in a Modal, but when I put the Modal inside a loop with multiple links and open the modal, it open like 5 times if I have 5 links. What do I do wrong?
Modal Component: https://github.com/appleple/react-modal-video
import React from 'react'
import ReactDOM from 'react-dom'enter code here
import ModalVideo from 'react-modal-video'
class App extends React.Component {
constructor () {
super()
this.state = {
isOpen: false
}
this.openModal = this.openModal.bind(this)
}
openModal () {
this.setState({isOpen: true})
}
render () {
return (
<div>
<ModalVideo channel='youtube' isOpen={this.state.isOpen} videoId='L61p2uyiMSo' />
<button onClick={this.openModal}>Open</button>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
My Loop with the Modal Component Inside:
render(){
return(
<div>
{(this.props.frag.all == null) ? null :
this.props.frag.all.map((frags, i) => {
return (
<li key={frags.id} className="group" id="" style={{width: 'calc(13% - 30px)'}}>
<ModalVideo channel='youtube' isOpen={this.state.isOpen} videoId='{frags.url}' />
<button onClick= {this.openModal.bind(this)}>Open</button>
</li>
)})
}
</div>
The problem is that each ModalComponent uses the same state property isOpen so when you click on any link it sets this property and each ModalComponent becomes open. You should use unique property for each modal (you can use poperty which you already uses as key).
<li key={frags.id} className="group" id="" style={{width: 'calc(13% - 30px)'}}>
<ModalVideo channel='youtube' isOpen={this.state.isOpen[frags.id]} videoId='{frags.url}' />
<button onClick= {this.openModal.bind(this, frags.id)}>Open</button>
</li>
And your method:
openModal (id) {
this.setState({
isOpen: {
[id]: true
}
});
}
Reason is, you are using single state variable to maintain open/close status of modal, it will work properly for one, but in case of multiple modals, you have to use multiple state values to maintain the statuses, Use this:
Define isOpen as an array in state:
this.state= {
isOpen=[],
}
Use this method to change the status of any particular modal:
openModal(index){
let isOpen = this.state.isOpen.slice();
isOpen[index] = true;
this.setState({isOpen});
}
Bind the index of each modal in onClick method:
render(){
return(
<div>
{(this.props.frag.all == null) ? null :
this.props.frag.all.map((frags, i) => {
return (
<li key={frags.id} className="group" id="" style={{width: 'calc(13% - 30px)'}}>
<ModalVideo channel='youtube' isOpen={this.state.isOpen[i] || false} videoId='{frags.url}' />
<button onClick= {this.openModal.bind(this,i)}>Open</button>
</li>
)})
}
</div>
)
}
Modals in a loop are a bit complicated because they need a unique key for each row. Making the modal work without duplicating it is another challenge. The first mistake many of us make is including the modal within the loop. To prevent the duplication of the modal we need to make it fully dynamically. I have included a full example without having to duplicate the modal inside of the loop. I hope that helps
here is a full example
import React, { Component } from 'react';
import { Button, Alert, Input, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
class History extends Component
{
constructor(props)
{
super(props);
this.state = {
userHistory: [{'id': 1, 'test': 'this is a test'}, {'id': 2, 'test': 'this is a test2'}, {'id': 3, 'test': 'this is a test3'}],
showLog: false,
logID: null
}
}
render()
{
const history = this.state.userHistory.map( (ticket, key) =>
{
return (
<tr key={key}>
<td>{ticket.test}</td>
<td>{ticket.id ? <Button color="info" onClick={() => this.setState({logID: ticket.id, showLog: true})}>View</Button> : ''}</td>
</tr>
)
});
return (
<div className="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>test</th>
<th>modal</th>
</tr>
</thead>
<tbody>
{history}
</tbody>
</table>
<Modal id={this.state.logID} isOpen={this.state.showLog} fade="false" toggle={() => this.setState({showLog: false})}>
<ModalHeader toggle={() => this.setState({showLog: false})}>#jerryurenaa is awesome :D</ModalHeader>
<ModalBody>
<p>Modal Number: {this.state.logID}</p>
</ModalBody>
<ModalFooter>
<Button onClick={() => this.setState({showLog: false})}>Cancel</Button>
</ModalFooter>
</Modal>
</div>
);
}
}
export default History;

Categories