So, i'm trying to add react-select component to my project. I'm using grouped options and trying to have the ability to select multiple options
This is my component code
class QueueFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
options: [
{
label: 'Partner',
options: [
{
value: {
id: 'ABCDSC',
value: 'Partner1'
},
label: 'Partner1'
},
{
value: {
id: 'ABCDSC',
value: 'Partner2'
},
label: 'Partner2'
}
]
},
{
label: 'Study',
options: [
{
value: {
id: 'ABCDSC123',
value: 'Study1'
},
label: 'Study1'
}
]
}
],
selectedFilters: []
};
this.fecthQueueFilters = this.fecthQueueFilters.bind(this);
this.onFilterChange = this.onFilterChange.bind(this);
this.applyFilter = this.applyFilter.bind(this);
}
componentDidMount(prevState, prevProps) {
if (prevProps.queueId !== this.props.queueId) {
this.fetchQueueFilters(this.props.queueId);
}
}
onFilterChange(selectedFilters) {
this.setState({ selectedFilters });
}
fecthQueueFilters(queueId) {
}
applyFilter() {
}
render() {
const groupStyles = {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
};
const groupBadgeStyles = {
backgroundColor: '#EBECF0',
borderRadius: '2em',
color: '#172B4D',
display: 'inline-block',
fontSize: 12,
fontWeight: 'normal',
lineHeight: '1',
minWidth: 1,
padding: '0.16666666666667em 0.5em',
textAlign: 'center',
};
const formatGroupLabel = data => (
<div style={groupStyles}>
<span>{data.label}</span>
<span style={groupBadgeStyles}>{data.options.length}</span>
</div>
);
const Input = (props) => {
if (props.isHidden) {
return <components.Input {...props} />;
}
return (
<div style={{ border: '1px dotted black' }}>
<components.Input {...props} />
</div>
);
};
return (
<Container fluid className="main-header">
<Row>
<Col xs="1">Queue Filters:</Col>
<Col auto>
<Select
options={this.state.options}
isMulti
isClearable
formatGroupLabel={formatGroupLabel}
components={{Input}}
closeMenuOnSelect={false}
value={this.state.selectedFilters}
onChange={this.onFilterChange}
/>
</Col>
<Col xs="1">
<Button type="button" onClick={this.applyFilter} color="success">
<Filter />
</Button>
</Col>
</Row>
</Container>
);
}
}
QueueFilter.propTypes = {
queueId: PropTypes.string
};
export default QueueFilter;
But when I select multiple options, only 1 is shown in the select field
The console shows there's 2 options selected
And, well, there's this warning in the console
If I change the the options values to be simple strings instead of objects
this.state = {
options: [
{
label: 'Partner',
options: [
{
value: 'ABCDSC:Partner1',
label: 'Partner1'
},
{
value: 'ABCDSC:Partner2',
label: 'Partner2'
}
]
},
{
label: 'Study',
options: [
{
value: 'ABCDSC123:Study1',
label: 'Study1'
}
]
}
],
selectedFilters: []
};
Well, it works as expected, but I'd rather have the object values.
Any idea how to achieve this?
You can use the prop getOptionValue
<Select
getOptionValue={option => option.value.value}
Related
Im using react and displaying some labels via the array object of labels. Now, I want to do this dynamically. So if a user clicks a button, the object updates and the user interface should update accordingly as well. The issue here is that I got the array to update after clicking on the button, as evidenced by a console log line that I wrote in the onclick handler. But the user interface does not update accordingly. Just the array shows the values. Here is what the inital array looks like:
const labelsArray = [
{ label: 'Hey There', sublabel1: 'How are you?' },
{
label: 'Greetings', sublabel1: 'Fellows'
},
{ label: 'Awesome', sublabel1: 'Youre doing great', sublabel2: 'cool' }
];
I want to append a warningLabel, and errorLabel to the 2nd object of this array. So since arrays are 0 indexed, I did the following in the onclick handler:
const appendLabel = async () => {
labelsArray[1].warningLabel = "Hello";
labelsArray[1].errorLabel = "Hello";
console.log(labelsArray)
};
The array updates, but not the user interface. Which is really weird.
Also, this is not related to react state mutation, which I know because of my research of this topic when I was trying to figure it out. So just to be clear, its not about state mutation, which might have someone put this as a duplicate question. Its more of a react/object structure question. But I could be wrong! Anyways, any help is appreciated. Thanks!
Here is my whole component for reference
import React, { useState } from 'react';
import { Button, Typography } from '#material-ui/core';
import { withStyles } from '#material-ui/core/styles/';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step';
import StepLabel from '#material-ui/core/StepLabel';
import StepConnector from '#material-ui/core/StepConnector';
import PropTypes from 'prop-types';
const styles = theme => ({
stepLabelRoot: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
},
checklistHeader: {
fontWeight: 'bold',
marginTop: '80px'
},
connectorIcon: {
color: theme.palette.text.secondary
},
stepper: {
background: 'none',
fontWeight: 'bold'
},
checkListImageContainer: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center'
},
connector: {
},
activeConnector: {
border: 'solid 1px #6fef71'
},
stepIcon: {
height: '35px',
width: '35px',
'&:hover': {
backgroundColor: 'rgba(134, 141, 150, 0.37)',
borderRadius: '50%'
},
},
activeStepIcon: {
backgroundColor: 'yellow'
},
label: {
fontWeight: 'bold',
display: 'flex',
fontSize: '15px'
},
sublabel: {
fontWeight: 'normal',
fontSize: '13px'
},
errorLabel: {
color: 'red'
},
warningLabel: {
color: 'yellow'
},
step: {
'&$completed': {
color: 'lightgreen'
},
'&$active': {
color: 'pink'
},
'&$disabled': {
color: 'red'
},
},
alternativeLabel: {},
active: {
}, // needed so that the &$active tag works
completed: {
},
disabled: {
},
labelContainer: {
'&$alternativeLabel': {
marginTop: 0
},
},
});
const labelsArray = [
{ label: 'Random text?', sublabel1: 'Lorem Ipsum' },
{
label: 'Another random text', sublabel1: 'Hello World'
},
{ label: 'Cool', sublabel1: 'cool', sublabel2: 'ayo' }
];
const Checklist = ({ classes,activeStep }) => {
return (
<React.Fragment>
<Stepper alternativeLabel activeStep={2} connector={<StepConnector />} className={classes.stepper}>
{labelsArray.map(label => (
<Step key={label} completed>
<StepLabel active
completed
StepIconProps={{
classes: {
root: classes.step,
completed: classes.completed,
active: classes.active,
disabled: classes.disabled
}
}}>
<div className={classes.stepLabelRoot}>
<span className={classes.label}>
{label.label}
</span>
<span className={classes.sublabel}>
{label.sublabel1}
</span>
<span className={classes.sublabel}>
{label.sublabel2}
</span>
<span className={classes.sublabel}>
{label.sublabel3}
</span>
<span className={classes.errorLabel}>
{label.errorLabel && <img src="/static/images/lock-material.png" alt="img" style={{ height: '15px', width: '15px' }} />}
{label.errorLabel}
</span>
<span className={classes.warningLabel}>
{label.warningLabel && <img src="/static/images/warning-sign.png" alt="img" style={{ height: '15px', width: '15px' }} />}
{label.warningLabel}
</span>
</div>
</StepLabel>
</Step>
))}
</Stepper>
<Button onClick={() => appendLabel()}>Hello</Button>
</React.Fragment>
);
};
Checklist.defaultProps = {
activeStep: -1
};
Checklist.propTypes = {
classes: PropTypes.object.isRequired,
form: PropTypes.bool.isRequired,
activeStep: PropTypes.number
};
export default withStyles(styles, { withTheme: true })(Checklist);
You need to set the labelsArray in the state and update it accordingly in order to re-render the component when the user clicks the button
Edited:
A way of doing that with a state would be:
const LABELS =[
{ label: 'Hey There', sublabel1: 'How are you?' },
{ label: 'Greetings', sublabel1: 'Fellows' },
{ label: 'Awesome', sublabel1: 'Youre doing great', sublabel2: 'cool' }
];
const [labelsArray, setLabelsArray] = useState(LABELS);
const appendLabel = () => {
let editedLabels = [...labelsArray];
editedLabels[1].warningLabel = "Hello";
editedLabels[1].errorLabel = "Hello";
setLabelsArray(editedLabels);
};
In my example I present an accordion separately and a table separately and I wanted to know how I present the table within the accordion.
this is the accordion that i want put inside it the table as in the example below :
import React, { Component } from "react";
import { Container, Header, Content, Accordion } from "native-base";
const dataArray = [
{ title: "First Element", content: "**I WANT PUT HERE THE TABLE**" },
{ title: "Second Element", content: "BO" },
{ title: "Third Element", content: "MO" }
];
export default class AccordionHeaderContentStyleExample extends Component {
render() {
return (
<Container>
<Header />
<Content padder>
<Accordion
dataArray={dataArray}
headerStyle={{ backgroundColor: "#b7daf8" }}
contentStyle={{ backgroundColor: "#ddecf8" }}
/>
</Content>
</Container>
);
}
}
this is the table that i want put inside the "content" of the "First Element" accordion above :
import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import { Table, Row, Rows } from 'react-native-table-component';
export default class ExampleOne extends Component {
constructor(props) {
super(props);
this.state = {
tableHead: ['Head', 'Head2', 'Head3', 'Head4'],
tableData: [
['1', '2', '3', '4'],
['a', 'b', 'c', 'd'],
['1', '2', '3', '456\n789'],
['a', 'b', 'c', 'd']
]
}
}
render() {
const state = this.state;
return (
<View style={styles.container}>
<Table borderStyle={{borderWidth: 2, borderColor: '#c8e1ff'}}>
<Row data={state.tableHead} style={styles.head} textStyle={styles.text}/>
<Rows data={state.tableData} textStyle={styles.text}/>
</Table>
</View>
)
}
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16, paddingTop: 30, backgroundColor: '#fff' },
head: { height: 40, backgroundColor: '#f1f8ff' },
text: { margin: 6 }
});
Try this might help
import ExampleOne from "../components/ExampleOne";
// ExampleOne is the component that should be rendered inside content of dataArray
renderExampleOne = () => {
return <ExampleOne />;
};
const dataArray = [
{ title: "First Element", content: this.renderExampleOne() },
{ title: "Second Element", content: "BO" },
{ title: "Third Element", content: "MO" }
];
renderContent(item: ArrayContent) {
return item.content;
}
<Accordion
dataArray={dataArray}
headerStyle={{ backgroundColor: "#b7daf8" }}
contentStyle={{ backgroundColor: "#ddecf8" }}
renderContent={this.renderContent}
/>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
import React from 'react';
import {
SafeAreaView,
TouchableOpacity,
FlatList,
StyleSheet,
Text,
} from 'react-native';
const DATA = [
{
id: '1',
title: 'First Item',
},
{
id: '2',
title: 'Second Item',
},
{
id: '3',
title: 'Third Item',
},
{
id: '4',
title: 'Fourth Item',
},
{
id: '5',
title: 'Fifth Item',
},
{
id: '6',
title: 'Sixth Item',
},
{
id: '7',
title: 'Seventh Item',
},
];
function Item({id, title, selected, onSelect}) {
return (
<TouchableOpacity
onPress={() => onSelect(id)}
style={[styles.item, {backgroundColor: selected ? '#1EF09D' : 'white'}]}
>
<Text style={styles.title}>{title}</Text>
</TouchableOpacity>
);
}
export default function App() {
const [selected, setSelected] = React.useState(new Map());
const onSelect = React.useCallback(
id => {
const newSelected = new Map();
// newSelected.set(id, !selected.get(id));
newSelected.set(id, !selected.get(id));
setSelected(newSelected);
},
// [selected],
);
return (
<SafeAreaView style={styles.container}>
<FlatList
horizontal
initialScrollIndex={DATA.length - 1}
data={DATA}
renderItem={({item}) => (
<Item
id={item.id}
title={item.title}
selected={!!selected.get(item.id)} **im facing the issue at this point after converting this into a class file**
onSelect={onSelect}
/>
)}
keyExtractor={item => item.id}
extraData={selected}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
item: {
backgroundColor: 'red',
padding: 20,
marginVertical: 8,
marginHorizontal: 10,
width: '50%',
height: '20%',
flex: 2,
borderWidth: 2,
borderRadius: 15,
borderColor: '#39FF33',
},
title: {
fontSize: 14,
},
});
How can I convert this code in a class file. This code is in running state you can run it on snack.expo.io or on your own pc. I'm facing minirect issue and much more when I tried to convert this code.
I'm also facing hooks error when I tried to convert the code.
this is native-app which converted into class.
import React, { Component } from 'react';
import {
SafeAreaView,
TouchableOpacity,
FlatList,
StyleSheet,
Text,
} from 'react-native';
const DATA = [
{
id: '1',
title: 'First Item',
},
{
id: '2',
title: 'Second Item',
},
{
id: '3',
title: 'Third Item',
},
{
id: '4',
title: 'Fourth Item',
},
{
id: '5',
title: 'Fifth Item',
},
{
id: '6',
title: 'Sixth Item',
},
{
id: '7',
title: 'Seventh Item',
},
];
class Item extends Component {
constructor(props) {
super(props);
}
render() {
const {id, title, selected, onSelect} = this.props;
return (
<TouchableOpacity
onPress={() => onSelect(id)}
style={[styles.item, {backgroundColor: selected ? '#1EF09D' : 'white'}]}
>
<Text style={styles.title}>{title}</Text>
</TouchableOpacity>
);
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
selected: new Map(),
};
}
onSelect = id => {
const { selected } = this.state;
var newSelected = new Map();
newSelected.set(id, !selected.get(id));
this.setState({selected: newSelected});
};
render() {
const { selected } = this.state;
return (
<SafeAreaView style={styles.container}>
<FlatList
horizontal
initialScrollIndex={DATA.length - 1}
data={DATA}
renderItem={({item}) => (
<Item
id={item.id}
title={item.title}
selected={!!selected.get(item.id)}
onSelect={this.onSelect}
/>
)}
keyExtractor={item => item.id}
extraData={selected}
/>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
item: {
backgroundColor: 'red',
padding: 20,
marginVertical: 8,
marginHorizontal: 10,
width: '50%',
height: '20%',
flex: 2,
borderWidth: 2,
borderRadius: 15,
borderColor: '#39FF33',
},
title: {
fontSize: 14,
},
});
export default App;
expo snack link
if you want to initialise the status of the selected map, try like this.
constructor(props) {
super(props);
this.state = {
selected: new Map([[DATA[DATA.length - 1].id, true]]), // last item selected
};
}
I use React Native to create a group of checkbox that allow users to choose the option they may like. But I am having problem that all the checkbox is checked at the same time and unable to get it's value. For checkboxes I use this package react-native-circle-checkbox Here is my code:
class Answer extends Component {
constructor(prop) {
super(prop);
this.state = {
checked: false,
checkboxValue: [
{
label: "Option1",
value: 1
},
{
label: "Option2",
value: 2
},
{
label: "Option3",
value: 3
},
{
label: "Option4",
value: 4
},
{
label: "Option5",
value: 5
}
]
};
}
CheckMe = (value, index) => {
this.setState({
checked: !this.state.checked
});
console.log(index);
};
render() {
const options = this.state.checkboxValue;
return (
<View style={styles.mainContainer}>
<View style={styles.questionWrapper}>
<View style={styles.questionGroup}>
<View style={{ flexDirection: "row" }}>
{options.map(option => {
return (
<CircleCheckBox
key={option.value}
checked={this.state.checked}
onToggle={(value, index) => this.CheckMe()}
labelPosition={LABEL_POSITION.RIGHT}
label={option.label}
styleLabel={{ fontSize: 17 }}
/>
);
})}
</View>
</View>
</View>
</View>
);
}
}
I want when a user check on a checkbox only that checkbox is checked and get it's value.
How can I do that?
To make sure that only one option is selected it would be more natural to use radio-buttons. But you can achieve that with checkboxes too:
class Answer extends Component {
constructor(prop) {
super(prop);
this.state = {
selectedCheckbox: {}, // keep selected item in state, by default its empty meaning nothing is selected
checkboxValue: [
{
label: "Option1",
value: 1
},
{
label: "Option2",
value: 2
},
{
label: "Option3",
value: 3
},
{
label: "Option4",
value: 4
},
{
label: "Option5",
value: 5
}
]
};
}
CheckMe = selectedCheckbox => {
this.setState({ selectedCheckbox }); // update selected item
};
render() {
const { checkboxValue, selectedCheckbox } = this.state;
return (
<View style={styles.mainContainer}>
<View style={styles.questionWrapper}>
<View style={styles.questionGroup}>
<View style={{ flexDirection: "row" }}>
{checkboxValue.map((option, indexInArray) => {
return (
<CircleCheckBox
key={option.value}
checked={option.value === selectedCheckbox.value} // for current element
onToggle={(value, index) => this.CheckMe(option)} // pass index of toggled element
labelPosition={LABEL_POSITION.RIGHT}
label={option.label}
styleLabel={{ fontSize: 17 }}
/>
);
})}
</View>
</View>
</View>
</View>
);
}
}
Trying to figure out how to change the styling on just the first and last button. How do I tell the button which one is which? Beginner in JS and React/React Native trying to find my way. Currently coming out with no rounded buttons on either end. The Button element in the child is my own wrapper on TouchableOpacity and only accepts an object for the buttonStyles. Any help appreciated.
Parent component:
export class Rating extends React.Component {
ratings = [
{ text: '1' },
{ text: '2' },
{ text: '3' },
{ text: '4' },
{ text: '5' },
];
onButtonPress = (e) => {
console.log(e.target.value);
};
render() {
return (
<View>
{this.ratings.length && (
this.ratings.map((rating, index) => (
<View key={index}>
<RatingButton rating={rating} onButtonPress={this.onButtonPress} />
</View>
))
)
}
</View>
);
}
}
Child component:
const buttonStyles = () => {
const allButtons = {
backgroundColor: sc.colors.white.white,
borderWidth: 1.5,
borderColor: sc.colors.blue.darker1,
padding: sc.padding.lg,
};
const startButton = {
borderTopLeftRadius: sc.borderRadius.sm,
borderBottomLeftRadius: sc.borderRadius.sm,
borderRightWidth: 0.75,
...allButtons,
};
const endButton = {
borderTopRightRadius: sc.borderRadius.sm,
borderBottomRightRadius: sc.borderRadius.sm,
borderLeftWidth: 0.75,
...allButtons,
};
return StyleSheet.create({
allButtons,
startButton,
endButton,
buttonText: {
color: sc.colors.blue.darker1,
fontSize: sc.font.size.largeContent,
},
});
};
class RatingButton extends React.Component {
render() {
const { onButtonPress, rating } = this.props;
const styles = buttonStyles();
return (
<Button
buttonStyles={styles.allButtons}
textStyles={styles.buttonText}
onPress={onButtonPress}
>
{rating.text}
</Button>
);
}
}
Inside of your ratings variable, you could store another attribute for style like so:
ratings = [
{ text: '1', style: {backgroundColor:'red'} },
{ text: '2' },
{ text: '3' },
{ text: '4' },
{ text: '5', backgroundColor: 'yellow' },
];
And then inside of <RatingButton/> you can add the style to the element
<Button
buttonStyles={styles.allButtons}
textStyles={styles.buttonText}
onPress={onButtonPress}
style={rating.style}
>
{rating.text}
</Button>
Note: You could also pass a class through the rating variable.
ratings = [
{ text: '1', buttonStyle: 'startButton' },
{ text: '2' },
{ text: '3' },
{ text: '4' },
{ text: '5', buttonStyle: 'endButton' },
];
and set your style like this:
<Button
buttonStyles={ratings.buttonStyle?styles[rating.buttonStyle]:styles.allButtons}
textStyles={styles.buttonText}
onPress={onButtonPress}
style={rating.style}
>
{rating.text}
</Button>