onclick show and hide data in react.js - javascript

i have component which is showing data in the webpage
I want to write another component and create buutton in it. which just hide other component on clicking the button and show basic input field form.
My code is something like this
component app
class App extends React.Component{
constructor(props) {
super(props);
this.state= {
filter: null,
};
this.setFilter = this.setFilter.bind(this);
}
setFilter(filter) {
this.setState({filter: filter})
}
render(){
let filteredPassword = details_data.filter(
(detail) =>{
console.log(detail.website.toLowerCase(), this.state.filter)
return detail.website.toLowerCase().indexOf(this.state.filter)!= -1;
}
);
return (
<ul>
<Filter onUpdateFilter={this.setFilter} />
{
filteredPassword.map((detail)=>{
return <Detail item={detail}
key={detail.id}/>
})
}
</ul>
)
}
}
Another Detail component
class Filter extends React.Component{
constructor() {
super();
this.state={
search: 'Search'
}
}
updateSearch(event) {
this.props.onUpdateFilter(event.target.value.substr(0,40))
}
formShow(){
}
render() {
return (
<div>
<input id="search" type="text" placeholder={this.state.search} onChange={this.updateSearch.bind(this)}/>
<input id="button1" type="button" value="+" onClick={this.formShow()}/>
</div>
)
}
}
Few other component like this.
i am trying to hide the table and form button above is used to "show form" button.
class Form extends React.Component {
render() {
return(
<div>
<form>
<input type="text" placeholder="username" />
<input type="password" placeholder="username" />
</form>
</div>
)
}
}
Guide me how to do this.. thank you

Without looking too much to your code (it's a bit messy) it seems to me what you want to achieve is to communicate two components. Component A will react to a button click event and tell: 1) component B to hide and 2) component C to show up.
The way of doing this depends on if the components have hierarchical relationship or not. I would recommend start by reading this chapter of the official React documentation. Then, here is also a great article on component communication strategies in React.
On top of that, some patterns that focus specifically on this have achieved great success, like Flux or Redux.
Hope it helps.

Related

How can I make the default value of an input changeable in ReactJS?

I am new to working with React so this might be an easy one that I am struggling to figure out. Let's say I have this very simple class, that renders an input with a default value. I want this input to have the value I set it, but also being able to change it. However, when it renders, the input field is filled with "hi" and I can't write or delete anything over it. How can I make this possible?
export class Hello extends React.Component {
render(){
let i = "hi"
return(
<div>
<input type="input" value={i} />
</div>
);
}
}
Store the input value as part of your component's state, and listen for the onchange event on the input field to update the component's state.
export class Hello extends React.Component {
state = {
textbox: "hi",
};
render() {
return(
<div>
<input
type="input"
value={this.state.textbox}
onChange={ev => this.setState({ textbox: ev.target.value })}
/>
</div>
);
}
}
See examples: https://reactjs.org/docs/forms.html#controlled-components
You need to use state for this purposes. Look here: https://reactjs.org/docs/forms.html#controlled-components
I'am adding a bit different answer, its depends if your component is Controlled or Uncontrolled component, see difference in docs.
Controlled example you can find in other answers or docs.
Uncontrolled example is usually when using <form/> elements, in this case you can just add defaulValue prop as mentioned in related docs.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" defaultValue="hi" ref={this.input} />
<input type="submit" value="Submit" />
</form>
);
}
}

React : Pass conditional renderings data

Assuming that this is a Toggle component to hide and display data, when called alone it's working perfectly.
Now I have a dashboard.js where I will be calling this component, but I only want to output the data, keeping the toggle switch separated in his file.
How do I pass data from the Toggle component to the Dashboard component ?
Still newbie in React and from what I learned apparently you can't pass data from child to parent.
import React, { Component } from 'react';
export default class Toggle extends React.Component{
constructor(){
super();
this.state={isShowBody: false}
}
handleClick(event) {
this.setState({isShowBody: !this.state.isShowBody})
}
render() {
return (
<div >
<div >
<span className="switch switch-sm" >
<label>
<input type="checkbox" name="select" onClick={this.handleClick.bind(this)}/>
<span />
</label>
</span>
</div>
{this.state.isShowBody ?
<div>
Data test
</div>
: null}
</div>
);
}
}
This might give you more insight in addition to what the previous answer is: Using Redux would definitely a good option but that entirely depends on the complexity of the project.
export class Toggle extends React.Component {
constructor(){
super();
this.state={
isShowBody: false
}
}
handleClick = (event) => {
this.setState({ isShowBody: !this.state.isShowBody })
}
checkbox = () => {
return (
<span className="switch switch-sm" >
<label>
<input type="checkbox" name="select" onClick={() => this.handleClick(this)}/>
</label>
</span>
)
}
dataTest = () => {
return (
<div>
Data test
</div>
)
}
render() {
return (
<div>
{this.checkbox()}
{this.state.isShowBody && this.dataTest()}
/**
* You can extract this dataSet into another component as well where you can pass initial visibility value as this.state.isShowBody
* for example
* <Dataset visibility={this.state.isShowBody} />
* */
</div>
);
}
}
If you want the parent to have information the child has you need to left up the state to the parent component and pass it to the child.
If your component has the potential to become bigger, keeping lifting up the state will become a problem so consider using a state management library like Redux.

Accessing the data from one component to another component

Hi I am starting to learn reactjs. So after understanding the basics Im starting to work on database connectivity using reactjs. In the code Im trying to get the userId and Password to establish a DB connectivity and trying to list the tables available in the DB. In the Login.js I have create a form (userId and Password) when login button is clicked I will make a connectivity and execute the Show Table query to list all the tables in the DB, and move to the Table.js page where I try to list the available tables. Right now I able to connect to the DB but not able to display the tables in the Table.js, so how to display the tables list in the Table.js file, because I have placed my DB connectivity and query inside a button event in the Login.js. Also Is there a possible to declare a variable global and access it across the another js files. Any help would be great, thank you.
Login.js
import React from 'react';
import TableContent from './tables';
class Login extends React.Component{
constructor(){
super();
this.state={
showComponent : false,
};
// this.buttonClick = this.buttonClick.bind(this);
}
buttonClick(event){
event.preventDefault();
this.setState({
showComponent: true,
})
var db = require('#dataBase/dynamoConnect')({
"UserId": "XXXXXXXXXXXXXXXXXXXXXXXX",
"Password": "YYYYYYYYYYYYYYY",
"region": "ZZZZZZZZZZ"
});
db.query("SHOW TABLES",(err,data)=>{
const tableList = data;
console.log(tableList);
})
}
render(){
return(
<div>
<form>
<label>User Id :</label>
<input type="text" className="test"/>
<br/>
<label>Password :</label>
<input type="text" className="test" />
<button onClick={this.buttonClick.bind(this)} className="connect" > Login</button>
</form>
{this.state.showComponent && <TableContent />}
</div>
)
}
}
export default Login;
Table.js
import React from 'react';
class TableContent extends React.Component {
constructor() {
super();
this.state = {
showComponent: false,
};
this.buttonClick = this.buttonClick.bind(this);
}
buttonClick(event) {
event.preventDefault();
this.setState({
showComponent: true,
})
}
render() {
return (
<div>
<form>
<div id="first">
<label> Table </label>
<br />
//Display the tables from DB here
<select name="sometext" multiple="multiple" >
<option>Table1</option>
<option>Table2</option>
<option>Table3</option>
<option>Table4</option>
<option>Table5</option>
</select>
</div>
<div id="second">
<label> SQL </label>
<br/>
<textarea rows="4" cols="50">SQL </textarea>
</div>
<button onClick={this.buttonClick.bind(this)} > Execute </button>
<div id="third" >
{this.state.showComponent && <SampleTable />}
</div>
</form>
</div>
)
}
}
export default TableContent;
First.
The Table.js component need to know the data to display.
1 - you have to save result of the query in component state, by calling this.setState({tableData: tableList}) in query callback:
db.query("SHOW TABLES",(err,data)=>{
const tableList = data;
this.setState({
tableData: tableList,
});
})
2 - you need to pass saved result as a property to TableContent, like this:
in Login.js:
{this.state.showComponent && <TableContent data={this.state.tableData} />};
3 - render data in the child component. You can get access to it via this.props.data. You can iterate over an result array and render all table rows in single loop. Take a look at this react doc.
Second:
Also Is there a possible to declare a variable global and access it across the another js files
In short - yes. You can export functions, variables, classess from your module.
Small example:
// scriptA.js;
export const a = 42;
// scriptB.js;
import { a } from 'path/to/scriptA.js';
console.log(a) // will print 42;
This example assumes you are using es6 import/export feature. You can require it as well.
There are a number of strategies for communicating between components, but the easiest way (without using Flux or Redux) is to use a parent component to act as a mediator for the communication.
Basically, the parent passes a callback to one component that sets some state to pass down the the other component, for example:
Child creating data
class Child1 extends React.Component {
constructor() {
super()
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.props.setMessage("hello world")
}
render() {
return <button onClick={this.handleClick}>say hello</button>
}
}
Child using data
const Child2 = ({message}) => {
return <p>{message}</p>
}
Parent
class Parent extends React.Component {
constructor() {
super()
this.state = { message: "" }
}
render() {
return (
<div>
<Child1 setMessage={(message) => this.setState({ message })} />
<Child2 message={this.state.message} />
</div>
)
}
}
If they can't be siblings, this pattern can get a bit strenuous, but can still be achieved by having the mediator component as the lowest common ancestor and passing the relevant props all the way down. At that point though, you may want to investigate Flux or Redux and externalising the state from the components entirely.

How can a component send a message to its sibling without moving the state up the component tree?

I've got a "page" component which houses a form and a list. The form and the list are completely self-contained and disjoint except for the fact that when you save the form, the list should refresh.
My page component looks like this, in its entirety:
export default class PaymentsPage extends React.PureComponent {
static propTypes = {
bookingId: XPropTypes.stringOrNumber.isRequired,
test: PropTypes.bool,
stripePublishableKey: PropTypes.string,
stripeUserId: PropTypes.string,
};
render() {
return (
<div>
<ContentSection title="Enter Payment" storageKey="record-payment">
<RecordPaymentForm bookingId={this.props.bookingId} test={this.props.test} />
</ContentSection>
<ContentSection title="Previous Payments" storageKey="previous-payments">
<PreviousPaymentsTable bookingId={this.props.bookingId} test={this.props.test} stripePublishableKey={this.props.stripePublishableKey} stripeUserId={this.props.stripeUserId} />
</ContentSection>
</div>
)
}
}
My question is, how can RecordPaymentForm send a message to PreviousPaymentsTable to tell it to refresh?
I don't want to move RecordPaymentForm's state up into PaymentsPage because I want it to remain self-contained.
I'm not using flux/redux, nor do I plan on it right now.
Using mufa (event oriented programming), communication among siblings will be as following :
Component Sender (Publisher) :
import {fire} from 'mufa';
class RecordPaymentForm extends React.Component {
// Assuming that the trigger to send the message is the following
handleClick() {
const message = 'this is a message from RecordPaymentForm';
fire('sendSomething', message);
}
}
Component Receiver (Subscriber) :
import {on} from 'mufa';
class PreviousPaymentsTable extends React.Component {
componentDidMount() {
on('sendSomething', (message) => {
this.setState({recordPaymenetMessage: message});
})
}
}
//if your are using npm => import {on, fire} from 'mufa';
const {on, fire} = window.mufa;
class RecordPaymentForm extends React.Component {
onClick(event) {
fire('addPayment', this.refs.item.value, this.refs.price.value);
}
render() {
return (
<div>
<input ref="item" placeholder="item name" />
<input ref="price" placeholder="price" type="number" />
<button onClick={this.onClick.bind(this)}>Add</button>
</div>
)
}
}
class PreviousPaymentsTable extends React.Component {
state={records:[]}
componentDidMount() {
on('addPayment', (item, price) => {
this.setState({records: [...this.state.records, {item, price}]});
})
}
render() {
return (
<ul>
{
this.state.records.map((r, index) =>
<li key={index}> <b> {r.item} : </b> {r.price} $ </li>)
}
</ul>
)
}
}
class App extends React.Component {
render() {
return (
<div>
<RecordPaymentForm />
<PreviousPaymentsTable />
</div>
)
}
}
ReactDOM.render(<App />, document.querySelector('section'))
<script src="https://cdn.rawgit.com/abdennour/mufa/ddf78fd9/cdn/mufa-latest.min.js"></script>
<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>
<section />
General Rules for React with Event-driven :
publish (fire) : is called in events handlers.
subscribe (on) : is called in componentDidMount.
unsubscribe (off) : is called in componentWillUnmount
I don't want to move RecordPaymentForm's state up into PaymentsPage because I want it to remain self-contained.
To your point above, RecordPaymentForm isn't self contained if you want it to update another component.
The proper "React" way to handle this situation is to store the shared state for both RecordPaymentForm and PreviousPaymentsTable in the parent component (PaymentsPage) and pass it into each child component.
To update the state of PaymentsPage from RecordPaymentForm, you can pass a function as a prop to act as a handler. and you can create the handleChange function in PaymentsPage.
export default class PaymentsPage extends React.PureComponent {
static propTypes = {
bookingId: XPropTypes.stringOrNumber.isRequired,
test: PropTypes.bool,
stripePublishableKey: PropTypes.string,
stripeUserId: PropTypes.string,
};
handleChange(newValue) => {
this.setState({
someProp: newValue;
});
}
render() {
return (
<div>
<ContentSection title="Enter Payment" storageKey="record-payment">
<RecordPaymentForm
bookingId={this.props.bookingId}
onChange={this.handleChange}
someProp={this.props.someProp}
test={this.props.test}
/>
</ContentSection>
<ContentSection title="Previous Payments" storageKey="previous-payments">
<PreviousPaymentsTable
bookingId={this.props.bookingId}
test={this.props.test}
someProp={this.props.someProp}
stripePublishableKey={this.props.stripePublishableKey}
stripeUserId={this.props.stripeUserId}
/>
</ContentSection>
</div>
)
}
}
I just implemented PubSubJS in about 3 lines of code. I think it will work well for this particular use-case.
When a payment is entered, I publish a "paymentEntered" event. Any component that's interested (such as my PreviousPaymentsTable) can subscribe to that topic, and then do what it needs to.
More-over, I could even publish the payment data and pop it into my payments list so that I don't have to do a full refresh, but I'm going to anyway because I already have the code for it and I don't mind a 50ms delay for fresh data.
This way my payments page remains dumb, and I can move these components around to any page, and re-use them where ever I please, with or without each-other, and they'll continue to work.

Calling a ref from another component (?)

I am working with React in a chat application. I need that evertytime you click on the chat box the input where you enter your messagges, should be focused.
The problem I have is that the chat box which is in the main component, is separately from the component where the input to enter the messages is.
Look, main component
class ChatView extends React.Component {
constructor (props) {
super(props);
this._inputFocus = this._inputFocus.bind(this);
}
_inputFocus () {
let input = React.findDOMNode(this.refs.SHOULDFOCUS-HERE);
input.focus();
}
render () {
if (this.props.mode === 'player') {
dealerPlayerMessages = <ul ref="messages">{messages}</ul>;
// CHAT FORM IS THE COMPONENT CONTAINING THE INPUT
chatForm = <ChatForm onAddMessage={this.addMessage} />;
chatBox = <div>{dealerPlayerMessages}{chatForm}</div>
}
return <div className="dealer-player-box" onClick={this._inputFocus} >
{chatBox}
</div>;
}
}
so, as you see, when you click in the div with class name dealer-player-box, the function this._inputFocus is called.
But the input to enter your message text, is in the component ChatForm:
class ChatForm extends React.Component {
constructor (props) {
super(props);
}
render () {
return (<div className="chat-form">
// THIS IS THE INPUT I NEED TO FOCUS ON
<input className="input-form"
placeholder="Your message..."
ref="SHOULDFOCUS-HERE"
autofocus="true" />
</div>);
}
}
so, from the main component, what should I do in order to focus on that input since in another component ?
Add a ref to your ChatForm:
<ChatForm ref="chatForm" onAddMessage={this.addMessage} />;
In your ChatForm change the input ref to something meaningful:
<input className="input-form"
placeholder="Your message..."
ref="chatInput"
autofocus="true" />
In your ChatForm component add a method which focuses:
focusInput() {
this.refs.chatInput.focus();
}
In your ChatView component modify the _inputFocus method:
_inputFocus() {
this.refs.chatForm.focusInput();
}
Note that using refs might be a little different if you are using deprecated versions of react (<0.14).

Categories

Resources