I'm stuck on my note taking app. Basically the App component passes in data to the NoteEntry component through props. Yet I can't figure out how to edit the previous passed text through props within each NoteEntry instance when I click the "edit" button. The edit button is supposed to bring up text inputs to change the content by updating the text and then pressing the save button. Any tips on how to go about it?
class App extends Component {
constructor(props) {
super(props);
this.state = {
notes: [],
title: "",
details: ""
}
this.updateTitle = this.updateTitle.bind(this);
this.updateDetails = this.updateDetails.bind(this);
this.submitHandler = this.submitHandler.bind(this);
this.deleteHandler = this.deleteHandler.bind(this);
}
updateTitle(event) {
this.setState({ title: event.target.value });
}
updateDetails(event) {
this.setState({ details: event.target.value });
}
submitHandler(e) {
e.preventDefault();
if (!this.state.title.length || !this.state.details.length) {
return;
}
const newNote = {
newTitle: this.state.title,
newDetails: this.state.details
}
this.setState(prevState => ({
notes: prevState.notes.concat(newNote),
title: "",
details: ""
}))
}
deleteHandler(id) {
this.setState(prevState => ({
notes: prevState.notes.filter(el => el !== id)
}))
}
render() {
return (
<div className="container">
<h1 className="title">React Notes App</h1>
<NoteForm
titleValue={this.state.title}
detailsValue={this.state.details}
titleHandle={this.updateTitle}
detailsHandle={this.updateDetails}
onSubmit={this.submitHandler}
/>
<div className="entry-section">
{this.state.notes.map((note, i) => (
<NoteEntry
key={i}
title={note.newTitle}
details={note.newDetails}
deleteNote={this.deleteHandler.bind(this, note)}
/>
))}
</div>
</div>
);
}
}
const NoteForm = (props) => {
return (
<div>
<form className="form-section">
<input
className="title-input"
type="type"
placeholder="Title"
value={props.titleValue}
onChange={props.titleHandle}
/>
<br />
<textarea
className="details-input"
cols="20"
rows="3"
placeholder="Details"
value={props.detailsValue}
onChange={props.detailsHandle}
/>
<br />
<button
className="input-button"
onClick={props.onSubmit}
>Add Note</button>
</form>
</div>
)
}
class NoteEntry extends Component {
constructor(props) {
super(props);
this.state = {
display: false,
editTitle: this.props.title,
editDetails: this.props.details,
editing: false
}
this.displayToggle = this.displayToggle.bind(this);
this.edit = this.edit.bind(this);
this.save = this.save.bind(this);
}
displayToggle() {
this.setState(prevState => ({
display: !prevState.display
}))
}
edit() {
this.setState({
editing: true
})
}
save() {
let titleVal = this.refs.updateTitle.value;
let detailsVal = this.refs.updateDetails.value;
this.setState({
editTitle: titleVal,
editDetails: detailsVal,
editing: false
})
}
render() {
return (
<div className="entry">
<div className="entry-header" onClick={this.state.editing ? null : this.displayToggle}>
{this.state.editing ? (
<input ref="updateTitle" className="edit-title" type="text" />
) : (
<h2 className="entry-title">{this.props.title}</h2>
)}
<p className="timestamp">{this.displayTime}</p>
</div>
<hr />
<div className={"entry-content " + (!this.state.display ? "hide-details" : null)}>
{this.state.editing ? (
<textarea ref="updateDetails" className="edit-details" cols="10" rows="2"></textarea>
) : (
<p className="details">{this.props.details}</p>
)}
<div className="entry-buttons">
{this.state.editing ? (
<button className="save" onClick={this.save}>Save</button>
) : (
<button className="edit" onClick={this.edit}>Edit</button>
)
}
<button className="delete" onClick={this.props.deleteNote}>Delete</button>
</div>
</div>
</div>
)
}
}
You can do by pass data from child to parent component as mention it in comment.
In you case NoteEntry add onEditNote props. This props use for function by parent (App component) and use by onClick edit button.
<NoteEntry
...
onEditNote={this.handleClickEdit}
/>
then in class NoteEntry
<button className="edit" onClick={() => this.props.handleClickEdit(this.props.title, this.props.detail)}>Edit</button>
So, handleClickEdit handle by App component and set it to your state
handleClickEdit = (_title, _detail) => {
this.setState({title: _title, details: _detail});
}
Now, your NoteForm component able to edit.
Related
Good morning, I have a question. When I press the + button, only one employee line is added and I would like it to be added as many times as I press
ReactJS component code:
class Home extends React.Component {
state = { showForm:false }
showForm = () => {
return(
<Employee />
)
}
render() {
return (
<div className='container-home'>
<div className='min-margin'>
<Employee />
{this.state.showForm ? this.showForm() : null}
<div className='container-append'>
<button onClick={() => this.setState({showForm: true})}>➕</button>
</div>
</div>
</div>
)
}
}
You just click to show and hide the input.
You need:
Add to state array: (inputs: ["Employee-0"])
state = {
showForm: false,
inputs: ["Employee-0"]
};
Add to functions
handleAddInput = e => {
e.preventDefault();
const inputState = this.state.inputs;
let inputs = inputState.concat([`Employee-${inputState.length}`]);
this.setState({
inputs
});
};
handleShowForm = e => {
e.preventDefault();
this.setState({
...this.state,
showForm: !this.state.showForm
})
}
Change the code in render
render() {
return (
<div className="App">
{this.state.showForm && <form>
{this.state.inputs.map((input, idx) => (
<Employee key={idx}/>
))}
</form>}
<button onClick={this.handleAddInput}>Add New Employee</button>
<button onClick={this.handleShowForm}>Show form</button>
</div>
);
}
Click on the buttons)
The difference options exist for doing it , but that's work you did just a flag for shown of a Component. So you are able to try followings this:
class Home extends React.Component {
state = {
employeesCount: 0,
employees: []
}
render() {
return (
<div className='container-home'>
<div className='min-margin'>
{employees.map((eNumber) => {
return <Employee key={eNumber}/>
}}
<div className='container-append'>
<button onClick={() => this.setState({
employeesCount: employeesCount + 1,
employees: [...this.state.employess , (employeesCount + 1)]
})}>➕</button>
</div>
</div>
</div>
)
}
}
Try this:
import React from "react";
const Employee = (props) => {
return(
<div>Hello I am employee number {props.number}</div>
)
}
class App extends React.Component {
constructor() {
super()
this.state = { employees: [] }
}
addEmployee() {
this.setState({
employees: [...this.state.employees, <Employee number={this.state.employees.length} />]
})
}
render() {
return (
<div>
<div className='container-append'>
<button onClick={() => this.addEmployee()}>➕</button>
</div>
{ this.state.employees.map(employee => employee) }
</div>
)
}
}
export default App;
Take a look on my Chat.js contents:
import React, { Component } from "react";
class Chat extends Component {
constructor(props) {
super(props);
this.state = {
messages: [],
message: ""
};
}
submitMessage(event) {
event.preventDefault();
this.setState(state => ({
messages: [<li>{this.state.message}</li>, ...state.messages]
}));
this.setState({
message: ""
});
}
render() {
return (
<>
<div class="container py-3">
<h2 className="text-center mb-4">Simple Chat</h2>
<form
onSubmit={e => {
this.submitMessage(e);
}}
>
<input
type="text"
className="form-control"
placeholder={"Enter your message..."}
value={this.state.message}
onChange={e => this.setState({ message: e.target.value })}
/>
<button type="submit" className="btn btn-success mt-2">
Send Message
</button>
</form>
<div className="container border mt-2">
<ul className="group-list mt-3 pt-2">{this.state.messages}</ul>
</div>
</div>
</>
);
}
}
export default Parent;
Also, this is my example:
https://codesandbox.io/s/objective-water-1e8uq
i need to replace user link when anyone type username with #
for example, this is my message content:
Are you good #Daniel ?
I need to convert above message to following content:
Are you good #Daniel ?
I use react-router-dom, so i need to replace link with this code:
Eg:
<Router>
<Link to={ '#'} onClick={() => {this.example()}}>
#Daniel
</Link>
</Router>;
It should be done with a string replace:
// This is to have as tag "Are you good #Daniel ?" (with # in the username)
const replacementReg = /(#[a-zA-Z0-9]+)/g;
// This is to have as tag "Are you good Daniel ?" (without # in the username)
const replacementReg = /#([a-zA-Z0-9]+)/g;
function decorateWithLink(text) {
text.replace(replacementReg, replaced => ` ${replaced} `);
}
and you should use in your component:
this.setState(state => ({
messages: [
<li>{decorateWithLink(this.state.message)}</li>,
...state.messages
],
message: '' // with this you don't need to call again the this.setState
}));
I have updated your submitMessage function here is the code:
submitMessage(event) {
event.preventDefault();
const { message } = this.state;
let msg = message.replace(/#([a-zA-Z0-9]+)/g, value => ` ${value} `);
this.setState(state => ({
messages: [<li dangerouslySetInnerHTML={{__html: msg}} />, ...state.messages]
}));
this.setState({
message: ""
});
}
here is the working code: https://codesandbox.io/s/stupefied-platform-zmg94
I am trying to fit 3 component in a single page by hiding/showing on a div.But I am not really getting into how to do it.This is the first div.
<div>
<p>What is the type of your property?</p>
<button >Residence</button>
<button>Commercial</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
Only If i click the 'Commercial' or 'Next' button it would go into the second div and first div will hide.
<div>
<p>What is the type of your commercial property?</p>
<button>Office</button>
<button>Restaurant</button>
<button >Outlet</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
and lastly if i click 'restaurant' button from the first div and any button of the second div except the back button it will go into the third div and other div will hide.this is the third div.
<div>
<div className='slider' style={{ marginTop:'165px',marginLeft:'319px',width:'700px',backgroundColor:'EF5350'}} >
<Slider min={850} max={5000} value={value} onChangeStart={this.handleChangeStart}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
<div className='value'>{value} Squarefeet</div>
<div style={{marginTop:'86px'}}>
<span onChange={this.handleChange} onClick={() => this.saveValue()} >Next</span>
<span onChange={this.handleChange} onClick={() => this.saveValue()} >Next</span>
</div>
</div>
</div>
I tried to do it this way. But it will not work.
import React from 'react';
import Link from "next/link";
class Jh extends React.Component {
constructor() {
super();
this.state = {
shown: true,
hide: false
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
toggles() {
this.setState({
shown: !this.state.hide
});
}
render() {
var shown = {
display: this.state.shown ? "block" : "none"
};
var hidden = {
display: this.state.shown ? "none" : "block"
}
return (
<div>
<button onClick={this.toggle.bind(this)} style={ shown }>
<div>
<p>What is the type of your property?</p>
<button >Residence</button>
<button>Commercial</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
</button>
<button onClick={this.toggles.bind(this)} style={ hidden }>
<div>
<p>What is the type of your commercial property?</p>
<button>Office</button>
<button>Restaurant</button>
<button >Outlet</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
</button>
</div>
)
}
}
export default Jh
What should be my approach?
There are many patterns to achieve a "switch case", I'll try to show my favorites:
For sipmlicity, I'll use a generic use case.
Straight Forward
Managing visible state for every component:
return {visible && <CoolComponent id={1} />};
Switch case in disguise
Manage a state of object keys. (currentCounter)
const countersPicker = {
counter1: <Counter id={1} />,
counter2: <Counter id={2} />,
coolComponent: <CoolComponent id={3} />
};
return {countersPicker[currentCounter]};
Here you also can take action on the object, for example, adding a header:
return {Object.entries(countersPicker).map(([key,component]) =>
<div key={key}>
<h1>Component key = {key}</h1>
{component}
</div>
)};
Filter Children
Manage a predicate and use it for filtering/mapping the children.
Check React.Children API.
return (
<FilterComponents predicate={predicate}>
<Counter key={1} id={1} />
<Counter key={2} id={2} />
<CoolComponent key={3} id={3} />
<BestComponent key={4} id={4} />
</FilterComponents>
);
function FilterComponents({ children, predicate }) {
const filteredChildren = React.Children.toArray(children).filter(child =>
// Use the predicate.
// Filter a child by key, key & type or even use ref etc.
);
return <div>{filteredChildren}</div>;
}
I believe you are looking for something like this.
Main things to-do:
Enhance your state-value. Keep track of the different pages in sequence by using an array. Track the current page. Track the start and end of the collection.
Here is the sandbox as well: https://codesandbox.io/s/unruffled-sun-gpzx6
import React from "react";
class Pages extends React.Component {
state = {
currentPage: "property",
pages: ["property", "type", "firstBusiness"],
start: true,
end: false
};
changePage = event => {
const { currentPage, pages } = this.state;
const { name } = event.target;
//check if we are going to end
if (
name == "next" &&
pages[pages.indexOf(currentPage) + 1] === pages[pages.length - 1]
) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
end: true,
start: false
});
//go to next page
} else if (name == "next") {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
start: false
});
//check if we are going to beginning
} else if (
name == "back" &&
currentPage !== pages[0] &&
pages[pages.indexOf(currentPage) - 1] == pages[0]
) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) - 1],
start: true
});
//go back one page
} else {
this.setState({
currentPage: pages[pages.indexOf(currentPage) - 1],
end: false
});
}
};
goToNextPage = () => {
const { currentPage, pages, end } = this.state;
//check if we are going to end
if (pages[pages.indexOf(currentPage) + 1] === pages[pages.length - 1]) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
end: true,
start: false
});
//go to next page
} else if (end) {
return;
} else {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
start: false
});
}
};
render() {
const { currentPage, start, end } = this.state;
return (
<div style={{ background: "gray" }}>
{currentPage === "property" ? (
<div>
<p>What is the type of your property?</p>
<button onClick={this.goToNextPage}>Residence</button>
<button onClick={this.goToNextPage}>Commercial</button>
</div>
) : null}
{currentPage === "type" ? (
<div>
<p>What is the type of your commercial property?</p>
<button onClick={this.goToNextPage}>Office</button>
<button onClick={this.goToNextPage}>Restaurant</button>
<button onClick={this.goToNextPage}>Outlet</button>
</div>
) : null}
{currentPage === "firstBusiness" ? (
<div>
<p>Is this your first business?</p>
<button onClick={this.goToNextPage}>Yes</button>
<button onClick={this.goToNextPage}>No</button>
</div>
) : null}
<div>
<button onClick={this.changePage} name="back" disabled={start}>
Back
</button>
<button onClick={this.changePage} name="next" disabled={end}>
Next
</button>
</div>
</div>
);
}
}
export default Pages;
So essentially you want router like functionality. Here is one approach:
class FirstPage extends React.Component {
render() {
//...first page content
}
}
class SecondPage extends React.Component {
render() {
//...second page content
}
}
const pages = {
first: FirstPage,
second: SecondPage
};
class App extends React.Component {
constructor() {
this.state = {
page: 'first'
};
}
render() {
const PageComponent = pages[this.state.page];
return <div>
<button onClick={() => this.setState({page: 'first'})}>First page</button>
<button onClick={() => this.setState({page: 'second'})}>Second page</button>
<PageComponent/>
</div>
}
}
There are many ways to solve this problem. But in my opinion the best solution is the one which solves the problem in a succinct manner.
Please find below the working solution which I have tried and works like a charm:
import React from "react";
class Pages extends React.Component {
state = {
activeTab: 1
};
toggle = tab => {
this.setState({
activeTab: tab
});
};
togglePage = page => {
if (page === "next") {
this.setState({
activeTab: this.state.activeTab + 1
});
} else if (page === "back") {
this.setState({
activeTab: this.state.activeTab - 1
});
}
};
render() {
return (
<div style={{ background: "#dedede" }}>
<div hidden={this.state.activeTab === 1 ? false : true}>
<p>1) What is the type of your property?</p>
<button class="btn btn-primary" onClick={() => this.toggle(2)}>
Residence
</button>
<button onClick={() => this.toggle(2)}>Commercial</button>
</div>
<div hidden={this.state.activeTab === 2 ? false : true}>
<p>2) What is the type of your commercial property?</p>
<button onClick={() => this.toggle(3)}>Office</button>
<button onClick={() => this.toggle(3)}>Restaurant</button>
<button onClick={() => this.toggle(3)}>Outlet</button>
</div>
<div hidden={this.state.activeTab === 3 ? false : true}>
<p>3) Is this your first business?</p>
<button onClick={this.NextAction}>Yes</button>
<button onClick={this.NextAction}>No</button>
</div>
<div>
<button
onClick={() => this.togglePage("back")}
name="back"
disabled={this.state.activeTab === 1 ? true : false}
>
Back
</button>
<button
onClick={() => this.togglePage("next")}
name="next"
disabled={this.state.activeTab === 3 ? true : false}
>
Next
</button>
</div>
</div>
);
}
}
export default Pages;
In react we have a hidden attribute which you can use to show/hide the elements without having to write any css for the same.
And I have tried to solve the problem with the least number of variables.
The sandbox for the same can be found here : https://codesandbox.io/s/mysolution-g8fu6
Hope this helps!
I'm trying to make simple CRUD example using react.js as frontend.
I already have add/edit functionality done in a component,
but I want to call this component dynamically on click and show it as a popup or modal window on the same page without redirecting to another route.
Does anyone have experience with doing this using react.js?
This is my parent component code where I show a grid of items displaying cities:
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Link, NavLink } from 'react-router-dom';
interface FetchNaseljeDataState {
nasList: NaseljeData[];
loading: boolean;
}
export class FetchNaselje extends React.Component<RouteComponentProps<{}>, FetchNaseljeDataState> {
constructor() {
super();
this.state = { nasList: [], loading: true };
fetch('api/Naselje/Index')
.then(response => response.json() as Promise<NaseljeData[]>)
.then(data => {
this.setState({ nasList: data, loading: false });
});
// This binding is necessary to make "this" work in the callback
this.handleDelete = this.handleDelete.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: this.renderNaseljeTable(this.state.nasList);
return <div>
<h1>Naselje Data</h1>
<p>This component demonstrates fetching Naselje data from the server.</p>
<p>
<Link to="/addnaselje">Create New</Link>
</p>
{contents}
</div>;
}
// Handle Delete request for an naselje
private handleDelete(id: number) {
if (!confirm("Do you want to delete naselje with Id: " + id))
return;
else {
fetch('api/Naselje/Delete/' + id, {
method: 'delete'
}).then(data => {
this.setState(
{
nasList: this.state.nasList.filter((rec) => {
return (rec.idnaselje != id);
})
});
});
}
}
private handleEdit(id: number) {
this.props.history.push("/naselje/edit/" + id);
}
// Returns the HTML table to the render() method.
private renderNaseljeTable(naseljeList: NaseljeData[]) {
return <table className='table'>
<thead>
<tr>
<th></th>
<th>ID Naselje</th>
<th>Naziv</th>
<th>Postanski Broj</th>
<th>Drzava</th>
</tr>
</thead>
<tbody>
{naseljeList.map(nas =>
<tr key={nas.idnaselje}>
<td></td>
<td>{nas.idnaselje}</td>
<td>{nas.naziv}</td>
<td>{nas.postanskiBroj}</td>
<td>{nas.drzava && nas.drzava.naziv}</td>
<td>
<a className="action" onClick={(id) => this.handleEdit(nas.idnaselje)}>Edit</a> |
<a className="action" onClick={(id) => this.handleDelete(nas.idnaselje)}>Delete</a>
</td>
</tr>
)}
</tbody>
</table>;
}
}
export class NaseljeData {
idnaselje: number = 0;
naziv: string = "";
postanskiBroj: string = "";
drzava: DrzavaData = { iddrzava: 0, naziv: ""};
drzavaid: number = 0;
}
export class DrzavaData {
iddrzava: number = 0;
naziv: string = "";
}
This is my child component that I want to dynamically show on create new link click:
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Link, NavLink } from 'react-router-dom';
import { NaseljeData } from './FetchNaselje';
import { DrzavaData } from './FetchNaselje';
interface AddNaseljeDataState {
title: string;
loading: boolean;
drzavaList: Array<any>;
nasData: NaseljeData;
drzavaId: number;
}
export class AddNaselje extends React.Component<RouteComponentProps<{}>, AddNaseljeDataState> {
constructor(props) {
super(props);
this.state = { title: "", loading: true, drzavaList: [], nasData: new NaseljeData, drzavaId: -1 };
fetch('api/Naselje/GetDrzavaList')
.then(response => response.json() as Promise<Array<any>>)
.then(data => {
this.setState({ drzavaList: data });
});
var nasid = this.props.match.params["nasid"];
// This will set state for Edit naselje
if (nasid > 0) {
fetch('api/Naselje/Details/' + nasid)
.then(response => response.json() as Promise<NaseljeData>)
.then(data => {
this.setState({ title: "Edit", loading: false, nasData: data });
});
}
// This will set state for Add naselje
else {
this.state = { title: "Create", loading: false, drzavaList: [], nasData: new NaseljeData, drzavaId: -1 };
}
// This binding is necessary to make "this" work in the callback
this.handleSave = this.handleSave.bind(this);
this.handleCancel = this.handleCancel.bind(this);
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: this.renderCreateForm(this.state.drzavaList);
return <div>
<h1>{this.state.title}</h1>
<h3>Naselje</h3>
<hr />
{contents}
</div>;
}
// This will handle the submit form event.
private handleSave(event) {
event.preventDefault();
const data = new FormData(event.target);
// PUT request for Edit naselje.
if (this.state.nasData.idnaselje) {
fetch('api/Naselje/Edit', {
method: 'PUT',
body: data,
}).then((response) => response.json())
.then((responseJson) => {
this.props.history.push("/fetchnaselje");
})
}
// POST request for Add naselje.
else {
fetch('api/Naselje/Create', {
method: 'POST',
body: data,
}).then((response) => response.json())
.then((responseJson) => {
this.props.history.push("/fetchnaselje");
})
}
}
// This will handle Cancel button click event.
private handleCancel(e) {
e.preventDefault();
this.props.history.push("/fetchnaselje");
}
// Returns the HTML Form to the render() method.
private renderCreateForm(drzavaList: Array<any>) {
return (
<form onSubmit={this.handleSave} >
<div className="form-group row" >
<input type="hidden" name="idnaselje" value={this.state.nasData.idnaselje} />
</div>
< div className="form-group row" >
<label className=" control-label col-md-12" htmlFor="Naziv">Naziv</label>
<div className="col-md-4">
<input className="form-control" type="text" name="naziv" defaultValue={this.state.nasData.naziv} required />
</div>
</div >
<div className="form-group row">
<label className="control-label col-md-12" htmlFor="PostanskiBroj" >Postanski broj</label>
<div className="col-md-4">
<input className="form-control" name="PostanskiBroj" defaultValue={this.state.nasData.postanskiBroj} required />
</div>
</div>
<div className="form-group row">
<label className="control-label col-md-12" htmlFor="Drzava">Država</label>
<div className="col-md-4">
<select className="form-control" data-val="true" name="drzavaid" defaultValue={this.state.nasData.drzava ? this.state.nasData.drzava.naziv : ""} required>
<option value="">-- Odaberite Državu --</option>
{drzavaList.map(drzava =>
<option key={drzava.iddrzava} value={drzava.iddrzava}>{drzava.naziv}</option>
)}
</select>
</div>
</div >
<div className="form-group">
<button type="submit" className="btn btn-default">Save</button>
<button className="btn" onClick={this.handleCancel}>Cancel</button>
</div >
</form >
)
}
}
I'm assuming I'll have to make css for the create/edit component to make it look like a popup...
EDIT: I would appreciate if someone could make code example using my classes, thanks...
In the parent component set a state on click functionality, say for eg:
this.setState({display: true})
In the parent component render based on condition display child component, say for eg:
<div>{(this.state.display) ? <div><childComponent /></div> : ''}</div>
To display the child component in a modal/popup, put the component inside say a bootstrap or react-responsive-modal. For that, you have to install and import react-responsive-modal and then
In the render method,
return (
<div>
{this.state.toggleModal ? <div className="container">
<Modal open={this.state.toggleModal} onClose={this.onCloseModal} center>
<div className="header">
<h4>{Title}</h4>
</div>
<div className="body">
<div>
{this.state.toggleModal ? <someComponent /> : ''}
</div>
</div>
</Modal>
</div>
: null}
</div>
)
Have your popup component receive a prop from the parent that will tell it if it should be displayed or not, a simple boolean will do the trick. Then, when you want something to show the popup, just change that state in the parent.
I am trying to use React bootstrap panelgroup (Accordion)
I want a custom header with radio buttons. Hence i replaced header with my custom header. After using custom header, Expand collapse has stopped working.
Code (Custom header)
constructor(props) {
super(props);
this.state = {
isSelected: false,
};
}
componentWillMount () {
if (this.props.isSelected) {
this.state = {isSelected:true};
} else {
this.state = {isSelected: false};
}
}
componentWillUpdate () {
if (this.props.isSelected) {
this.state = {isSelected:true};
} else {
this.state = {isSelected: false};
}
}
render() {
let radio =
<span>
<input type="radio" className="accordion_checkbox" name={this.props.name} />
{this.props.header}
</span> ;
if (this.state.isSelected) {
radio = <span>
<input type="radio" className="accordion_checkbox" defaultChecked name={this.props.name} />
{this.props.header}
</span>
}
return (
<div>
{radio}
</div>
)
}
Panel:
<PanelGroup className="payment-accordion" activeKey={this.state.activeKey} onSelect={e => this.handleSelect(e)} accordion>
<Panel header={<PanelHeaderCustom name="saved_card" isSelected={this.state.activeKey === "savedCards"} header="SAVED CARD"/>} eventKey="savedCards">
<SwipableCards savedCards={this.props.savedCards}/>
</Panel>
<Panel header={<PanelHeaderCustom name="debit_card" isSelected={this.state.activeKey === "creditDebitCards"} header="DEBIT CARD"/>} eventKey="creditDebitCards">Debit/Credit Card</Panel>
<Panel header={<PanelHeaderCustom name="net_banking" isSelected={this.state.activeKey === "netbanking"} header="NET BANKING"/>} eventKey="netbanking">Debit/Credit Card</Panel>
</PanelGroup>
What am i missing?
Thanks in advance
When calling an element with JSX syntax, the generated object type doesn't have "children" as prop, and I think react-bootstrap Panel cannot handle that situation correctly.
<PanelHeaderCustom /> // returns Object { type: PanelHeaderCustom(), props: { header:"NET BANKING", isSelected: false, name: "net_banking" } }
Therefore, as a workaround, you could wrap your custom header to div in the Panel header prop:
class PanelHeaderCustom extends Component {
render () {
return (
<span>
<input
type='radio'
className='accordion_checkbox'
checked={this.props.isSelected}
name={this.props.name} />
{this.props.header}
</span>
)
}
}
export default class Test extends Component {
constructor (props) {
super(props)
this.state = {
activeKey: ''
}
}
handleSelect (e) {
this.setState({
activeKey: e
})
}
render () {
return (
<div>
<PanelGroup
className='payment-accordion'
activeKey={this.state.activeKey}
onSelect={(e) => this.handleSelect(e)}
accordion>
<Panel
header={
<div>
<PanelHeaderCustom
name='saved_card'
isSelected={this.state.activeKey === 'savedCards'}
header='SAVED CARD' />
</div>
}
eventKey='savedCards'>
<div>Example</div>
</Panel>
<Panel
header={
<div>
<PanelHeaderCustom
name='debit_card'
isSelected={this.state.activeKey === 'creditDebitCards'}
header='DEBIT CARD' />
</div>
}
eventKey='creditDebitCards'>
Debit/Credit Card
</Panel>
<Panel
header={
<div>
<PanelHeaderCustom
name='net_banking'
isSelected={this.state.activeKey === 'netbanking'}
header='NET BANKING' />
</div>
}
eventKey='netbanking'>
Debit/Credit Card
</Panel>
</PanelGroup>
</div>
)
}
}
ReactDOM.render(
<Test />,
document.getElementById('main')
)
As a side note, I think you should make your custom header a stateless component, because there is no point for the component to know it's own state. Just use props in the PanelHeaderCustom and control the instances with the main app's state.
When you make that component stateless, you can write your component's code a as a pure function without need for unnecessary div-wrapping:
// Returns { type: "span", props: { children: [ { type: "input"... }, "SAVED_CARD" ] } }
function PanelHeaderCustom (
header,
name,
isSelected
) {
return (
<span>
<input
type='radio'
className='accordion_checkbox'
checked={isSelected}
name={name} />
{header}
</span>
)
}
Then call the function in Panel's header prop:
<Panel
header={
PanelHeaderCustom(
'SAVED CARD',
'saved_card',
this.state.activeKey === 'savedCards'
)
}
eventKey='savedCards'>
<div>Example</div>
</Panel>