onChange is not triggering in react js - javascript

I use the dropdown in react js app but onChange is not triggering
my code is
import React from "react";
import PropTypes from "prop-types";
import Dropdown from 'react-dropdown';
const options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two', className: 'myOptionClassName' },
];
class WebDashboardPage extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
quan = (event)=> {
console.log("Option selected:");
this.setState({ value: event.target.value });
};
render() {
return(
<b><Dropdown className="dropdownCss" options={options} onChange={e =>
this.quan(e.target.value)} /></b>
);
}
when I click the items in dropdown it shows the error
"TypeError: Cannot read property 'quan' of undefined"
I'm a newbie to react
thanks in advance

There is no issue with the react-dropdown library. Here is the code sandbox that I've set up and corrected OP's code. It works.
import React from "react";
import Dropdown from "react-dropdown";
import "react-dropdown/style.css";
const options = [
{ value: "one", label: "One" },
{ value: "two", label: "Two", className: "myOptionClassName" }
];
const defaultOption = options[0];
class WebDashboardPage extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedValue: ""
};
}
quan = value => {
this.setState({ selectedValue: value });
};
render() {
return (
<Dropdown options={options} value={defaultOption} onChange={this.quan} />
);
}
}
export default WebDashboardPage;

You should just do it this way:
<Dropdown className="dropdownCss" options={options} onChange={this.quan} />
Try this:
class WebDashboardPage extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' }
this.quan = this.quan.bind(this);
}
quan(event) {
console.log("Option selected:");
this.setState({ value: event.target.value });
};
render() {
return(
<div><Dropdown className="dropdownCss" options={options} onChange={this.quan} /></div>
);
}

It seems the issue is with the react-dropdown component itself. You'll need to file an issue there.
react-dropdown component might not be using this.props.onChange somewhere or might be using problematically.
Or, it's probably, the component requires value state which have not defined?
this.state = {
value: ''
}
And was causing the issue?

The dropdown dependency you are using does not fire onChange with event as argument instead it fires onChange with the selected option.Try changing
onChange={e =>
this.quan(e.target.value)}
to
onChange={this.quan}
and change quan to
quan = (selectedOption)=> {
console.log("Option selected:"+selectedOption.value);
this.setState({ value: selectedOption.value });
};
I have tried it on my machine and it wroks perfectly. Also next important thing is don't put options the way you are doing instead put it on state. my final code is
class WebDashboardPage extends Component {
constructor(props) {
super(props);
const options = [
{
value: 'one',
label: 'One'
}, {
value: 'two',
label: 'Two',
className: 'myOptionClassName'
}
];
this.state = {options}
}
quan = (selectedOption) => {
console.log("Option selected:" + selectedOption.value);
this.setState({value: selectedOption.value});
};
render() {
return (<b><Dropdown className="dropdownCss" options={this.state.options} onChange={this.quan}/></b>);
}
}

I only did a little refactoring to the code. The main change is in how Dropdown handles change. When you pass in a function to handleChange, Dropdown calls the function internally and passes the selected object to it, so you all you needed to do was create a handler method that has one parameter which you'll use to update the state. I also set an initial state for value. Here's is a demo https://codesandbox.io/s/4qz7n0okyw
import React, { Component, Fragment } from "react";
import ReactDOM from "react-dom";
import Dropdown from "react-dropdown";
const options = [
{ value: "one", label: "One" },
{ value: "two", label: "Two", className: "myOptionClassName" }
];
class WebDashboardPage extends Component {
state = {
value: {}
};
quan = value => {
console.log("Option selected:", value);
this.setState({ value });
};
render() {
return (
<Fragment>
<Dropdown
className="dropdownCss"
options={options}
onChange={this.quan}
/>
</Fragment>
);
}
}
export default WebDashboardPage;

Change to
onChange={this.quan}, also in the initial state you should state your this.state.value
this.state = {
value: ''
}
also try to learn it on html element, not on jsx

Related

React Rails Passing props to React Select

I'm trying to pass props from my Rails database to a React Select component using React rails, but the text is appearing invisible within the select option.
View:
= react_component('SelectSearch', options: Course.all.as_json(only: [:title]))
React select component:
import React from 'react';
import Select from 'react-select';
class SelectSearch extends React.Component {
constructor(props) {
super(props)
}
state = {
selectedOption: null,
};
handleChange = selectedOption => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
};
render() {
const { selectedOption } = this.state;
return (
<Select
value={selectedOption}
onChange={this.handleChange}
options={this.props.options}
/>
);
}
}
export default SelectSearch;
When something in the select is clicked, it console logs, for example:
Option selected: {title: "English"}
But opening the select, its completely blank. There is obviously an option there that can be clicked, but nothing is displayed. Likewise for searching, no options are displayed.
I know this is because I'm passing the props incorrectly, or handling the data incorrectly, I don't want {title: "English"} I just want English but not sure how to filter this correctly.
See the react-select example:
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
]
const MyComponent = () => (
<Select options={options} />
)
Your options contains unneeded 'title' attribute and not contains 'value' and 'label'. Fix it.
Took me a while to figure it out, but got this working:
= react_component('SelectSearch', data: Course.all.as_json(only: [:title]))
import React from 'react';
import Select from 'react-select';
class SelectSearch extends React.Component {
constructor(props) {
super(props);
}
state = {
selectedOption: null,
};
handleChange = selectedOption => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
};
render() {
const { selectedOption } = this.state;
return (
<Select
value={selectedOption}
onChange={this.handleChange}
options={this.props.data}
getOptionLabel={(option) => option.title}
getOptionValue={(option) => option.title}
/>
);
}
}
export default SelectSearch;
React-select expects a value and a label and this seems to be the easiest way to pass it.

Very simple state change of specific array item in React

I'm trying to change the state of only one specific array item from the reviews array. How can this be done? This code doesn't seem to work:
this.setState({
reviews[2].current: true
});
Here's the full code:
import React, { Component } from "react";
import { render } from "react-dom";
const reviewsInit = [
{
name: "Peter Lahm",
current: null
},
{
name: "Simon Arnold",
current: null
},
{
name: "Claire Pullen",
current: null
}
];
class App extends Component {
constructor() {
super();
this.state = {
name: "React",
reviews: reviewsInit
};
}
change = () => {
this.setState({
reviews[2].current: true
});
};
render() {
return (
<div>
{console.log(this.state.reviews[2].current)}
<button onClick={this.change}>click me</button>
</div>
);
}
}
render(<App />, document.getElementById("root"));
Demo: https://stackblitz.com/edit/react-tbryf5
As you can probably tell I'm new to react! Thanks for any help here
For some context, React detects state change when reference of the state object changes. It does not track deep changes happening in array or the object.
Solution
We need to make another variable with same data (mostly destructuring). Change the value needed. And assign that to state again.
For Object
this.setState({...oldState, keyToChange: 'newValue'});
For Array
const temp = [...oldState];
temp[index] = 'newValue';
this.setState(temp);
Hope it helps.
It's common for an Array state to copy first then update one of its value
change = () => {
const result = [...this.state.reviews];
result[2].current = true;
this.setState({reviews: result});
};
import React, { Component } from "react";
import { render } from "react-dom";
const reviewsInit = [
{
name: "Peter Lahm",
current: null,
},
{
name: "Simon Arnold",
current: null,
},
{
name: "Claire Pullen",
current: null,
},
];
class App extends Component {
constructor() {
super();
this.state = {
name: "React",
reviews: reviewsInit,
};
}
change = () => {
const prevState = [...this.state.reviews];
prevState[2].current = true;
this.setState({
reviews: prevState,
});
};
render() {
return (
<div>
{console.log(this.state.reviews[2].current)}
<button onClick={this.change}>click me</button>
</div>
);
}
}
render(<App />, document.getElementById("root"));

How to pass dropdown value to state/get request? React

Hey react newbie here!
I am trying to use a select/option value from a drop down to be used in a get request { selectedOption }.
I am unsure how to pass the selectedOption into my main state/component to be used in the get request.
Can anybody point me in the right direction please? <3
Constructor/state:
public constructor(props) {
super(props);
this.state = {
documents: [],
selectedOption: null
};
}
Get request:
public getDocuments() {
axios
.get("https://bpk.sharepoint.com/_api/search/query?querytext='Colour:" + this.state.selectedOption + "'&trimduplicates=true&rowsperpage=100&rowlimit=1000",
{ params:{},
headers: { 'accept': 'application/json;odata=verbose' }
})
....
}
Render:
public render(): React.ReactElement<IKimProps> {
let { documents, selectedOption } = this.state;
return (
<div className={ styles.kim }>
<Selecter></Selecter>
<br/><br/>
{this.renderDocuments()}
</div>
);
}
}
Selector Component (Not in main app, in the main app its a component called <.Selecter.><./Selecter.>):
import React from 'react';
import Select from 'react-select';
const options = [
{ value: 'red', label: 'red' },
{ value: 'blue', label: 'blue' },
{ value: 'green', label: 'green' }
];
class Selecter extends React.Component {
state = {
selectedOption: null,
};
handleChange = selectedOption => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
};
render() {
const { selectedOption } = this.state;
return (
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
/>
);
}
}
export default Selecter;
The issue here is that you're setting the state of Selecter, but never bubbling that up to the parent class. The general way you do this is via a prop passed to Selecter that sets the parent state:
Parent.js:
...
public setSelectedOption(selectedOption){
this.setState({ selectedOption: selectedOption });
// or this.setState({ selectedOption }); (whichever works)
}
public render(): React.ReactElement<IKimProps> {
...
<Selecter onChange={this.setSelectedOption.bind(this)}></Selecter>
}
Then, handle the passed function in Selecter.js:
class Selecter extends React.Component {
...
handleChange = selectedOption => {
this.setState({ selectedOption });
if(this.props.onChange){
this.props.onChange(selectedOption);
}
};
}

Get consolidated data from all the child components in the form of an object inside a parent component : React JS

I am implementing a setting page for an application. For each setting I have implemented a slider that has enabled(green) or disabled(red) state. But parent's settings is read only and is calculated based on the values of its children.
Parent's setting is derived as follows: If all children are red, parent stays red ; If all are green parent stays green; If at-least one of child is green then parent stays grey(Pending).
These settings are grouped something like this:
Parent Feature 1 : (read-only-toggle)
Setting 1 (Toggle)
Setting 2 (Toggle)
Parent Feature 2: (read-only-toggle)
Setting 1 (Toggle)
Setting 2 (Toggle)
And in the end there is also a button, that gives me a consolidated values of all parent and children. But so far I was able to do only with one parent and 2 children.
Can someone help with an approach of getting consolidated values of all the settings in one place(Like a super parent component where all these settings are configured).
For this , I am using react-multi-toggle for this toggle switch.
Help would be really appreciated.
Code Sandbox: https://codesandbox.io/s/react-multi-toggle-solution-perfect-v9bi5
App
import React from "react";
import ChildSwitch from "./ChildSwitch";
import ParentSwitch from "./ParentSwitch";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
parentVal: "disabled",
switch1Val: "enabled",
switch2Val: "disabled"
};
}
componentDidMount() {
this.setParentSwitchValue();
}
onGetChildSwitchValues = () => {
console.log(this.state);
};
setChildSwitchValue = (whichSwitch, selected) => {
this.setState(
prevState => ({ ...prevState, [whichSwitch]: selected }),
this.setParentSwitchValue
);
};
setParentSwitchValue = () => {
const { switch1Val, switch2Val } = this.state;
const switchStates = [switch1Val, switch2Val];
let parent = "pending";
if (switchStates.every(val => val === "enabled")) {
parent = "enabled";
}
if (switchStates.every(val => val === "disabled")) {
parent = "disabled";
}
this.setState(prevState => ({ ...prevState, parentVal: parent }));
};
render() {
const { parentVal, switch1Val, switch2Val } = this.state;
return (
<>
<div className="boxed">
Parent Setting 1 :{" "}
<ParentSwitch
parentSwitch={parentVal}
onSelect={this.setParentSwitchValue}
/>
Setting 1:
<ChildSwitch
switchName={"switch1Val"}
selected={switch1Val}
onSelect={this.setChildSwitchValue}
/>
Setting 2:
<ChildSwitch
switchName={"switch2Val"}
selected={switch2Val}
onSelect={this.setChildSwitchValue}
/>
</div>
<button onClick={this.onGetChildSwitchValues}>Get All Values</button>
</>
);
}
}
ChildSetting
import MultiToggle from "react-multi-toggle";
import React from "react";
export default class ChildSwitch extends React.Component {
constructor(props) {
super(props);
this.state = {
options: [
{
displayName: "Disabled",
value: "disabled"
},
{
displayName: "Enabled",
value: "enabled"
}
]
};
}
onSelectOption = selected => {
this.props.onSelect(this.props.switchName, selected);
};
render() {
const { options } = this.state;
const { selected } = this.props;
return (
<MultiToggle
options={options}
selectedOption={selected}
onSelectOption={this.onSelectOption}
/>
);
}
}
Parent Setting
import MultiToggle from "react-multi-toggle";
import React from "react";
import "react-multi-toggle/style.css";
export default class ParentSwitch extends React.Component {
constructor(props) {
super(props);
this.state = {
options: [
{
displayName: "Disabled",
value: "disabled"
},
{
displayName: "Pending",
value: "pending"
},
{
displayName: "Enabled",
value: "enabled"
}
]
};
}
render() {
const { options } = this.state;
return (
<MultiToggle
options={options}
selectedOption={this.props.parentSwitch}
onSelectOption={() => {}}
/>
);
}
}
I will suggest that you group your child and parent under one component. Let say we name it Settings. Then, we create another component that will render a list of Settings and a button. This last component will hold the values of all Settings. Finally, each time the value of a Setting Component Change, we update the list. Checkout a sample working app here.
App Component
export default class App extends PureComponent {
state = {};
onSettingChange = (settingId, setting) => {
this.setState(prevState => ({
...prevState,
[settingId]: setting
}));
};
onGetSettingValues = () => {
console.log(this.state);
};
render() {
return (
<Fragment>
<Setting id="setting1" onChange={this.onSettingChange} />
<Setting id="setting2" onChange={this.onSettingChange} />
<button onClick={this.onGetSettingValues}>Get All Values</button>
</Fragment>
);
}
}
Setting Component
import React, { PureComponent, Fragment } from "react";
import ChildSwitch from "./ChildSwitch";
import ParentSwitch from "./ParentSwitch";
export default class Setting extends PureComponent {
state = {
parentVal: "disabled",
switch1Val: "enabled",
switch2Val: "disabled"
};
componentDidMount() {
this.setParentSwitchValue();
}
setChildSwitchValue = (whichSwitch, selected) => {
this.setState(
prevState => ({ ...prevState, [whichSwitch]: selected }),
this.setParentSwitchValue
);
};
handleChange = () => {
const { id, onChange } = this.props;
onChange(id, this.state);
};
setParentSwitchValue = () => {
const { switch1Val, switch2Val } = this.state;
const switchStates = [switch1Val, switch2Val];
let parent = "pending";
if (switchStates.every(val => val === "enabled")) {
parent = "enabled";
}
if (switchStates.every(val => val === "disabled")) {
parent = "disabled";
}
this.setState(
prevState => ({ ...prevState, parentVal: parent }),
this.handleChange
);
};
render() {
const { parentVal, switch1Val, switch2Val } = this.state;
return (
<Fragment>
<div className="boxed">
Parent Setting 1
<ParentSwitch
parentSwitch={parentVal}
onSelect={this.setParentSwitchValue}
/>
Setting 1:
<ChildSwitch
switchName={"switch1Val"}
selected={switch1Val}
onSelect={this.setChildSwitchValue}
/>
Setting 2:
<ChildSwitch
switchName={"switch2Val"}
selected={switch2Val}
onSelect={this.setChildSwitchValue}
/>
</div>
</Fragment>
);
}
}
Put all your states into a single context hook.
const SettingsContext = createContext({state1, state2/* all your states in here*/);
You'll then wrap the whole thing into this context as such:
<SettingsContext.Provider>
<App/>
</SettingsContext.Provider>
Now you can access the state in any of the children, parents etc. I suggest however not storing things like "disabled", "enabled" as strings, but rather store states as { enabled: true, pending: false}

How to get the selected value using material-dropdown?

Following their example I am trying to get the selected value to dispatch it after that to my action but can't find any way to get it. Any help?
import React, { Component } from 'react';
import { Dropdown } from 'react-native-material-dropdown';
class Example extends Component {
constructor(props) {
super(props)
this.state = {
category: undefined,
}
}
onPost = () => {
var { category } = this.state;
console.log(category) // Undefined
}
render() {
let category = [{
value: 'Banana',
}, {
value: 'Mango',
}, {
value: 'Pear',
}];
return (
<Dropdown
label='Favorite Fruit'
data={category}
/>
<TouchableOpacity onPress={this.onPost}>
<FontAwesome name="check" size={25} color="white" />
</TouchableOpacity>
);
}
}
You can use onChangeText method to get the currently selected value. You can also send it via props to a handler method and use it as your app needs.
Example:
render() {
(...)
<Dropdown
label='Favorite Fruit'
data={category}
onChangeText(value => this.onChangeHandler(value)}
/>
(...)
}
const onChangeHandler = (value) => {
console.log(`Selected value: ${value}`);
}
Hope it helps

Categories

Resources