Assigning onClick button to the proper feature. Map function ReactJS - javascript

I created this mockup and I am trying to put this into real life
component mockup
I started from something simple so I created 3 buttons and an array
but what happens is that when I click on any button I see all of the features, and my goal was to when I click on SMS I see sms.features etc. But for now I see this that way current result
import React, { Component } from "react";
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
isHidden: true,
features: [
{
name: "sms.features",
key: "1",
icon: "sms icon"
},
{
name: "pricing.features",
key: "2",
icon: "pricing icon"
},
{
name: "api.features",
key: "3",
icon: "api icon"
}
],
buttons: [
{
name: "sms",
key: 1
},
{
name: "pricing",
key: 2
},
{
name: "api",
key: 3
}
]
};
this.toggleHidden = this.toggleHidden.bind(this);
}
toggleHidden() {
this.setState({
isHidden: !this.state.isHidden
});
}
render() {
return (
<div style={{ marginLeft: "20%" }}>
<div className="features__details__grid">
{!this.state.isHidden &&
this.state.features.map((object, key) => (
<div key={key}>{object.name}</div>
))}
</div>
<div className="buttons">
{this.state.buttons.map((button, key) => (
<div key={key}>
<button onClick={this.toggleHidden}>{button.name}</button>
</div>
))}
</div>
</div>
);
}
}

So, since you want to show only one, the isHidden should really be a pointer to which feature should be visible (by targeting the key property)
import React, { Component } from "react";
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
visibleFeature: "0",
features: [
{
name: "sms.features",
key: "1",
icon: "sms icon"
},
{
name: "pricing.features",
key: "2",
icon: "pricing icon"
},
{
name: "api.features",
key: "3",
icon: "api icon"
}
],
buttons: [
{
name: "sms",
key: "1"
},
{
name: "pricing",
key: "2"
},
{
name: "api",
key: "3"
}
]
};
this.toggleHidden = this.toggleHidden.bind(this);
}
toggleHidden(key) {
this.setState(state=>{
if (state.visibleFeature === key) return {visibleFeature: 0}
return {visibleFeature: key}
});
}
render() {
const feature = this.state.visibleFeature;
return (
<div style={{ marginLeft: "20%" }}>
<div className="features__details__grid">
{this.state.features.map((object) => (
feature === object.key && <div key={object.key}>{object.name}</div>
))}
</div>
<div className="buttons">
{this.state.buttons.map((button) => (
<div key={button.key}>
<button onClick={()=>this.toggleHidden(button.key)}>{button.name}</button>
</div>
))}
</div>
</div>
);
}
}
Demo at https://codesandbox.io/s/8y5q120wxj

Related

Attempting to show array element of react select in list item

I am using react-select to store multiple elements and am using the map function to display elements which is working fine. But when I am using the same element in another class to display in a list element it shows a blank.
Here is the code where I am displaying the multiple options.
const Departments = [
{ label: "OneIT", value: "OneIT" },
{ label: "HR", value: "HR" },
{ label: "Vigilance", value: "Vigilance" },
{ label: "Ethics", value: "Ethics" },
{ label: "Corporate Services", value: "Corporate Services" },
{ label: "Legal", value: "Legal" },
{ label: "Sports", value: "Sports" },
{ label: "TQM", value: "TQM" },
{ label: "Iron Making", value: "Iron Making" },
{ label: "TMH", value: "TMH" }
];
class MultiSelect2 extends Component {
state = {
selectedOptions: []
};
handleChangeField = selectedOptions => {
this.setState({ selectedOptions });
};
render() {
const { selectedOption } = this.state;
return (
<div className="container">
<div className="row">
<div className="col-md-2"></div>
<div className="col-md-8">
<span>Select Department</span>
<Select
value={selectedOption}
options={Departments}
onChange={this.handleChangeField}
isMulti
/>
{this.state.selectedOptions.map(o => (
<p>{o.value}</p>
))}
</div>
<div className="col-md-4"></div>
</div>
</div>
);
}
}
I am trying to display this in another class in the list item but it is not showing.
export class Confirm extends Component {
state = {
selectedOptions: []
};
render() {
const {
values: {selectedOptions
}
} = this.props;
return (
<List>
<ListItemText primary="Departments" secondary={selectedOptions} />
</List>

Filling a model with a list from Textarea

Now I do not really understand you. Sorry, I just started this whole study not so long ago. I’ll try to explain again what I can’t do.
I have an empty object and an object with data with the same structure.
data: [
{id: 1, title: "title1"},
{id: 2, title: "title1"},
{id: 3, title: "title3"},
{id: 4, title: "title4"},
{id: 5, title: "title3"}
],
item: [
{
itemId: "",
itemname: ""
}
]
And I have select and textarear. Select have data, textarear empty. Textarear displays title.
I want to press a button. Selected item from select. copied to textarear (title only), and also itemId - this selected element id: 5 and itemname - the same title: "title3" element, was recorded in item [].
https://codesandbox.io/s/priceless-hermann-g9flw
Please do check now
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
id: null,
title: "",
filmItem: "",
listFilms: [],
data: [
{ id: 1, title: "title1" },
{ id: 2, title: "title2" },
{ id: 3, title: "title3" },
{ id: 4, title: "title4" }
],
item: []
};
this.onChange = this.onChange.bind(this);
this.onChangeArea = this.onChangeArea.bind(this);
this.addFilm = this.addFilm.bind(this);
this.choice = this.choice.bind(this);
}
addFilm(film) {
const selectedData = this.state.data.find(item => item.id == film);
console.log(selectedData);
this.setState({
listFilms: [...this.state.listFilms, selectedData.title],
item: [
...this.state.item,
{ itemId: selectedData.id, itemname: selectedData.title }
]
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onChangeArea = e => {
this.setState({ [e.target.name]: e.target.value.split("\n") });
};
choice(title) {
this.setState({ filmItem: title });
}
render() {
return (
<div className="App">
<div className="row App-main">
<div>
<select name="filmItem" size="4" onChange={e => this.onChange(e)}>
{this.state.data.map(film => (
<option key={film.title} value={film.id}>
{film.title}
</option>
))}
</select>
</div>
<div>
<button
className="editButton"
onClick={() => this.addFilm(this.state.filmItem)}
>
button
</button>
</div>
<div>
<textarea
name="films"
onChange={this.onChangeArea}
value={this.state.listFilms.map(r => r).join("\n")}
/>
</div>
<div>
<input type="text" name="text-input" onChange={this.onChange} />
</div>
</div>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(this.state)}
</pre>
</div>
);
}
}
export default App;

ReactJS two way binding not working, somewhere wrong with binding

I'm new to reactJs, I'm not sure where it went wrong.
I suppose there is something wrong with binding input. I suppose, cant change input because of value={detail.name}. However, even though I have deleted value={detail.name}, Name: {detail.name} still keeps the original value.
Could somebody give me a hint?
import React, { Component } from "react";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
details: [
{ id: 1, name: "Tom", age: "20" },
{ id: 2, name: "zhunan", age: "22" },
{ id: 3, name: "kobe", age: "35" }
]
};
}
changeName(event) {
this.setState({
name: event.target.value
});
}
onDelete() {}
render() {
return (
<div>
<ul>
{this.state.details.map((detail, index) => (
<li key={index}>
Name: {detail.name} | age: {detail.age}
<input
style={{ marginLeft: "10px" }}
type="text"
onChange={this.changeName.bind(this)}
value={detail.name}
/>
</li>
))}
</ul>
</div>
);
}
}
export default App;
I updated the code a bit.
First of all, I moved the binding of the callback to the constructor (to have ONE callback instead of one per item*render)
I also changed the key used in the map to be the id, rather than the index of the current item.
Try, it, I hope it works for you.
import React, { Component } from "react";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
details: [
{ id: 1, name: "Tom", age: "20" },
{ id: 2, name: "zhunan", age: "22" },
{ id: 3, name: "kobe", age: "35" }
]
};
this.changeName = this.changeName.bind(this);
}
changeName(event) {
const {target} = event;
const id = Number(target.dataset.id);
const { details } = this.state;
this.setState({
details: details.map((detail) => {
if (detail.id === id) {
return {
...detail,
name: target.value,
}
}
return detail;
}),
});
}
onDelete() {}
render() {
return (
<div>
<ul>
{this.state.details.map(({ id, age, name }) => (
<li key={id}>
Name: {name} | age: {age}
<input
style={{ marginLeft: "10px" }}
type="text"
onChange={this.changeName}
data-id={id}
value={name}
/>
</li>
))}
</ul>
</div>
);
}
}
export default App;
Your code works fine, nothing wrong with the input data binding. The problem is you're setting the name property directly to the state object. That would make it go from this:
this.state = {
details: [
{ id: 1, name: "Tom", age: "20" },
{ id: 2, name: "zhunan", age: "22" },
{ id: 3, name: "kobe", age: "35" }
]
}
To this:
this.state = {
details: [
{ id: 1, name: "Tom", age: "20" },
{ id: 2, name: "zhunan", age: "22" },
{ id: 3, name: "kobe", age: "35" }
],
name: "Bob"
}
Which has no effect on how the component gets rendered. To properly change the name of one of the details, which is what I assume you want, you also need to do a find that detail object to modify. Like this:
changeName(e, target_detail) {
this.setState({
// always update the WHOLE STATE OBJECT! using a map
details: this.state.details.map(detail => {
// the detail we want to modify has the same ID
if(detail.id === target_detail.id) {
// modify the name value of only that
target_detail.name = e.target.value
}
})
});
}
render method:
render() {
return (
<div>
<ul>
{this.state.details.map((detail, index) => (
<li key={index}>
Name: {detail.name} | age: {detail.age}
<input
style={{ marginLeft: "10px" }}
type="text"
// arrow functions implicitly "bind" the current this context:
onChange={e => this.changeName(e, detail)}
value={detail.name}
/>
</li>
))}
</ul>
</div>
);
}

Creating multi switches dynamically using React-switch

I am having a list of data, which i displayed in the frontend using map function. Each data will have an switch button. If a user clicks on a particular, it will display an description regarding the data below. Now, if i use static data. it switch working properly. But all get selected at the same time. I want only the particular one to get select, when i click the particular one. I am using react-switch library for the switch. Below is my code, Pleasse check and let me know, how cal I achieve that.
/***Parent Component***/
import React, { Component } from "react";
import ReqLists from "./ReqLists";
class Requirements extends Component {
constructor(props) {
super(props);
this.state = {
reqs: [
{
id: 0,
name: "Application",
details: "Do you require an application from volunteers?"
},
{ id: 1, name: "Screening Questions", details: "", description: "Dummy content" },
{
id: 2,
name: "Recurring commitment",
details:
"Does this opportunity require a recurring commitment from volunteers?", description: "Dummy content"
},
{ id: 3, name: "Documents for volunteers to upload ", details: "", description: "Dummy content" },
{ id: 4, name: "Waiver & Release of Liability Forms", details: "", description: "Dummy content" },
{ id: 5, name: "Parental Consent & Medical Form", details: "", description: "Dummy content" },
{ id: 6, name: "Age", details: "", description: "Dummy content" },
{ id: 7, name: "Certifications", details: "", description: "Dummy content" },
{ id: 8, name: "Languages", details: "", description: "Dummy content" },
{ id: 9, name: "Skils", details: "", description: "Dummy content" },
{ id: 10, name: "Additional Requirements", details: "", description: "Dummy content" },
{ id: 11, name: "Additional Details", details: "", description: "Dummy content" }
],
checked: 0
};
}
handleChange = id => {
const checked = this.state.checked;
checked[id] = checked.hasOwnProperty(id) ? !checked[id] : true;
this.setState({ checked });
};
render() {
return (
<div style={{ width: "100%" }}>
<ReqLists
lists={this.state.reqs}
onChange={this.handleChange}
checked={this.state.checked}
/>
</div>
);
}
}
export default Requirements;
/***Child Component***/
import React, { Component } from "react";
import { withStyles, Typography } from "#material-ui/core";
import Switch from "react-switch";
class ReqLists extends Component {
render() {
const { lists, classes } = this.props;
return (
<div className={classes.reqWrapper}>
{lists &&
lists.map(list => {
return (
<div className={classes.reqCover} key={list.id}>
<div className={classes.reqDetails}>
<Typography className={classes.reqListName}>
{list.name}
<span className={classes.reqListDetails}>
{list.details}
</span>
</Typography>
<Switch
className={classes.reqSwitch}
onChange={() => this.props.onChange(list.id)}
checked={this.props.checked === list.id}
offColor="#cacaca"
onColor="#2299e9"
uncheckedIcon={
<div className={classes.checkedIcon}>NO</div>
}
checkedIcon={<div className={classes.checkedIcon}>YES</div>}
height={17}
width={35}
/>
</div>
{this.props.checked === list.id ? (
<div>
{list.description}
</div>
) : null}
</div>
);
})}
</div>
);
}
}
export default withStyles(styles)(ReqLists);
Change your handleChange method with this: All you need to check if the selected id is not equals to checked id update checked state.
handleChange = id => {
let selectedItemIndex = this.state.reqs.findIndex(item => item.id === id);
if (selectedItemIndex !== this.state.checked) {
this.setState({checked: selectedItemIndex});
}else{
this.setState({checked: null});
}
};

REACT onChange bind this error

So i have this REACT code which should work :
App.jsx:
class App extends Component {
constructor(props){
super(props);
this.state = {count: props.initialCount};
this.onChange = this.onChange.bind(this);
this.state = {
questions:[
{
id: 1,
text: 'What is your name ?',
choices: [
{
id: 'a',
text: 'Michael'
},
{
id: 'b',
text: 'Brad'
},
{
id: 'c',
text: 'Steven'
}
],
correct: 'b'
},
{
id: 2,
text: 'What is your mothers name ?',
choices: [
{
id: 'a',
text: 'Sara'
},
{
id: 'b',
text: 'Sue'
},
{
id: 'c',
text: 'Donna'
}
],
correct: 'c'
},
{
id: 3,
text: 'What is your father name ?',
choices: [
{
id: 'a',
text: 'Bobby'
},
{
id: 'b',
text: 'Harry'
},
{
id: 'c',
text: 'Wayne'
}
],
correct: 'a'
},
{
id: 4,
text: 'What is your friend name ?',
choices: [
{
id: 'a',
text: 'John'
},
{
id: 'b',
text: 'Paul'
},
{
id: 'c',
text: 'Dan'
}
],
correct: 'c'
}
],
score: 0,
current: 1
}
}
render(){
return(
<div onClick={this.onChange}>
<QuestionList {...this.state} />
</div>
)
}
}
export default App
QuestionList.jsx :
class QuestionList extends Component {
render(){
return(
<div className="questions">
{
this.props.questions.map(question => {
return <Question question={question} key={question.id} {...this.props} />
})
}
</div>
)
}
}
export default QuestionList
Question.jsx :
class Question extends Component {
render(){
const {question} = this.props;
return(
<div className="well">
<h3 >{question.text}</h3>
<hr />
<ul className="list-group">
{
this.props.question.choices.map(choice => {
return(
<li className="list-group-item">
{choice.id} <input type="radio" name={question.id} value={choice.id} /> {choice.text}
</li>
)
})
}
</ul>
</div>
)
}
}
export default Question
except it throws this error in console : TypeError: _this.onChange is undefined
I google it and found out that :
Make sure you do this.onChange = this.onChange.bind(this) in your constructor
But when I add that on my controller i get this error : TypeError: this.onChange is undefined
class Question extends Component {
onChange(e) {
//Your change code here!!
}
render(){
const {question} = this.props;
return(
<div className="well">
<h3 >{question.text}</h3>
<hr />
<ul className="list-group">
{
this.props.question.choices.map(choice => {
return(
<li className="list-group-item">
{choice.id} <input type="radio" onChange={this.onChange.bind(this)} name={question.id} value={choice.id} /> {choice.text}
</li>
)
})
}
</ul>
</div>
)
}
}
export default Question
You should have a onChange method in your class.
If you want to put it in the constructor you need to do it like this:
Note: this is an example from the react docs, which are linked below
export class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
this.onChange = this.onChange.bind(this);
}
onChange() {} // add this
render() {
return (
<div onClick={this.onChange}>
Clicks: {this.state.count}
</div>
);
}
}
docs: https://facebook.github.io/react/docs/reusable-components.html#es6-classes
To avoid an error with binding this, you have two options:
Using this.onClick = this.onClick.bind(this); (inside constructor)
Using arrow function for onClick function
I hope this trick helps you.

Categories

Resources