I would like to know how we can retrieve text from ModelDropdown upon selecting an option:
import ModalDropdown from 'react-native-modal-dropdown';
...
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
category: '',
}
}
updateCategory(newCategory) {
this.setState({
category: newCategory
})
}
....
<ModalDropdown
style={{padding: 20}}
options={['Electronics', 'Furniture']}
textStyle={{fontSize: 20, color: 'black', fontWeight: 'bold',}}
dropdownTextStyle={{fontSize: 20, backgroundColor: '#FFF', color: 'black'}}
defaultValue = 'Select Category'
onSelect={(newCategory) => this.updateCategory(newCategory)}
/>
I m getting index value, like "0" for Electronics and "1" for Furniture.
I would like to get the text corresponding to that index.
Or is there any alternative to ModelDropdown which may help me in accomplish this task?
since you are getting corresponding index so you can easily take value from options array, just set it in state or some global variable.
you can do something like this.
constructor(props) {
super(props);
this.state = {
options:['Electronics', 'Furniture'],
}
}
and then in updateCategory take value like this
updateCategory(newCategory) {
this.setState({
textValue: this.state.options[newCategory]
})
}
Related
I am using a nightlight button library: react-native-selectmultiple-button
In this library there is a prop selected
Description: Type:Boolean. Default is false. The selected prop determines whether the button is selected and highlighted
Is there a way I can change the state of "selected" prop, depending on number of buttons selected?
For example, if I select more than 5 buttons, I want other buttons to be unselectable.
constructor(props) {
super(props)
this.state = {
numberOfbuttonsSelected:0
}
}
{
if(this.state.numberOfbuttonsSelected <5){
<SelectMulipleButton
selected={true}/>}
else{<SelectMulipleButton
selected={false}/>
}
}
The code above won't work any comments or advise would be really appreciated :)
This is the new code:
<View style={{ flexWrap: 'wrap', flexDirection: 'row',backgroundColor:'gray',paddingTop:10,paddingLeft:6,paddingRight:0,borderColor:'white', borderWidth:1}}>
{
multipleData.map(
(interest) =>
<SelectMultipleButton
key={interest}
buttonViewStyle={{
borderRadius: 0,
height: 40,
width: 110,
}}
textStyle={{
fontSize: 15,
}}
highLightStyle={{
borderColor: 'white',
backgroundColor: 'transparent',
textColor: 'white',
borderTintColor: 'white',
backgroundTintColor: '#6AAAC6',
textTintColor: 'white',
}}
multiple={true}
value={interest}
selected={this.state.multipleSelectedData.includes(interest)}
singleTap={valueTap => this.trackSelection(valueTap)} />
)
}
</View>
</ScrollView>
Sorry for the delay in replying. Please see my example component below. I have included explanations in comments inline in the code. Please reach out if you need further help.
export class YourComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
numberOfbuttonsSelected: 0,
multipleSelectedData: []
};
}
//This method is what you mainly need
trackSelection = value => {
if (!this.state.multipleSelectedData.includes(value)) { //This checks if the value already exists in the checked buttons list
if (this.state.numberOfbuttonsSelected < 5) { //Here we check if the number of selected buttons has exceeded the specified number
this.state.multipleSelectedData.push(value);
this.setState({
numberOfbuttonsSelected: this.state.numberOfbuttonsSelected + 1
});
} //else do nothing. Effectively, we are disabling the click on the button.
} else { //we are simply toggling the selection here
this.state.multipleSelectedData.splice(
this.state.multipleSelectedData.indexOf(value), 1
);
this.setState({
numberOfbuttonsSelected: this.state.numberOfbuttonsSelected - 1
});
}
};
render() {
return (
//Customize your render function. I just included one button as an example.
<View>
<SelectMultipleButton
multiple={true}
value={interest} //"interest" is just an example value. Change it according to your requirements for each button.
selected={this.state.multipleSelectedData.includes(interest)}
singleTap={valueTap => this.trackSelection(valueTap)} //valueTap is supposed to be the "value" prop's value for each
//button according to the lib's documentation, but if you're not comfortable using valueTap, you can
//simply pass "interest" (or your own custom value for the particular button) into the trackSelection() method
/>
</View>
);
}
}
EDIT
I went through the code in the lib and the onPress function in the SelectMultipleButton component is why your multiple selection still works:
<TouchableWithoutFeedback
onPress={() => {
if (this.props.multiple) {
this.setState({ selected: !this.state.selected })
this.props.singleTap(this.props.value)
} else {
if (!this.state.selected) {
this.setState({ selected: !this.state.selected })
this.props.singleTap(this.props.value)
}
}
}
}>
I know it's not a good idea to modify library files, but in this case, instead of using the whole lib, you can copy over this file to your project (don't remove the author credit at the top of this file) and add a prop selectable to it and modify the onPress thus:
<TouchableWithoutFeedback
onPress={() => {
if (this.props.multiple) {
if(this.props.selectable) {
this.setState({ selected: !this.state.selected })
this.props.singleTap(this.props.value)
}
} else {
if (!this.state.selected) {
this.setState({ selected: !this.state.selected })
this.props.singleTap(this.props.value)
}
}
}
}>
Pass the prop thus:
<SelectMultipleButton
multiple={true}
value={interest}
selectable={this.state.multipleSelectedData.includes(interest) || this.state.numberOfbuttonsSelected < 5}
selected={this.state.multipleSelectedData.includes(interest)}
singleTap={valueTap => this.trackSelection(valueTap)}
/>
This should solve your problem.
I am fairly new to React and was wondering if anybody could give me an insight on a problem I am stuck with.
Right now I have a parent(Hello.js) component and two children(Mixer.js and renderCont.js) at the same level.
I am trying to render a list in the Mixer.js and display its corresponding objects in the Hello.js through by passing the values into RenderCont.js. I've gotten to a point where nothing is displayed before I click on any of the list to pass on a object.
From here is where I am stuck: I want the first object of the list to be displayed as a default, at the same time bold the first in the list. And then execute the as I have below.
This is my first time posting a question on stackoverflow so I'm not sure if my question makes sense with the attached codes but I will greatly appreciate any kind of support.
Parent Hello.js:
import React, { Component } from 'react';
import RenderCont from './renderCont.js';
import Mixer from './Mixer';
class Hello extends Component{
constructor(props) {
super(props);
this.state = {
items: [{
id: 0,
name: "First",
background: "white"
}, {
id: 1,
name: "Second",
background: "yellow"
}, {
id: 2,
name: "Third",
background: "blue"
}],
selectedItem: 0
}
this.handle = this.handle.bind(this)
}
handle(value) {
// console.log(this.state.selectedItem);
this.setState({
selectedItem: value
})
}
render() {
const list = this.state.items.map((item) => {
return(item);
})
return (
<div>
<Mixer item={list} onClick={this.handle} selected={this.state.selectedItem}/>
<ul id = "todo" >
<RenderCont item={this.state.selectedItem}/>
</ul>
</div>
)
}
}
export default Hello;
Mixer.js Child1:
import React, { Component } from 'react';
class Mixer extends Component{
constructor(props) {
super(props);
this.state = {
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(item){
this.props.onClick(item);
}
renderTodos(propItems) {
return (
<div>
{propItems.map((item) => (
<li className={this.props.selected === item ? 'media clicked' : 'media'}
key={item.id} onClick = {() => this.handleClick(item)}>
{item.name}
</li>
))}
</div>
)
}
render() {
return (
<div className="yoyoyo">
{this.renderTodos(this.props.item)}
</div>
)
}
}
export default Mixer;
Second Child Comp renderCont.js :
import React, { Component } from 'react';
class RenderCont extends Component{
constructor(props) {
super(props);
}
renderBox(item){
return(
<div style={{color:item.background}}>
{item.id}
{item.name}
</div>
)
}
render() {
return (
<div className="yoyo">
{this.renderBox(this.props.item)}
</div>
)
}
}
export default RenderCont;
and the CSS:
.yoyo{
left: 500px;
background-color:red;
width:500px;
height:500px;
}
.media{
color: black;
}
.clicked{
font-weight: 900;
}
.yoyoyo{
background-color:lightblue;
width:200px;
height:200px;
}
I think the problem is some mismatch between the initial and eventual value of this.props.selected in Mixer.js. You initially set this.state.selectedItem = 0, and this is what is initially passed as the selected prop to Mixer. But the test you apply in that component is
this.props.selected === item ?
While there is one item.id that === 0, there is never an item that === 0. So no items are highlighted at first. But then, once an item is clicked and selectedItem is actually set to an item, the entry is made bold.
So it looks like you need to either make your initial selection equal to the item.id === 0 reference, or consistently refer to items within your components by their id's.
I have an location app which can save name of locations.
I am trying to get each saved location a red border by clicking on it.
What it does is changing the border color of all the categories.
How can I apply that?
class Categories extends Component {
constructor(props) {
super(props);
this.state = {
term: '',
categories: [],
selectedCategories: [],
hidden: true,
checkboxState: true
};
}
toggle(e) {
this.setState({
checkboxState: !this.state.checkboxState
})
}
onChange = (event) => {
this.setState({ term: event.target.value });
}
addCategory = (event) => {
if (this.state.term === '') {
alert('Please name your category!')
} else {
event.preventDefault();
this.setState({
term: '',
categories: [...this.state.categories, this.state.term]
});
}
}
render() {
return (
<div className="categories">
<h1>Categories</h1>
<div className='actions'>
<button className="delete" onClick={this.deleteCategory}>Delete</button>
<button className="edit" onClick={this.editCategory}>Edit</button>
</div>
<p>To add new category, please enter category name</p>
<form className="App" onSubmit={this.addCategory}>
<input value={this.state.term} onChange={this.onChange} />
<button>Add</button>
</form>
{this.state.categories.map((category, index) =>
<button
key={index}
style={this.state.checkboxState ? { borderColor: '' } : { borderColor: 'red' }}
checked={this.state.isChecked}
onClick={this.toggle.bind(this)}>
{category}</button>
)}
</div >
);
}
}
I want to be able to control each selected category seperatly, to be able to delete and edit theme as well.
You can set the state based on index and retrieve the similar way,
Code:
{this.state.categories.map((category, index) =>
<button
key={index}
id={`checkboxState${index}`}
style={!this.state[`checkboxState${index}`] ?
{ borderColor: '' } : { border: '2px solid red' }}
checked={this.state.isChecked}
onClick={this.toggle}>
{category}</button>
)}
You can see how I am checking the state dynamically this.state[`checkboxState${index}`] and also I have assigned an id to it.
In toggle method:
toggle = (e) => {
const id = e.target.id;
this.setState({
[id]: !this.state[id]
})
}
FYI, this is a working code, you can see it
https://codesandbox.io/s/vy3r73jkrl
Let me know if this helps you :)
Here's a really bad example using react. I'd more than likely use this.props.children instead of just cramming them in there. This would allow it to be more dynamic. And instead of using state names we could then just use indexes. But you'll observe, that the parent container decides which child is red by passing a method to each child. On click, the child fires the method from the parent. How you implement it can vary in a million different ways, but the overall idea should work.
class ChildContainer extends React.Component
{
constructor(props)
{
super(props);
}
render() {
let color = this.props.backgroundColor;
return(
<section
className={'child'}
style={{backgroundColor: color}}
onClick={this.props.selectMe}
>
</section>
)
}
}
class Parent extends React.Component
{
constructor(props)
{
super(props)
this.state = {
first : 'Pink',
second : 'Pink',
third : 'Pink',
previous: null
}
this.updateChild = this.updateChild.bind(this);
}
updateChild(name)
{
let {state} = this;
let previous = state.previous;
if(previous)
{
state[previous] = 'Pink';
}
state[name] = 'Red';
state.previous = name;
this.setState(state);
}
render()
{
console.log(this)
return(
<section id={'parent'}>
<ChildContainer
selectMe={() => this.updateChild('first')}
backgroundColor = {this.state.first}
/>
<ChildContainer
selectMe={() => this.updateChild('second')}
backgroundColor = {this.state.second}
/>
<ChildContainer
selectMe={() => this.updateChild('third')}
backgroundColor = {this.state.third}
/>
</section>
)
}
}
class App extends React.Component
{
constructor(props)
{
super(props)
}
render()
{
return(
<section>
<Parent/>
</section>
)
}
}
React.render(<App />, document.getElementById('root'));
You need to track the state of every checkbox, possibly have an array with all currently checked checkboxes.
Then instead of this.state.checkboxState in this.state.checkboxState ? { borderColor: '' } : { borderColor: 'red' } you need to check if current category is in the currently checked categories array.
Hope this helps
I have created a simple React component with a table displaying 10 rows of data per page. The implementation of the pagination works as intended, but I want to be able to highlight the selected page.
In my constructor I have an initial state "active: null", which I then modify in a handleClick function.
constructor(props) {
super(props);
this.state = {
currentPage: 1,
eventsPerPage: 10,
active: null,
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(index) {
this.setState({ currentPage: Number(index.target.id) });
if (this.state.active === index) {
this.setState({ active: null });
} else {
this.setState({ active: index });
}
}
And a function for setting the font-weight to bold.
myStyle(index) {
if (this.state.active === index) {
return 'bold';
}
return '';
}
Here is what I render.
const renderPageNumbers = pageNumbers.map((number, index) => (
<p
style={{ fontWeight: this.myStyle(index) }}
key={number}
id={number}
onClick={index => this.handleClick(index)}
>
{number}
</p>
));
return (
<div id="page-numbers">
{renderPageNumbers}
</div>
);
FYI: It's not the complete code.
I am not quite sure where I go wrong, any help is appreciated :)
pageNumbers.map((number, index) => index is zero based and am sure number starts from 1 so when index === 0 and number === 1, you would have this.myStyle(0) but
this.handleClick(0) will not work because you first #id === 1 not 0
why not just use number for your functions and remove index to safe confusion
You need to bind the context of the class to myStyle function in order to use this inside it.
So, in your constructor you should add it like this:
(see the last line)
constructor(props) {
super(props);
this.state = {
currentPage: 1,
eventsPerPage: 10,
active: null,
};
this.handleClick = this.handleClick.bind(this);
this.myStyle = this.myStyle.bind(this);
}
I am new to React and have been trying to figure out how to control an array of components from a parent component. My job is to create a site where I can add or subtract names to a list, but have gotten stuck on the best way to do it. In this case, I created an array of react components, each with controlled input for title boxes and each with a delete button that would call the parent function's remove function through the prop system. However, I noticed that when doing so, the array in the parent function would remain correct, while the id's of the children components would not change to be reordered, thereby ruining subsequent removals. I am sure I am doing this wrong and would like to find a better and more efficient way of doing this. Thanks!
import React, {Component} from 'react';
import Music from './music'
import axios from 'axios';
var childrenComponents = [];
class Selection {
constructor(){
this.music = '';
this.beginning = 0;
this.the_end = 0;
}
setTitle=(title)=>{
this.music = title;
}
setStart=(start)=>{
this.beginning = start;
}
setEnd=(end)=>{
this.the_end = end;
}
}
class Practice extends React.Component{
constructor(props){
super(props);
this.state = {
number_music: 0,
number: 0,
selections: Array(0).fill(null),
deletions: 0,
}
this.addAnotherSong = this.addAnotherSong.bind(this);
this.removeSong = this.removeSong.bind(this);
this.renderMusicPlayed = this.renderMusicPlayed.bind(this);
}
removeSong(index){
if((this.state.number_music-1) >= 0){
alert(index);
for(var i = 0; i < (this.state.selections.length-1); i++){
console.log(this.state.selections[i].music);
}
childrenComponents.splice(index, 1);
this.setState({selections: this.state.selections.filter((_, i) => i !== index),
number_music: this.state.number_music - 1,
deletions: this.state.deletions += 1});
console.log("========================");
for(var i = 0; i < (this.state.selections.length-1); i++){
console.log(this.state.selections[i].music);
}
console.log("///////////////////////////////////////////////////");
}
}
addAnotherSong(){
this.state.selections.push(new Selection());
var i = this.state.number_music;
childrenComponents.push(
<Music key={i} number={i} subtract={this.removeSong}
Title={this.state.selections[i].music} Start={this.state.selections[i].beginning}
End={this.state.selections[i].the_end} changeTitle={this.state.selections[i].setTitle}
changeStart={this.state.selections[i].changeStart} changeEnd={this.state.selections[i].changeEnd}/>
);
this.setState({ number_music: this.state.number_music += 1, number: this.state.number += 1});
}
renderMusicPlayed(){
return (
<div>
{childrenComponents}
</div>
);
}
render(){
return(
<div>
<button onClick={()=> this.props.practice()}>Log Practice Session</button>
<h1>{this.props.time}</h1>
<form >
Description: <input type="form" placeholder="How did it go?" name="fname"/><br/>
</form>
{this.renderMusicPlayed()}
<button onClick={()=>this.addAnotherSong()}>Add Another Piece</button>
{this.state.number_music}
</div>
);
}
}
export default Practice;
That is the parent.
This is the Child:
import React, {Component} from 'react';
import InputBox from './input';
class Music extends React.Component{
constructor(props){
super(props);
this.state = {
title: null,
start: null,
end: null
}
}
componentWillReceiveProps(props){
this.setState({ title: this.props.Title});
}
render(){
return(
<div>
<InputBox initialValue={this.props.number} cValue={this.props.Title} identity={this.props.number} updateInput={this.props.changeTitle} />
<InputBox initialValue="Starting Measure" cValue={this.props.Start} identity={this.props.number} updateInput={this.props.changeStart} />
<InputBox initialValue="Ending Measure" cValue={this.props.End} identity={this.props.number} updateInput={this.props.changeEnd} />
<button onClick={()=> this.props.subtract(this.props.number)}>Delete</button>
</div>
)
}
}
export default Music;
And this is the grand child so to speak:
import React,{Component} from 'react';
class InputBox extends React.Component{
constructor(props){
super(props);
this.state = { value: this.props.initialValue, text: "" }
this.handleChange = this.handleChange.bind(this);
}
handleChange(event){
this.setState({value: event.target.value});
this.props.updateInput(this.state.value, this.props.identity);
}
render(){
return(
<input type="text" onChange={this.handleChange} value={this.state.cValue}></input>
)
}
}
export default InputBox;
I guess my main question is what is the ideal way for handling this kind of problem.
The reason your IDs are not changing is because you're pushing fully formed components to the array.
Imagine we have 3 components - formatting will be a little weird, but hopefully it illustrates the point:
[ Music: { id: 0 }, Music: { id: 1 }, Music: { id: 2 } ]
When we click the delete button, say on Music with id: 1, we end up with this:
[ Music: { id: 0 }, Music: { id: 2 } ]
We spliced the right Music out, but we now have a wrong index - we never actually changed the Music with id: 2. It would be much easier (in my opinion) to just dynamically construct your Music components in the render function.
Realistically, your childrenComponents array isn't all that useful - the Music components created in it are all created with the index i in mind:
Title={this.state.selections[i].music}
Start={this.state.selections[i].beginning}
End={this.state.selections[i].the_end}
and so on and so forth.
We could simplify this pretty easily, and consolidate all of this into one array.
Imagine we had an array field state.children, which looked something like this:
[
{ title: _____, start: _____, end: ____, ... },
{ title: _____, start: _____, end: ____, ... },
{ title: _____, start: _____, end: ____, ... },
]
This is a lot more clear in a huge way: our data is consolidated in one, singular place, and we aren't tying them together by some arbitrary index. You've done this in a sense with your selections array, but because you are also using childrenComponents, you're double managing what is essentially the same data.
We can pretty easily render it, too, with something along the lines of:
render() {
{
this.state.children.map((child, index) => (
<Music key={index}
number={index}
subtract={this.removeSong}
Title={this.state.children[index].title}
...
/>
);
}
}
That helps us decouple the actual meat of our objects (title, beginning, ending, etc) from their position in the array, which don't really mean anything and are just getting in the way here. That lets us splice up our array however we see fit, and be certain that we're not breaking any relationships between our components and their indexes.