How to use onChange method in semantic react dropdown - javascript

Can someone help me out how to use onChange in dropdown (Semantic UI React). I am reading the docs, but still, I don't get it. It does have onChange props.
onChange(event: SyntheticEvent, data: object)
How do I use it? Like, I have method dropdownmethod().
edit - implemented the suggestion, but it didn't work. I think in your suggestion, you didn't bind the function. But, I bind the function.
onChangeFollower(event,data){
console.log("on change follower",data.text)
}
render() {
console.log("this.props",this.props)
var onChangeFollower = this.onChangeFollower.bind(this)
return (
<div>
<h2>project settings are here</h2>
<h2>Add new Member</h2>
<Dropdown onChange={onChangeFollower}
placeholder='Select Member'
fluid search selection options={arr} />
<h2>List of members</h2>
{lr}
</div>

As stated in the docs, you just need to pass a reference of your method and then you will get 2 parameters:
The native event
The object of the option selected
Here is a running example
Here is a code snippet (it uses a CDN but throws some debug warnings, so ignore them)
const { Dropdown } = semanticUIReact;
const languageOptions = [
{ key: 'eng', text: 'English', value: 'eng' },
{ key: 'spn', text: 'Spanish', value: 'spn' },
{ key: 'rus', text: 'Russian', value: 'Russian' },
]
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
searchQuery: '',
selected: null
}
}
onChange = (e, data) => {
console.log(data.value);
this.setState({ selected: data.value });
}
onSearchChange = (e, data) => {
console.log(data.searchQuery);
this.setState({ searchQuery: data.searchQuery });
}
render() {
const { searchQuery, selected } = this.state;
return (
<div>
<Dropdown
button
className='icon'
fluid
labeled
icon='world'
options={languageOptions}
search
text={searchQuery}
searchQuery={searchQuery}
value={selected}
onChange={this.onChange}
onSearchChange={this.onSearchChange}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.9/semantic.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/semantic-ui-react#0.77.1/dist/umd/semantic-ui-react.min.js"></script>
<div id="root"></div>
Edit
As a followup to your comment.
I checked example. Even there when i type something, it doesnt show me
anything in console
You are not talking about onChange of the select you are talking about when the search input has changed.
You can use onSearchChange with same parameters. (I've updated the example)

I have implemented as below
React hooks function is as below , if you prefer you can pass handleOnChange as a prop as well
const RenderDropdown = ({optionsArray}) => {
const handleOnChange = (e, data) => {
console.log(data.value);
}
return (
<Dropdown
placeholder='Please select'
fluid
selection
options={optionsArray}
onChange={handleOnChange}
/>
);
}
options array as below
const optionsArray = [
{
key: 'male',
text: 'Male',
value: 'male',
image: { avatar: true, src: 'https://semantic-ui.com/images/avatar/small/elliot.jpg' },
},
{
key: 'female',
text: 'Female',
value: 'female',
image: { avatar: true, src: 'https://semantic-ui.com/images/avatar/small/stevie.jpg' },
}
]

use onChange event to detect the changes in the dropdown list
onSearchChange={(e, v) => {
changeMethod(e, v)
}}
use onSearchChange event to detect the search input
onSearchChange={(e, v) => {
searchMethod(e, v)
}}
and you have to define searchMethod and changeMethod as consts in the top of your page.

Below is the working code of your's:
onChangeFollower(event, data){
console.log("on change follower",data.text)
}
render() {
console.log("this.props",this.props)
return (
<div>
<h2>project settings are here</h2>
<h2>Add new Member</h2>
<Dropdown onChange={this.onChangeFollower}
placeholder='Select Member'
fluid search selection options={arr} />
<h2>List of members</h2>
{lr}
</div>
)
}

Related

React JS Filter Methods: Hiding table columns using array filters and state

This is the code I am trying to rebuild using functional component, but my arrays do not behave correctly.
EXPECTED RESULT: https://stackblitz.com/edit/antd-showhidecolumns
My forked functional component version:
MY WORK https://stackblitz.com/edit/antd-showhidecolumns-rdyc8h
Main issue here is I am not able to show/hide column cells, I am not sure why my array is different when I use the same method as the original code.
My code:
const onChange = (e) => {
let { checkedColumns } = colmenu;
if (e.target.checked) {
checkedColumns = checkedColumns.filter((id) => {
return id !== e.target.id;
});
console.log('if checked columns is', checkedColumns);
} else if (!e.target.checked) {
checkedColumns.push(e.target.id);
console.log('elseif checked columns', checkedColumns);
}
const filtered = checkedColumns.filter((el) => {
return el.dataIndex !== checkedColumns.el;
});
console.log('filtered items', filtered);
setColmenu({ ...colmenu, columns: filtered });
};
working version from the old code (class component)
onChange = (e) => {
var checkedColumns = this.state.checkedColumns
if(e.target.checked){
checkedColumns = checkedColumns.filter(id => {return id !== e.target.id})
}
else if(!e.target.checked){
checkedColumns.push(e.target.id)
}
var filtered = this.state.initialColumns;
for(var i =0;i< checkedColumns.length; i++)
filtered = filtered.filter(el => {return el.dataIndex !== checkedColumns[i]})
this.setState({columns: filtered, checkedColumns: checkedColumns})
}
Something really went wrong with your code (or homework i guess?)
Please have a look at least at the docs for React.useState to set some basics.
First you should init your initalColumns and later you should filter on them.
Additional i init the checkColumns with the correct values and changed the wrong logic for changing them.
Have a look how the filtering is done via Array.includes maybe someone will ask for this ;-)
Another point is that you may split the state object in separate primitive states.
Nevertheless here is a working stackblitz and the depending code.
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Table, Button, Dropdown, Menu, Checkbox } from 'antd';
const App = () => {
const columns = [
{
title: 'Description',
dataIndex: 'description',
},
{
title: 'Employees',
dataIndex: 'employees',
},
];
const [colmenu, setColmenu] = React.useState({
value: false,
checkedColumns: ['description', 'employees'],
visibleMenuSettings: false,
columns,
initialColumns: columns,
});
const onChange = (e) => {
let { checkedColumns, columns, initialColumns } = colmenu;
if (!e.target.checked) {
checkedColumns = checkedColumns.filter((id) => {
return id !== e.target.id;
});
console.log('if checked columns is', checkedColumns);
} else if (e.target.checked) {
checkedColumns.push(e.target.id);
console.log('elseif checked columns', checkedColumns);
}
console.log(columns);
columns = initialColumns.filter((col) =>
checkedColumns.includes(col.dataIndex)
);
setColmenu({ ...colmenu, columns, checkedColumns });
};
const handleVisibleChange = (flag) => {
setColmenu({ ...colmenu, visibleMenuSettings: flag });
};
const menu = (
<Menu>
<Menu.ItemGroup title="Columns">
<Menu.Item key="0">
<Checkbox id="description" onChange={onChange} defaultChecked>
Description
</Checkbox>
</Menu.Item>
<Menu.Item key="1">
<Checkbox id="employees" onChange={onChange} defaultChecked>
Employees
</Checkbox>
</Menu.Item>
</Menu.ItemGroup>
</Menu>
);
const dataSource = [
{
key: '1',
description: 'Holiday 1',
employees: '79',
},
{
key: '2',
description: 'Holiday 2',
employees: '12',
},
{
key: '3',
description: 'Holiday 3',
employees: '0',
},
];
return (
<div>
<div className="row">
<div className="col-12 mb-3 d-flex justify-content-end align-items-center">
<Dropdown
overlay={menu}
onVisibleChange={handleVisibleChange}
visible={colmenu.visibleMenuSettings}
>
<Button>Show/Hide Columns</Button>
</Dropdown>
</div>
</div>
<div className="row">
<div className="col-12">
<Table
columns={colmenu.columns}
dataSource={dataSource}
size="small"
pagination={{
pageSizeOptions: ['20', '50'],
showSizeChanger: true,
}}
/>
</div>
</div>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('container'));

Creating an element using .map function in Javascript

I'm struggling while creating an element that is passed by the .map function. Basically, I want my webpage to create a div element with some date in it when a button is clicked for that I'm using a .map function but it isn't working out.
const handleSubmit = (e) => {
e.preventDefault();
const data = {title:`${title}`, desc:`${desc}`, date:`${date}`};
data.map(userinfo =>{
return(<div>
<h1>{userinfo.title}</h1>
</div>)
})
console.log(data);
}
In reactJS, if we want to display our data in HTML webpage we usually do that in the render funciton.
We can use userInfo variable in the state object.
The userInfo data is hardcoded for demonstration purposes but you can also populate the userInfo variable either using API or in any other way you like.
Moreover, showUserInfo is another variable (initially false) that would render the data once it is set to true
this.state = {
userInfo: [
{
title: 'one',
desc: '',
date: new Date()
},
{
title: 'two',
desc: '',
date: new Date()
}
],
showUserInfo: false
}
On a click event we can set showUserInfo to true using setState function.
more on setState function via this link ->
https://medium.com/#baphemot/understanding-reactjs-setstate-a4640451865b
handleSubmit = async (event) => {
event.preventDefault();
this.setState(
{
...this.state,
showUserInfo: true
}
)
}
In the render function, if showUserInfo is false then userInfo.map is never going to render unless showUserInfo is set to true which we do using a click listener that is associated with our function handleSubmit.
render(){
return (
<div>
<button onClick={this.handleSubmit}>Click Me</button>
{ this.state.showUserInfo &&
this.state.userInfo.map(item =>(
<div>
<p> {item.date.toString()} </p>
</div>
) ) }
</div>
);
}
Overall the result looks a something like this.
export default class App extends React.Component {
constructor() {
super();
this.state = {
showUserInfo: false,
userInfo: [
{
title: 'one',
desc: '',
date: new Date()
},
{
title: 'two',
desc: '',
date: new Date()
}
],
}
}
handleSubmit = async (event) => {
event.preventDefault();
this.setState(
{
...this.state,
showUserInfo: true
}
)
}
render(){
return (
<div>
<button onClick={this.handleSubmit}>Click Me</button>
{ this.state.showUserInfo &&
this.state.userInfo.map(item =>(
<div>
<p> {item.date.toString()} </p>
</div>
) ) }
</div>
);
}
}

Passing value to state using react-select

I'm new to react and trying to learn on my own. I started using react-select to create a dropdown on a form and now I'm trying to pass the value of the option selected. My state looks like this.
this.state = {
part_id: "",
failure: ""
};
Then in my render
const {
part_id,
failure
} = this.state;
My form looks has 2 fields
<FormGroup>
<Label for="failure">Failure</Label>
<Input
type="text"
name="failure"
placeholder="Failure"
value={failure}
onChange={this.changeHandler}
required
/>
</FormGroup>
<FormGroup>
<Label for="part_id">Part</Label>
<Select
name="part_id"
value={part_id}
onChange={this.changeHandler}
options={option}
/>
</FormGroup>
the changeHandler looks like this
changeHandler = e => {
this.setState({ [e.target.name]: e.target.value });
};
The change handler works fine for the input but the Select throws error saying cannot read property name. I went through the API docs and came up with something like this for the Select onChange
onChange={part_id => this.setState({ part_id })}
which sets the part_id as a label, value pair. Is there a way to get just the value? and also how would I implement the same with multiselect?
The return of react-select onChange event and the value props both have the type as below
event / value:
null | {value: string, label: string} | Array<{value: string, label: string}>
So what the error means is that you can't find an attribute of null (not selected), or any attributes naming as name (you need value or label)
For multiple selections, it returns the sub-list of options.
You can find the related info in their document
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
Update
For your situation (single selection)
option having type as above
const option = [
{value: '1', label: 'name1'},
{value: '2', label: 'name2'}
]
state save selected value as id
changeHandler = e => {
this.setState({ part_id: e ? e.value : '' });
};
pick selected option item via saved id
<Select
name="part_id"
value={option.find(item => item.value === part_id)}
onChange={this.changeHandler}
options={option}
/>
For multiple selections
state save as id array
changeHandler = e => {
this.setState({ part_id: e ? e.map(x => x.value) : [] });
};
pick via filter
<Select
isMulti // Add this props with value true
name="part_id"
value={option.filter(item => part_id.includes(item.value))}
onChange={this.changeHandler}
options={option}
/>
onChange function is a bit different in react-select
It passes array of selected values, you may get first one like
onChange={([selected]) => {
// React Select return object instead of value for selection
// return { value: selected };
setValue(selected)
}}
I have tried the above solutions but some of these solutions does update the state but it doesn't gets rendered on the Select value instantly.
Herewith a demo example:
this.state = {
part_id: null,
};
handleUpdate = (part_id) => {
this.setState({ part_id: part_id.value }, () =>
console.log(`Option selected:`, this.state.part_id)
);
};
const priceOptions = [
{ value: '999', label: 'Item One' },
{ value: '32.5', label: 'Item Two' },
{ value: '478', label: 'Item Three' }
]
<Select
onChange={this.handleUpdate}
value={priceOptions.find(item => item.value === part_id)}
options={priceOptions}
placeholder={<div>Select option</div>}
/>

Filter state in React without removing data

I'm trying to make a react component that can filter a list based on value chosen from a drop-down box. Since the setState removes all data from the array I can only filter once. How can I filter data and still keep the original state? I want to be able to do more then one search.
Array list:
state = {
tree: [
{
id: '1',
fileType: 'Document',
files: [
{
name: 'test1',
size: '64kb'
},
{
name: 'test2',
size: '94kb'
}
]
}, ..... and so on
I have 2 ways that I'm able to filter the component once with:
filterDoc = (selectedType) => {
//way #1
this.setState({ tree: this.state.tree.filter(item => item.fileType === selectedType) })
//way#2
const myItems = this.state.tree;
const newArray = myItems.filter(item => item.fileType === selectedType)
this.setState({
tree: newArray
})
}
Search component:
class SearchBar extends Component {
change = (e) => {
this.props.filterTree(e.target.value);
}
render() {
return (
<div className="col-sm-12" style={style}>
<input
className="col-sm-8"
type="text"
placeholder="Search..."
style={inputs}
/>
<select
className="col-sm-4"
style={inputs}
onChange={this.change}
>
<option value="All">All</option>
{this.props.docTypes.map((type) =>
<option
value={type.fileType}
key={type.fileType}>{type.fileType}
</option>)}
</select>
</div>
)
}
}
And some images just to get a visual on the problem.
Before filter:
After filter, everything that didn't match was removed from the state:
Do not replace original data
Instead, change what filter is used and do the filtering in the render() function.
In the example below, the original data (called data) is never changed. Only the filter used is changed.
const data = [
{
id: 1,
text: 'one',
},
{
id: 2,
text: 'two',
},
{
id: 3,
text: 'three',
},
]
class Example extends React.Component {
constructor() {
super()
this.state = {
filter: null,
}
}
render() {
const filter = this.state.filter
const dataToShow = filter
? data.filter(d => d.id === filter)
: data
return (
<div>
{dataToShow.map(d => <span key={d.id}> {d.text}, </span>)}
<button
onClick={() =>
this.setState({
filter: 2,
})
}
>
{' '}
Filter{' '}
</button>
</div>
)
}
}
ReactDOM.render(<Example />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<body>
<div id='root' />
</body>
Don't mutate local state to reflect the current state of the filter. That state should reflect the complete available list, which should only change when the list of options changes. Use your filtered array strictly for the view. Something like this should be all you need to change what's presented to the user.
change = (e) => {
return this.state.tree.filter(item => item.fileType === e.target.value)
}

How to Create an AutoComplete in React

What I have here is a function where I call the codigo, and the nombre, in the DB
  table registrations. What I want to achieve is that the digital code that is like an autocomplete to fill in the name when you select the code.
enter image description here
class Matriculas extends Component {
state = {
status: "initial",
data: []
}
componentDidMount = () => {
this. getInfo()
}
getInfo= async () => {
try {
const response = await getAll('matriculas')
console.log(response.data)
this.setState({
status: "done",
data: response.data
});
} catch (error) {
this.setState({
status: "error"
});
}
};
render() {
const data = [...this.state.data];
return (
<Container>
<RowContainer margin="1px" >
<ColumnContainer margin="10px">
<h3>Info</h3>
<label>Codigo</label>
<Input
width='150px'
type="text"
placeholder="Digite el codigo"
value={data.codigo } ref="codigo" />
<label>Nombre</label>
<Input
width='150px'
type="text"
placeholder="Nombre completo"
value={data.nombre} />
</ColumnContainer>
</RowContainer>
</Container>
)
}
};
export default Matriculas;
What you most likely want to use is react-select
You can pass options to the select (which would be your names) and it will return values that match whatever you type in the search bar.
import Select from 'react-select'
const options = [
{ value: 'mike', label: 'Mike' },
{ value: 'john', label: 'John' },
{ value: 'vanessa', label: 'Vanessa' }
]
const MyComponent = () => (
<Select options={options} />
)
So you can take that example, and the examples in the link, and put it in your code:
import Select from 'react-select'
<Container>
<RowContainer margin="1px" >
<ColumnContainer margin="10px">
<h3>Info</h3>
<label>Codigo</label>
<Input
width='150px'
type="text"
placeholder="Digite el codigo"
value={data.codigo } ref="codigo" />
<label>Nombre</label>
<Select
value={this.state.nameValue}
onChange={event => {this.setState({nameValue: e.value})}
options={options} />
</ColumnContainer>
</RowContainer>
</Container>
When using onChage, it returns an event, which has the value of the selected name. You can use that to set the state's nameValue, and then use that name value in the rest of your component as well
Once you get this up and running, it also worth looking at the async select, which allows you to give an async function that returns values (your getInfo function, for example)
-- edit --
If you want to define the onChange event elsewhere, it would look like this:
handleChange = event => {
// event.value will be the value of the select
this.setState({optionSelected: event.value});
}
and then in your onChange, tell it that is the function you want but do not invoke it (don't write it with parentheses):
<Select
value={this.state.optionSelected}
onChange={this.handleChange}
options={options} />

Categories