Hello i have a list of student
when i click on a student it direct me to student's page
student page is a component(view student details/degrees) that contains a child component(edit-degrees form)
when I go to student1 page first time everything works ok
if I press back and choose student2 then component renders the correct student details but child component (edit-degrees form) shows the degrees of student1 if I go back and go again to student2 twice in a row it will show correct.
Any tip?
Edit: Actually container component also hold previous state
component's while this.props contain the correct current state
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { fetch as fetchStudent } from '../actions/student'
import Title from '../components/Title'
import StudentEditor from './StudentEditor'
//import BatchEditor from './BatchEditor'
class StudentContainer extends PureComponent {
componentWillMount() {
this.props.dispatch(fetchStudent(this.props.match.params.id))
if (this.props){console.log(this.props)}
this.setState(this.props)
}
componentDidMount(){
this.forceUpdate()
}
renderEvaluations(evaluations) {
const evdata = evaluations.map( evaluation => {
let tdstyle= {
background: evaluation.color,
};
return (
<tr>
<td>{evaluation.createdAt}</td>
<td style={tdstyle}>{evaluation.remark}</td>
<td style={tdstyle}>{evaluation.color}</td>
<td>{evaluation.userId}</td>
</tr>);
});
return (
<table border="1">
<tr>
<th>Date</th>
<th>Remark</th>
<th>Color</th>
<th>TeacherID</th>
</tr>
<tbody>
{evdata}
</tbody>
</table>
)
}
render() {
if (this.props.student)
{
var student = this.props.student;
console.log(this.state)
console.log(this.props)
var childprops= this.state.student;
return(
<div className="StudentContainer">
<header>
<Title content={`Student: ${student.name}`} />
</header>
<main>
<div className="studentPhoto">
<img src={student.photo} alt={student.name} />
</div>
<div className="studentDetails">
<div className="title">Name:{student.name}</div>
<div>Evaluations</div>
<div className="evaluations">{this.renderEvaluations(student.evaluations)} </div>
</div>
<StudentEditor student={student} />
</main>
</div>
)} else { return <div>loading</div> }
}
}
const mapStateToProps = ({ student }) => ({ ...student })
export default connect(mapStateToProps)(StudentContainer)
editor
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import 'medium-editor/dist/css/medium-editor.css'
import 'medium-editor/dist/css/themes/default.css'
import updateStudent from '../actions/student/update'
import Title from '../components/Title'
class StudentEditor extends PureComponent {
constructor(props) {
super()
this.state = props.student
this.state.currentUser = "5a3151c868720b1d4cef1b48"
}
updateName(event) {
if (event.keyCode === 13) {
event.preventDefault()
this.refs.name.medium.elements[0].focus()
}
this.setState({
name: this.refs.name.value
})
}
updateRemark(event) {
const index = event.target.id
console.log(index)
if (event.keyCode === 13) {
event.preventDefault()
this.refs.remark.medium.elements[0].focus()
}
const evaluat = this.state.evaluations
evaluat[index].remark = event.target.value
console.log(this.state)
this.setState({evaluations: evaluat })
console.log(this.state)
//const evaluation = this.state.evaluations;
//this.state.evaluations[index].remark = this.refs.remark.value;
this.forceUpdate();
/*
this.setState({
this.state.evaluations[0].remark: this.refs.remark.value
})*/
}
updateColor(event) {
const index = event.target.id
if (event.keyCode === 13) {
event.preventDefault()
this.refs.color.medium.elements[0].focus()
}
//const evaluation = this.state.evaluations;
//this.setState( {evaluations[index]: event.target.value}) //= event.target.value;
const evaluat = this.state.evaluations
evaluat[index].color = event.target.value;
this.setState({evaluations: evaluat })
this.forceUpdate();
}
updatePhoto(event) {
if (event.keyCode === 13) {
event.preventDefault()
this.refs.photo.medium.elements[0].focus()
}
this.setState({
photo: this.refs.photo.value
})
}
addEvaluation() {
const newremark= this.refs.newremark.value
const newcolor= this.refs.newcolor.value
const newuserId= "5a3151c868720b1d4cef1b48"
let newarray= this.state.evaluations.slice()
let neweva= {remark: newremark, color: newcolor, userId:newuserId}
newarray.push(neweva)
const student= {
...this.state
}
student.evaluations=newarray
this.setState(student)
this.props.save(student)
this.forceUpdate()
}
saveStudent() {
console.table(this.state)
const student= {
...this.state
}
console.table(student)
this.props.save(student)
}
renderEvaluationsForm(){
if(this.state.evaluations){
const rendered = this.state.evaluations.map((evaluation,index) => {
if (evaluation.userId === this.state.currentUser){
return (
<div>
<input
type="text"
ref="remark"
className="remark"
placeholder="remark"
onChange={this.updateRemark.bind(this)}
value={this.state.evaluations[index].remark}
id={index} />
<select
ref="color"
className="color"
onChange={this.updateColor.bind(this)}
value={this.state.evaluations[index].color}
id={index}>
<option value="green">green </option>
<option value="orange">orange </option>
<option value="red">red </option>
</select>
</div>
);}});
return rendered;
}
}
render() {
return (
<div className="editor">
<header>
<Title content="Modify Name or Photo" />
</header>
<label>Student's Name:</label>
<input
type="text"
ref="name"
className="name"
placeholder="name"
onChange={this.updateName.bind(this)}
onKeyUp={this.updateName.bind(this)}
value={this.state.name} />
<label>Student's Photo:</label>
<input
type="text"
ref="photo"
className="photo"
placeholder="photo"
onChange={this.updatePhoto.bind(this)}
onKeyUp={this.updatePhoto.bind(this)}
value={this.state.photo}/>
<br /><br />
<div> Modify Evaluations </div><br />
{this.renderEvaluationsForm()}
<div className="actions">
<button className="primary" onClick={this.saveStudent.bind(this)}>Update</button><br />
</div>
<br />
<div> Add new Evaluation </div><br />
<label>Evaluation Remark:</label>
<input
type="text"
ref="newremark"
className="newremark"
placeholder="Add remark"
/>
<label>Evaluation Color:</label>
<select
type="text"
ref="newcolor"
className="newcolor"
>
<option value="green">green</option>
<option value="orange">orange</option>
<option value="red">red</option>
</select>
<div className="actions">
<button className="primary" onClick={this.addEvaluation.bind(this)}>Add Evaluation</button><br />
</div>
</div>
)
}
}
const mapDispatchToProps = { save: updateStudent }
export default connect(null, mapDispatchToProps)(StudentEditor)
Note that you need to implement componentWillReceiveProps(nextProps) method in StudentContainer component and set the state accordingly. componentWillMount() method will be invoked only once before the component is rendered in the DOM.
After that for any props change componentWillReceiveProps() lifecycle hook will be invoked by React
Related
I have trouble with simple task of adding elements selected in checkboxes to an array in component state. It seems like the push method for state.toppings (Editor.js) is invoked twice for each checkbox click, even though console.log shows that updateFormValueCheck method is invoked once per click. Can anyone help?
This is App.js
import React, { Component } from "react";
import { Editor } from "./Editor";
import { Display } from "./Display";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
formData: {}
}
}
submitData = (newData) => {
console.log("newData", newData)
this.setState({ formData: newData });
}
render() {
return <div className="container-fluid">
<div className="row p-2">
<div className="col-6">
<Editor submit={this.submitData} />
</div>
<div className="col-6">
<Display data={this.state.formData} />
</div>
</div>
</div>
}
}
This is Editor.js
import React, { Component } from "react";
export class Editor extends Component {
constructor(props) {
super(props);
this.state = {
toppings: ["Strawberries"]
}
this.toppings = ["Sprinkles", "Fudge Sauce",
"Strawberries", "Maple Syrup"]
}
updateFormValueCheck = (event) => {
event.persist();
this.setState(state => {
if (event.target.checked) {
state.toppings.push(event.target.name);
} else {
let index = state.toppings.indexOf(event.target.name);
state.toppings.splice(index, 1);
}
}, () => this.props.submit(this.state));
}
render() {
return <div className="h5 bg-info text-white p-2">
<div className="form-group">
<label>Ice Cream Toppings</label>
{this.toppings.map(top =>
<div className="form-check" key={top}>
<input className="form-check-input"
type="checkbox" name={top}
value={this.state[top]}
checked={this.state.toppings.indexOf(top) > -1}
onChange={this.updateFormValueCheck} />
<label className="form-check-label">{top}</label>
</div>
)}
</div>
</div>
}
}
This is Display.js
import React, { Component } from "react";
export class Display extends Component {
formatValue = (data) => Array.isArray(data)
? data.join(", ") : data.toString();
render() {
let keys = Object.keys(this.props.data);
if (keys.length === 0) {
return <div className="h5 bg-secondary p-2 text-white">
No Data
</div>
} else {
return <div className="container-fluid bg-secondary p-2">
{keys.map(key =>
<div key={key} className="row h5 text-white">
<div className="col">{key}:</div>
<div className="col">
{this.formatValue(this.props.data[key])}
</div>
</div>
)}
</div>
}
}
}
The output is:
You cannot directly mutate this.state, it can only be done using this.setState. For more info. refer this: Why can't I directly modify a component's state, really?
Therefore, you need to update your Editor component as follows.
componentDidMount is used to display the initial state during the initial rendering. Then componentDidUpdate is used to render the state changes through display component whenever it's updated.
import React, { Component } from "react";
export class Editor extends Component {
constructor(props) {
super(props);
this.state = {
toppings: ["Strawberries"],
};
this.toppings = ["Sprinkles", "Fudge Sauce", "Strawberries", "Maple Syrup"];
}
updateFormValueCheck = (event) => {
event.persist();
let data;
if (event.target.checked) {
data = [...this.state.toppings, event.target.name];
} else {
const index = this.state.toppings.indexOf(event.target.name);
const temp = [...this.state.toppings];
temp.splice(index, 1);
data = temp;
}
this.setState({
toppings: data,
});
};
componentDidMount() {
this.props.submit(this.state.toppings);
}
componentDidUpdate(prevPros, prevState) {
if (prevState.toppings !== this.state.toppings) {
this.props.submit(this.state.toppings);
}
}
render() {
console.log(this.state);
return (
<div className="h5 bg-info text-white p-2">
<div className="form-group">
<label>Ice Cream Toppings</label>
{this.toppings.map((top) => (
<div className="form-check" key={top}>
<input
className="form-check-input"
type="checkbox"
name={top}
value={this.state[top]}
checked={this.state.toppings.indexOf(top) > -1}
onChange={this.updateFormValueCheck}
/>
<label className="form-check-label">{top}</label>
</div>
))}
</div>
</div>
);
}
}
Hope this would be helpful to solve your issue.
I carry out a project which can modify the price of a product (recovered from a fake API) and then at the click of a button carries out the update by calculating the VAT of 20%. I encounter a problem I would like to have a price state and that in this state it's the value of my input namely {listProduct.price} but it doesn't work.
If you have solutions, I am interested, thank you in advance. (sorry I'm new to React I still have a bit of trouble with all these concepts)
import React, { Component } from 'react'
import '../css/ProductsDetails.css'
import {AiOutlineArrowLeft} from "react-icons/ai";
import {Link} from 'react-router-dom'
export default class ProductsDetails extends Component {
state = {
id: this.props.match.params.id,
price:
}
updatePrice = (e) => {
console.log(e);
this.setState({
price: e.target.value
})
}
render() {
const {location: {state: {listProduct}}} = this.props;
return (
<div className="products__details">
<Link to="/"><AiOutlineArrowLeft className="nav__arrow" /></Link>
<h1 className="details__title">{listProduct.title}</h1>
<div className="details__align--desk">
<div className="details__img">
<img className="product__img" src={listProduct.image} alt="Affichage du produit"/>
</div>
<div className="products__align--desk">
<h2 className="product__title">Description</h2>
<p className="product__description">{listProduct.description}</p>
<h2 className="product__title">Price</h2>
<form className="form__price">
<input className="input__price" type="text" value={listProduct.price} onChange={this.updatePrice} />
<p>Price (including VAT): {Math.round((listProduct.price + listProduct.price * 0.2)*100) /100} €</p>
<br/>
<input className="btn__update" type="submit" value="Update product" />
</form>
</div>
<div className="category__align--desk">
<h2 className="product__title">Category</h2>
<p className="product__category">{listProduct.category}</p>
</div>
</div>
</div>
)
}
}
export default class Products extends Component {
constructor(props) {
super(props);
this.state = {productsData: []};
}
componentDidMount = () => {
axios.get('https://fakestoreapi.com/products?limit=7')
.then(res => {
console.log(res.data)
this.setState ({
productsData: res.data
})
})
}
render() {
const listsProducts = this.state.productsData.map(listProduct => {
return <tbody className="products__body">
<tr>
<td> <Link to={{pathname: "/products-details/" + listProduct.id,state: {listProduct}}}>{listProduct.title}</Link></td>
<td className="products__category">{listProduct.category}</td>
<td>{listProduct.price}</td>
<td>{Math.round((listProduct.price + listProduct.price * 0.2)*100) /100}</td>
</tr>
</tbody>
})
return (
<main className="products">
<h1 className="products__title">Products management</h1>
<table cellSpacing="0">
<thead className="products__head">
<tr>
<th className="table--title">Product name</th>
<th className="table--title">Category</th>
<th className="table--title">Price</th>
<th className="table--title">Price (including VAT)</th>
</tr>
</thead>
{listsProducts}
</table>
</main>
)
}
}
Inside a react component:
1 - You declare the initial state of your component, which is, in this case, the price that the product has before the user writes something. For now, we'll set it to 0:
state = {
id: this.props.match.params.id,
price: this.props.listProduct.price ? this.props.listProduct.price : 0
}
2 - Then, in the render method, we access the price value from this.state
3 - Finally, we modify our input element so that it gets the value of the price.
<input className="input__price" type="text" value={price} onChange={this.updatePrice} />
The rest of the component was working well.
This is the result:
import React, { Component } from 'react'
import '../css/ProductsDetails.css'
import {AiOutlineArrowLeft} from "react-icons/ai";
import {Link} from 'react-router-dom'
export default class ProductsDetails extends Component {
state = {
id: this.props.match.params.id,
price: '0'
}
updatePrice = (e) => {
console.log(e);
this.setState({
price: e.target.value
})
}
render() {
const {price} = this.state
return (
<div className="products__details">
<Link to="/"><AiOutlineArrowLeft className="nav__arrow" /></Link>
<h1 className="details__title">{listProduct.title}</h1>
<div className="details__align--desk">
<div className="details__img">
<img className="product__img" src={listProduct.image} alt="Affichage du produit"/>
</div>
<div className="products__align--desk">
<h2 className="product__title">Description</h2>
<p className="product__description">{listProduct.description}</p>
<h2 className="product__title">Price</h2>
<form className="form__price">
<input className="input__price" type="text" value={price} onChange={this.updatePrice} />
<p>Price (including VAT): {Math.round((listProduct.price + listProduct.price * 0.2)*100) /100} €</p>
<br/>
<input className="btn__update" type="submit" value="Update product" />
</form>
</div>
<div className="category__align--desk">
<h2 className="product__title">Category</h2>
<p className="product__category">{listProduct.category}</p>
</div>
</div>
</div>
)
}
}
Start off with the price at 0 (not in quotes) in state, and then...
const price = this.state.price || (this.props.listProduct ? this.props.listProduct.price : 0)
<input className="input__price" type="text" value={price} onChange{this.updatePrice} />
So if the state value has been updated, that will be used, if not it will check if the price is available in props and use that, and if not it will display zero.
I have created a ToDo App in React. I want to add a single button which when I clicked on removes the whole todo list and shows the message to the user "You don't have any todo's". I am trying to add functionality but can't seem to find a perfect way.
I have given all the Todos a unique id and I also to grab these id's but don't how to use them to remove all Todos from a single button only. Help me. Thanks in advance
here is my main component App.js
import React, { Component } from 'react';
import PrintTodo from "./printtodo"
import Addtodo from "./addTodo"
class App extends Component {
state = {
todos: [
{id:1, content:"Buy Tomatoes"},
]
}
deleteTodo = (id) => {
const todos = this.state.todos.filter(todo => {
return todo.id !== id
})
this.setState({
todos
})
}
addTodo = (todo) => {
todo.id = Math.random()
// console.log(todo)
let todos = [...this.state.todos, todo]
this.setState({
todos
})
}
button = () => {
// console.log(this.state)
const allTodos = this.state.todos.filter(todo => {
console.log(todo)
})
// const id = 10;
// console.log(allTodos)
// allTodos.forEach(todo => {
// // console.log(todo)
// const arr = new Array(todo)
// arr.pop()
// })
}
render(){
// console.log(this.state)
return (
<div className="App">
<div className="container">
<header className="text-center text-light my-4">
<h1>ToDo - List</h1>
<form>
<input type="text" name="search" placeholder="Search ToDo's" className="form-control m-auto"/>
</form>
</header>
<PrintTodo addTodo={this.state.todos} deleteTodo={this.deleteTodo}/>
<Addtodo addTodo={this.addTodo} allTodos={this.button}/>
</div>
</div>
)
}
}
export default App;
PrintTodo Component
import React from 'react'
const printTodo = ({addTodo, deleteTodo, }) => {
// console.log(addTodo)
const todoList = addTodo.length ? (
addTodo.map(todo => {
return (
<ul className="list-group todos mx-auto text-light" key={todo.id}>
<li className="list-group-item d-flex justify-content-between align-items-center">
<span>{todo.content}</span>
<i className="far fa-trash-alt delete" onClick={()=>{deleteTodo(todo.id)}}></i>
</li>
</ul>
)
})
) : (
<p className="text-center text-light">You don't have any ToDo's</p>
)
return (
<div>
{todoList}
</div>
)
}
export default printTodo
AddTodo Component
import React, { Component } from 'react'
class Addtodo extends Component{
state = {
content: ""
}
handleChange = (e) => {
this.setState({
content: e.target.value
})
}
handleSubmit = (e) => {
e.preventDefault()
this.props.addTodo(this.state)
this.setState({
content: ""
})
}
render(){
// console.log(this.props.allTodos)
return(
<div>
<form className="text-center my-4 add text-light" onSubmit={this.handleSubmit}>
<label htmlFor="add">Add a New ToDo</label>
<input onChange={this.handleChange} type="text" name="add" id="add" className="form-control m-auto" value={this.state.content}/>
</form>
<button onClick={() => {this.props.allTodos()}}>Clear Whole List</button>
</div>
)
}
}
export default Addtodo
In your app.js make this your button component.
button = () => {
this.setState({todos: []})
})
Resetting your todos to an empty array will delete all your todos.
I have a problem. My if statement always returns an error.
What is the problem with it? It's a simple code.
I want to compare two inputs from the database and post the first one by HTTP request.
componentDidMount() is only for developing purposes, to see recent results added.
handleSubmit(e) {
e.preventDefault();
const itemsRef = firebase.database().ref('items');
itemsRef.on('value', (snapshot) => {
if (this.state.testNumberCheck === this.state.testNumber && this.state.usernameCheck === this.state.username){
return alert('udalo sie!');
}
else return alert('error');
});
}
render() {
return (
<div className='app'>
<header>
<div className="wrapper">
<h1>Sprawdź wyniki badania</h1>
</div>
</header>
<div className='container'>
<section className='add-item'>
<form onSubmit={this.handleSubmit}>
<input type="text" name="usernameCheck" placeholder="Podaj numer testu" onChange={this.handleChange} value={this.state.usernameCheck} />
<input type="number" name="testNumberCheck" placeholder="Numer telefonu" onChange={this.handleChange} value={this.state.testNumberCheck} />
<button>Sprawdź test</button>
</form>
</section>
<section className='display-item'>
<div className="wrapper">
<ul>
{this.state.items.map((item) => {
return (
<li key={item.id}>
<h3>Numer testu: <strong>{item.user}</strong></h3>
<h3>Numer telefonu: <strong>{item.title}</strong></h3>
</li>
)
})}
</ul>
</div>
</section>
</div>
</div>
);
}
}
export default App;
Here's the full code of App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import firebase from './firebase.js';
class App extends Component {
constructor() {
super();
this.state = {
testNumber: '',
testNumberCheck: '',
username: '',
usernameCheck: '',
valueCheck: '',
items: []
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit(e) {
e.preventDefault();
const itemsRef = firebase.database().ref('items');
itemsRef.on('value', (snapshot) => {
if (this.state.testNumberCheck === this.state.testNumber && this.state.usernameCheck === this.state.username){
return alert('udalo sie!');
}
else return alert('error');
});
}
componentDidMount() {
const itemsRef = firebase.database().ref('items');
itemsRef.on('value', (snapshot) => {
let items = snapshot.val();
let newState = [];
for (let item in items) {
newState.push({
id: item,
title: items[item].title,
user: items[item].user,
});
}
this.setState({
items: newState
});
});
}
render() {
return (
<div className='app'>
<header>
<div className="wrapper">
<h1>Sprawdź wyniki badania</h1>
</div>
</header>
<div className='container'>
<section className='add-item'>
<form onSubmit={this.handleSubmit}>
<input type="text" name="usernameCheck" placeholder="Podaj numer testu" onChange={this.handleChange} value={this.state.usernameCheck} />
<input type="number" name="testNumberCheck" placeholder="Numer telefonu" onChange={this.handleChange} value={this.state.testNumberCheck} />
<button>Sprawdź test</button>
</form>
</section>
<section className='display-item'>
<div className="wrapper">
<ul>
{this.state.items.map((item) => {
return (
<li key={item.id}>
<h3>Numer testu: <strong>{item.user}</strong></h3>
<h3>Numer telefonu: <strong>{item.title}</strong></h3>
</li>
)
})}
</ul>
</div>
</section>
</div>
</div>
);
}
}
export default App;
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.