Get keys of every object and insert that data into array - javascript

I want to get the keys of every frame object and insert that data into array. After it should have arrays in array. I have tried multiple ways and have not figured it out. Any suggestions?
This is the output.json that i will be working with, it could go up to 550 frame number's.
[{"frame_number": 1, "roi0": [101.78202823559488, 99.39509279584912, 49.546951219239915, 29.728170731543948], "intensity0": 80.0, "roi1": [101.78202823559488, 99.39509279584912, 49.546951219239915, 29.728170731543948], "intensity1": 157.0},
{"frame_number": 2, "roi0": [102.56623228630755, 97.95906005049548, 50.25603182631066, 30.153619095786393], "intensity0": 80.0, "roi1": [102.56623228630755, 97.95906005049548, 50.25603182631066, 30.153619095786393], "intensity1": 158.0},
{"frame_number": 3, "roi0": [103.39336535376313, 98.20468223716023, 49.58465295946593, 29.750791775679556], "intensity0": 80.0, "roi1": [103.39336535376313, 98.20468223716023, 49.58465295946593, 29.750791775679556], "intensity1": 157.0},
The following is my app.js where i get the output.json file from the api and send it through to a component, button_footer
import "bootstrap/dist/css/bootstrap.css";
import React from "react";
import Radio_Button from "./components/Radio_Button.js";
import Buttons_Footer from "./components/Buttons_Footer.js";
import LeftPane from "./components/LeftPane.js";
//import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { apiResponse: [] };
}
// Comunicate with API
callAPI() {
fetch("http://localhost:9000/IntensityAPI") //React app talks to API at this url
.then(res => res.json())
.then(res => this.setState({ apiResponse: res }));
}
componentWillMount() {
this.callAPI();
}
render() {
return (
<div className="App">
<header className="App-header">
<p></p>
<div class="row fixed-bottom no-gutters">
<div class="col-3 fixed-top fixed-bottom">
<LeftPane></LeftPane>
</div>
<div class="offset-md-3" >
<Buttons_Footer readings = {this.state.apiResponse}/>
</div>
</div>
</header>
</div>
);
}
}
export default App;
The following is the button_footer which is where I tried to handle this data and put it in a array but failed.
import $ from "jquery";
import React, { Component } from 'react';
import { MDBFormInline } from 'mdbreact';
import { Container, Row, Col } from 'reactstrap';
import Radio_Button from "./Radio_Button.js";
// Footer Component with checkbox's used to select region/region's of interest
class Buttons_Footer extends Component {
// Enables the Functionality of the "Select Multiple Region's" switch using jquerys
componentDidMount() {
$(".region").click(function(e){
if($('#customSwitches').is(':not(:checked)')){
if($('.region:checked').length > 1){ // Multiply regions unable to be selected
alert('You can not check multiple');
e.preventDefault();
}
}
});
$("#customSwitches").click(function(e){ // Multiply regions able to be selected
$(".region").prop('checked', false);
}); }
//<p>{this.props.region.roi0}</p>
render() {
return (
<Container class = "container offset-md-3" >
<div className='custom-control custom-switch' >
<input type='checkbox' className='custom-control-input' id='customSwitches' />
<label className='custom-control-label' htmlFor='customSwitches'>
Select Multiple Region's
</label>
{this.props.readings.map((region)=>{
return <Radio_Button region ={region} key ={region.frame_number}/>
})}
Object.keys({this.props.readings}).map((key, index) => {
const myItem = myObject[key]
return <MyComponent myItem={myItem} key={index} />
})
<MDBFormInline>
<input class="region" type="checkbox" name="region1" value="1" />
<label for="region1"> 1</label>
<input class="region" type="checkbox" name="region2" value="2" />
<label for="region2"> 2</label>
</MDBFormInline>
</div>
</Container>
);
}
}
export default Buttons_Footer;
```

Maybe this work
this.props.readings.map((reading, index) => {
Object.keys(reading).map((key, index) => {
const myItem = reading[key]
return <MyComponent myItem={myItem} key={index} />
})
})

Related

Handle multiple checkbox components in React

I´m having issues with creating my checkbox component(s).
Since I´m mapping over an object´s entries, where the keys are the sectiontitles and the values are arrays, filled with the checkable features.
I´m also using tailwind. I will let the code speek for itself I think :D
Checkboxes
Object structure, which im passing as a prop, down to the checkboxes component:
const features = {
Features: [
'Mintable',
'Burnable',
'Pausable',
'Permit',
'Votes',
'Flash Minting',
'Snapchots'
],
'Access Control': ['Ownable', 'Roles'],
Upgradeability: ['Transparent', 'UUPS']
};
Checkboxes component, which renders the checkbox component multiple times by mapping over the object (Ik the id is missing, but I dont know how to control the ID´s:
import React from 'react';
import { connect, useDispatch } from 'react-redux';
import Checkbox from '../../layout-blueprints/Checkbox';
import { featureCheckboxClick } from './Redux/actions';
const FeaturesComponent = ({ features }) => {
const dispatch = useDispatch();
return (
/* Card layout and heading */
<div className="bg-white p-4 rounded col-span-2 row-span-5">
{Object.entries(features).map(([key, value]) => {
return (
<div key={key}>
<h5 className="text-black m-t-4">{key}</h5>
<div className="border-bottom border-primary pb-2 mb-4 mr-20">
{/* Render feature checkboxes */}
{value.map((feature) => {
return (
<div className="flex justify-between m-2" key={feature}>
<div>
<Checkbox
onChange={() => dispatch(featureCheckboxClick(feature))}
/>
<span className="pl-2 text-lg">{feature}</span>
</div>
</div>
);
})}
</div>
</div>
);
})}
</div>
);
};
export default connect()(FeaturesComponent);
checkbox-component:
import React from 'react';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faCheck } from '#fortawesome/free-solid-svg-icons';
const Checkbox = () => {
return (
<label htmlFor="check-box-1" className="cursor-pointer relative">
<input
type="checkbox"
className="check-box-1 appearance-none h-4.5 w-4.5 border-2 border-primary rounded-sm relative translate-y-0.5"
/>
<FontAwesomeIcon
icon={faCheck}
className="-translate-x-4 translate-y-0.5 h-4.5 w-4.5 text-sm absolute text-white text-opacity-0 transition check-1 duration-200"
/>
</label>
);
};
export default Checkbox;
css tailwind directives (should be readable, even if you never worked with tailwind):
#tailwind components;
#tailwind utilities;
.check-box-1:checked {
#apply bg-primary;
}
.check-box-1:checked ~ .check-1 {
#apply text-opacity-100;
}
That´s all the code. Like I said, I´d usually work with a useState array or so, but It´s kinda hard to control it, bc there is so much nesting in the mapping, or am I thinking too complicated?
I´m honestly clueless and am glad for any help I can get, cheers!
I hope this helps
import { NextPage } from "next"
import { useState } from "react"
import CheckboxList from "../../../components/learn22/CheckboxList"
const myFoodList = [
'김치',
'고구마',
'감자',
'피자',
'햄버거',
'라면',
'제육볶음',
'삼계탕',
'닭곰탕',
'추어탕'
]
const MyCheckList: NextPage = () => {
const [checkedFoods, setCheckedFoods] = useState<string[]>([])
const onMyFoodChecked = (checked : string[]) => {
setCheckedFoods(checked)
console.log(checked)
}
return(
<CheckboxList
checkedFoods ={checkedFoods}
onCheck = {onMyFoodChecked}
foods = {myFoodList}
/>
)
}
export default MyCheckList;
import { FunctionComponent } from "react";
interface Props {
checkedFoods ?: string[];
onCheck: (checked : string[]) => void;
foods ?: string[];
}
const CheckBoxList : FunctionComponent<Props> = ({
checkedFoods =[],
onCheck,
foods =[]
}) => {
return (<ol>{foods.map((food, idx)=>
<li key={food + '-' + idx}>
<input type='checkbox' checked={checkedFoods?.includes(food)}onChange={(e)=>{
if(e.target.checked){
onCheck([...checkedFoods!, food])
} else{
onCheck(checkedFoods.filter((_food)=> _food !== food));
}
}}/>
<span>{food}</span>
</li>
)}
</ol> );
}
export default CheckBoxList;
[blog post that shows how to Handle multiple checkbox components in React][1]
[1]: https://codemasterkimc.tistory.com/459

Some problems with react.js

I'm recently working on react.js, and now I have two problems:
The file structure is like
>public
>src
>components
>img
x.png
Item.js
App.js
index.js
Item.js:
import React from 'react';
class Item extends React.Component{
constructor(props){
super(props);
}
render(){
return(
<li className="todo-app__item">
<div className="todo-app__checkbox">
<input type="checkbox" id={this.props.num}
checked={this.props.completed} onClick = {this.props.onClick}/>
<label htmlFor={this.props.num}></label>
</div>
<h1 className="todo-app__item-detail">{this.props.text}</h1>
<img src='./components/img/x.png' className="todo-app__item-x"/>
</li>
);
}
}
export default Item;
App.js
import './App.css';
import React from 'react';
import Item from './components/Item.js';
class Main extends React.Component{
constructor(props){
super(props);
this.state={tasks: []}
}
handleKeyDown = (e)=>{
if (e.key === 'Enter') {
this.setState (prevState => ({
tasks: [...prevState.tasks, {content: e.target.value, completed: false}]
}));
}
}
handleClick = (e) =>{
this.setState (prevState => {
let newTasks = prevState.tasks.slice();
newTasks[e].completed = !prevState.tasks[e].completed;
return{tasks: newTasks};
})
}
/*displayAll = () =>{
}
displayActive = () =>{
}
displayCompleted = () =>{
}
deleteCompleted = () =>{
}*/
render(){
return(
<section className="todo-app__main">
<input className="todo-app__input"
placeholder="What needs to be done?" onKeyDown={this.handleKeyDown} />
<ul className="todo-app__list" id="todo-list">
{this.state.tasks.map(item =>
<Item num={this.state.tasks.indexOf(item)} text={item.content} completed={item.completed}
onClick={() => this.handleClick(this.state.tasks.indexOf(item))}/>)}
</ul>
<footer className="todo-app__footer" id="todo-footer">
<div className="todo-app__total"> {this.state.tasks.filter(e=>e.completed===false).length} Left</div>
<ul className="todo-app__view-buttons">
<button>All</button>
<button>Active</button>
<button>Complete</button>
</ul>
<div className="todo-app__clean">
<button>Clear complete</button>
</div>
</footer>
</section>
);
}
}
My x.png is not showing properly. How to fix it?
The three buttons in the bottom, I hope that completed can do something like displaying the task that satisfies task[1]=true without deleting the item. How do I implement this?
You can modify the src attribute of img, the relative path is wrong now
<img src='./img/x.png' className="todo-app__item-x"/>
Use react state to render different buttons
{this.state.tasks[x].completed && <button>Complete</button>}
eg: when tasks x is completed, display button.

why does one react project use .bind(this) method but another react project does not use it? [duplicate]

This question already has answers here:
Arrow vs classic method in ES6 class
(1 answer)
Why we don't need to bind the arrow function in React?
(2 answers)
Closed 2 years ago.
I did 2 tutorials on using REACT. "to-do-app" is a django/react project while "robofriends" is a purely react project. "to-do-app" uses .bind(this) for its functions while "robofriends" does not use this method. While i understand why the .bind method is needed, i do not understand why "robofriends" was able to work without binding its functions.
to-do app (apps.js)
import React from 'react';
import './App.css';
class App extends React.Component{
constructor(){
super();
this.state={
todoList:[],
activeItem:{
id:null,
title:"",
completed:false
},
editing:false,
}
this.fetchTasks=this.fetchTasks.bind(this)
this.handleChange=this.handleChange.bind(this)
this.handleSubmit=this.handleSubmit.bind(this)
}
componentWillMount(){
this.fetchTasks()
}
fetchTasks(){
console.log('fetching')
fetch('http://127.0.0.1:8000/api/task-list/')
.then(response=>response.json())
.then(data=>
this.setState({todoList:data})
)
}
handleChange(e){
const name=e.target.name;
const value=e.target.value;
console.log('Name', name)
console.log('Value', value)
this.setState({
activeItem:{
...this.state.activeItem,
title:value
}
})
}
handleSubmit(e){
e.preventDefault()
console.log('ITEM', this.state.activeItem)
var url='http://127.0.0.1:8000/api/task-create/'
fetch(url, {
method:'POST',
headers:{
'Content-type':'application/json',
},
body:JSON.stringify(this.state.activeItem)
}).then((response) =>{
this.fetchTasks()
this.setState({
activeItem:{
id:null,
title:"",
completed:false
}
})
}).catch(function(error){
console.log('ERROR', error)
})
}
render(){
const tasks=this.state.todoList
return(
<div className="container">
<div id="task-container">
<div id="form-wrapper">
<form onSubmit={this.handleSubmit} id="form">
<div className="flex-wrapper">
<div style={{flex:6}}>
<input onChange={this.handleChange} className="form-control" id="title" type="text" name="title" placeholder="Add task" />
</div>
<div style={{flex:1}}>
<input id="submit" className="btn btn-warning" type="submit" name="Add" />
</div>
</div>
</form>
</div>
<div id="list-wrapper">
{tasks.map((task, index)=>{
return(
<div key={index} className="task-wrapper flex-wrapper">
<div style={{flex:7}}>
<span>{task.title}</span>
</div>
<div style={{flex:1}}>
<button className="btn btn-sm btn-outline-info">Edit</button>
</div>
<div style={{flex:1}}>
<button className="btn btn-sm btn-outline-dark delete">-</button>
</div>
</div>
)
})}
</div>
</div>
</div>
)
}
}
export default App;
robofriends(apps.js)
import React, {Component} from 'react';
import CardList from '../components/Cardlist';
// import {robots} from './robots';
import SearchBox from '../components/SearchBox';
import './App.css';
import Scroll from '../components/Scroll';
import ErrorBoundary from '../components/ErrorBoundary';
class App extends Component {
constructor(){
super()
this.state={
robots:[],
searchfield:''
} //a state is what changes in an app
}
componentDidMount(){
fetch('https://jsonplaceholder.typicode.com/users')
.then(response=> response.json())
.then(users => this.setState({robots:users}))
}
// remember to use => for functions you create yourself.
onSearchChange=(event) => {
this.setState({searchfield:event.target.value})
}
render(){
const {robots, searchfield}=this.state;
const filteredRobots=robots.filter(robot=>{
return robot.name.toLowerCase().includes(searchfield.toLowerCase());
})
if (!robots.length){
return <h1>Loading</h1>
}else{
return(
<div className='tc'>
<h1 className='f1'>Robofriends</h1>
<SearchBox searchChange={this.onSearchChange}/>
<Scroll>
<ErrorBoundary>
<CardList robots={filteredRobots}/>
</ErrorBoundary>
</Scroll>
</div>
);
}
}
}
export default App;
robofriends 'searchbox.js'
import React from 'react';
const SearchBox=({searchChange})=>{
return (
<div className='pa2'>
<input
className='pa3 ba b--green bg-lightest-blue'
type='search'
placeholder='search robots'
onChange={searchChange}
/>
</div>
);
}
export default SearchBox;
fetchTasks(){
if you define a function like this, then you need to .bind(this)
as this will lose the context of this of class, to maintain it we need to use .bind(this)
But if you use below one then no need to bind, it maintains the context of this, so no need of using .bind(this)
Arrow functions do not bind their own this, instead, they inherit the
one from the parent scope, which is called "lexical scoping"
fetchTasks = () => {
For more detail : DO READ
Hope the below snippet will help you get understanding :
const { useState , useEffect } = React;
class App extends React.Component {
constructor() {
super();
this.state = {
name : "Vivek"
}
this.withBound = this.withBound.bind(this);
}
withoutBound() {
console.log(this.state.name)
}
withBound() {
console.log(this.state.name)
}
withFatArrow = () => {
console.log(this.state.name)
}
render() {
return (
<div>
Check the console on click:
<br/><br/>
<button onClick={this.withoutBound}>Without Bind</button>
<br/><br/>
<button onClick={this.withBound}>With Bind</button>
<br/><br/>
<button onClick={this.withFatArrow}>Fat Arrow</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('react-root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>

Display radio buttons depending on attributes present in dictionary

I need to dynamically display radio buttons depending on how many roi_ (e.g roi0 or roi1) each frame_number has.
For example if frame_number: 1, had only one roi_ (roi0) attribute then it would display one radio button. But in the below output.json form the first three frames have two roi_ (roi0, roi2) so therefore two radio buttons are displayed.
I've tried multiple ways but cant get it.Any sugestions?
Also in Buttons_footer, ive displayed two radio buttons temporary as this is what i want it to look like, but to change dynamically depending on the data.
[{"frame_number": 1, "roi0": [101.78202823559488, 99.39509279584912, 49.546951219239915, 29.728170731543948], "intensity0": 80.0, "roi1": [101.78202823559488, 99.39509279584912, 49.546951219239915, 29.728170731543948], "intensity1": 157.0},
{"frame_number": 2, "roi0": [102.56623228630755, 97.95906005049548, 50.25603182631066, 30.153619095786393], "intensity0": 80.0, "roi1": [102.56623228630755, 97.95906005049548, 50.25603182631066, 30.153619095786393], "intensity1": 158.0},
{"frame_number": 3, "roi0": [103.39336535376313, 98.20468223716023, 49.58465295946593, 29.750791775679556], "intensity0": 80.0, "roi1": [103.39336535376313, 98.20468223716023, 49.58465295946593, 29.750791775679556], "intensity1": 157.0},
import "bootstrap/dist/css/bootstrap.css";
import React from "react";
import Radio_Button from "./components/Radio_Button.js";
import Buttons_Footer from "./components/Buttons_Footer.js";
import LeftPane from "./components/LeftPane.js";
//import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { apiResponse: [] };
}
// Comunicate with API
callAPI() {
fetch("http://localhost:9000/IntensityAPI") //React app talks to API at this url
.then(res => res.json())
.then(res => this.setState({ apiResponse: res }));
}
componentWillMount() {
this.callAPI();
}
render() {
return (
<div className="App">
<header className="App-header">
<p></p>
<div class="row fixed-bottom no-gutters">
<div class="col-3 fixed-top fixed-bottom">
<LeftPane></LeftPane>
</div>
<div class="offset-md-3" >
<Buttons_Footer readings = {this.state.apiResponse}/>
</div>
</div>
</header>
</div>
);
}
}
export default App;
import $ from "jquery";
import React, { Component } from 'react';
import { MDBFormInline } from 'mdbreact';
import { Container, Row, Col } from 'reactstrap';
import Radio_Button from "./Radio_Button.js";
// Footer Component with checkbox's used to select region/region's of interest
class Buttons_Footer extends Component {
// Enables the Functionality of the "Select Multiple Region's" switch using jquerys
componentDidMount() {
$(".region").click(function(e){
if($('#customSwitches').is(':not(:checked)')){
if($('.region:checked').length > 1){ // Multiply regions unable to be selected
alert('You can not check multiple');
e.preventDefault();
}
}
});
$("#customSwitches").click(function(e){ // Multiply regions able to be selected
$(".region").prop('checked', false);
}); }
//<p>{this.props.region.roi0}</p>
render() {
return (
<Container class = "container offset-md-3" >
<div className='custom-control custom-switch' >
<input type='checkbox' className='custom-control-input' id='customSwitches' />
<label className='custom-control-label' htmlFor='customSwitches'>
Select Multiple Region's
</label>
{this.props.readings.map((region)=>{
return <Radio_Button region ={region} key ={region.frame_number}/>
})}
<MDBFormInline>
<input class="region" type="checkbox" name="region1" value="1" />
<label for="region1"> 1</label>
<input class="region" type="checkbox" name="region2" value="2" />
<label for="region2"> 2</label>
</MDBFormInline>
</div>
</Container>
);
}
}
export default Buttons_Footer;
import React, { Component } from 'react';
import { MDBFormInline } from 'mdbreact';
import { Container, Row, Col } from 'reactstrap';
class Radio_Button extends Component {
//
render() {
return (
<div>
//<p>{this.props.region.roi0}</p>
<input class="region" type="checkbox" name="region1" value="1" />
<label for="region1"> 1</label>
</div>
);
}
}
export default Radio_Button;
Assuming that you don't know how many roi's will be in response:
Get keys of every frame object and insert that data into array. After that you should have arrays in array.
const keys = frames.map(frame => Object.keys(frame))
Filter keys with regex.
const filteredKeys = keys.map(frame => frame.filter(key => new RegExp(/^roi\d+$/).test(key)))
For each key that's left show button.
const showButtons = () => {
return filteredKeys.map(frame => frame.map(roi => <Button />))
}
That should work, but it won't be the fastest and cleanest solution.

Passing data to parent - recipebook React

I am working on the recipe book app and trying to implement the edit entry function.
How it works is to input recipe name (e.g Pasta), followed by ingredients (e.g egg, flour, salt). The ingredients have to be input with commas and will be shown as a list.
Pasta
-Egg
-Flour
i can see that it is somewhat working, because i can see the new entries in the input text (e.g initially was egg,flour,salt -> egg,flour,salt,water) when i tried to edit it again.
However, the extra ingredients (in the above example: water) is not showing up in the list. Do i have to figure a way to re-render the list?
updates:
I think i know where the error might be. There is some issue passing the data and setting the state.
<EditRecipe recipe={this.props.recipe} editRecipe={this.editRecipe.bind(this, this.props.recipe.id, recipe)}/>
App.js
import React, { Component } from 'react';
// import logo from './logo.svg';
import './App.css';
import uuid from 'uuid';
import Modal from 'react-modal';
import RecipeList from './components/RecipeList/RecipeList';
import AddRecipe from './components/AddRecipe/AddRecipe';
class App extends Component {
constructor(props){
super(props);
this.state = {
recipes:[]
};
}
getRecipes(){
this.setState({recipes:[
{
id: uuid.v4(),
food: "pumpkin pie",
ingredients: ["pumpkin puree", "sweetened condensed milk", "eggs", "pumpkin pie spice", "pie crust"]
},
{
id: uuid.v4(),
food: "spaghetti",
ingredients: ["noodles", "tomato sauce", "meatballs"]
},
{
id: uuid.v4(),
food: "onion pie",
ingredients: ["onion", "pie crust"]
},
]});
}
componentWillMount(){
this.getRecipes();
}
handleAddRecipe(recipe){
let recipes = this.state.recipes;
recipes.push(recipe);
this.setState({recipes: recipes});
}
handleDeleteRecipe(id){
let recipes = this.state.recipes;
let index = recipes.findIndex(x => x.id === id);
recipes.splice(index,1);
this.setState({recipes: recipes});
}
handleEditRecipe(id, recipe){
let recipes = this.state.recipes;
let index = recipes.findIndex(x => x.id === id);
recipes.splice(index,1,recipe);
this.setState({recipes: recipes});
}
render() {
return (
<div className="App">
<RecipeList recipes={this.state.recipes} onDelete={this.handleDeleteRecipe.bind(this)} onEdit={this.handleEditRecipe.bind(this)}/>
<AddRecipe addRecipe={this.handleAddRecipe.bind(this)}/>
</div>
);
}
}
export default App;
RecipeList.js
import React, { Component } from 'react';
import Collapsible from 'react-collapsible';
import RecipeItem from '../RecipeItem/RecipeItem'
import './RecipeList.css';
class RecipeList extends Component{
deleteRecipe(id){
this.props.onDelete(id);
}
editRecipe(id, recipe){
this.props.onEdit(id, recipe);
}
render(){
let recipeItem;
if(this.props.recipes){
recipeItem=this.props.recipes.map(recipe => {
return(
<RecipeItem onEdit={this.editRecipe.bind(this)} onDelete={this.deleteRecipe.bind(this)} key={recipe.id} recipe={recipe} />
)
});
}
return(
<div className="recipeList box">
{recipeItem}
</div>
)
}
}
export default RecipeList;
RecipeItem.js
import React, { Component } from 'react';
import Collapsible from 'react-collapsible';
import EditRecipe from '../EditRecipe/EditRecipe';
class RecipeItem extends Component{
deleteRecipe(id){
this.props.onDelete(id);
}
editRecipe(id, recipe){
this.props.onEdit(id, recipe);
}
render(){
let recipe=this.props.recipe
let foodName=recipe.food;
let ingredientItem;
if(recipe.ingredients){
ingredientItem=recipe.ingredients.map(ingredient=>{
return(
<a className="panel-block">
{ingredient}
</a>
)
})
}
return(
<ul>
<li className="Recipe">
<Collapsible trigger={foodName} transitionTime="200" easing="ease-in-out">
<nav className="panel">
<p className="panel-heading">
Ingredients
</p>
{ingredientItem}
<div className="panel-block">
<button className="button is-warning is-outlined" onClick={this.deleteRecipe.bind(this, this.props.recipe.id)}>
Delete
</button>
<EditRecipe recipe={this.props.recipe} editRecipe={this.editRecipe.bind(this, this.props.recipe.id, recipe)}/>
</div>
</nav>
</Collapsible>
</li>
</ul>
);
}
}
export default RecipeItem;
EditRecipe.js
import React, { Component } from 'react';
import RecipeForm from '../RecipeForm/RecipeForm';
// import './EditRecipe.css';
import Modal from 'react-modal';
import uuid from 'uuid';
// import Modal from 'boron/DropModal';
// import './RecipeList.css';
class RecipeEdit extends Component{
constructor(props){
super(props);
this.state = {
revisedRecipe:{
id: this.props.recipe.id,
food: this.props.recipe.food,
ingredients: this.props.recipe.ingredients
},
modalIsOpen: false,
speed: 100
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
openModal(){
this.setState({modalIsOpen: true});
}
closeModal(){
this.setState({modalIsOpen: false});
}
handleSubmit(e){
const revised = this.state.revisedRecipe;
this.props.editRecipe(revised);
e.preventDefault();
}
handleNameChange(e){
this.setState({revisedRecipe:{
food: e.target.value
}
});
}
handleIndChange(e){
this.setState({revisedRecipe:{
ingredients: e.target.value
}
});
}
render(){
const speed = this.state.speed;
let recipe=this.props.recipe;
let foodName=this.state.revisedRecipe.food;
let ingredients=recipe.ingredients;
return(
<div>
<button className="button is-primary" onClick={this.openModal}>Edit Recipe</button>
<Modal
isOpen={this.state.modalIsOpen}
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
closeTimeoutMS={speed}
contentLabel="Example Modal"
>
<div className="field">
<h2 className="title is-2">Edit Recipe</h2>
<form>
<label className="label">Recipe</label>
<div className="control">
<input className="input" type="text" placeholder="Recipe Name" ref="recipeName" value={this.state.revisedRecipe.food} onChange={this.handleNameChange.bind(this)}/>
</div>
<div className="field">
<label className="label">Ingredients</label>
<div className="control has-icons-left has-icons-right">
<input className="input" type="text" placeholder="Enter ingredients. (if more than 1 ingredient, separate them with commas)" ref="ingredients" value={this.state.revisedRecipe.ingredients} onChange={this.handleIndChange.bind(this)}/>
<span className="icon is-small is-left">
<i className="fa fa-flask"></i>
</span>
</div>
</div>
<div className="field is-grouped">
<div className="control">
<button className="button is-primary" onClick={this.closeModal}>Edit Recipe</button>
</div>
<div className="control">
<button className="button" onClick={this.closeModal}>Cancel</button>
</div>
</div>
</form>
</div>
</Modal>
</div>
);
}
}
export default RecipeEdit;
I believe you're actually getting an error when trying to re-render after updating a list. The ingredients property in the recipes are an array (as shown in getRecipes()) but you're setting the new state of ingredients (in EditRecipe) as a string: "egg,flour,salt,water" and then trying to render the ingredients as an array: ingredients.map().
When you render an input field with an array <input value={["egg", "flour"]} /> it does show the values separated by comma, but the event.target.value in onChange is actually a string.
In EditRecipe's, handleIndChange could be fixed with:
this.setState({revisedRecipe: {ingredients: e.target.value.split(',')}});
This does have another problem, though in that you are overriding the revisedRecipe completely. So all of the setState calls should be something like:
const recipe = this.state.revisedRecipe;
recipe.ingredients = e.target.value.split(',');
this.setState({revisedRecipe: recipe);

Categories

Resources