Error - PrimeReact Autocomplete suggestions not showing - reactjs

https://primefaces.org/primereact/showcase/#/autocomplete
I am trying to load suggestions dropdown as soon as component loads with some data in componentDidMount. The suggestionsList is updating with the obj data in componentDidMount, however suggestion dropdown is not showing.
Simply, whenever input is get focussed and no input text is there, a suggestion dropdown should show.
abcCmp.jsx
class abcCmp extends React.Component {
state;
constructor() {
super();
this.state = {
suggestionsList: []
};
}
componentDidMount() {
let obj = [{'color':'red',name: 'Danny', id: '1'}];
this.setState({suggestionsList: [...obj]})
}
render(){
return (
<div className="containerBox">
<AutoComplete suggestions={this.state.suggestionsList}
minLength={1} placeholder="Add People" field="name" multiple={true}
autoFocus={true} />
</div>
)
}

If you gone through documentation there are other parameters also required.
Those are: completeMethod,value,onChange out of these completeMethod is required to show filtered list as you type. Inside completeMethod you need to filter your data that's how your dropdown list reduces as you type more.
You need ref for toggling dropdown functionality and also you need to check on focus if input value is empty and no value is selected so toggle dropdown.
Here is simple POC I create for reference. Try typing D
Code:
import React from "react";
import { AutoComplete } from "primereact/autocomplete";
import "./styles.css";
let obj = [
{ color: "red", name: "Dagny", id: "1" },
{ color: "red", name: "kanny", id: "2" },
{ color: "red", name: "Dgnny", id: "3" },
{ color: "red", name: "Danny", id: "4" },
{ color: "red", name: "Dmnny", id: "5" },
{ color: "red", name: "Donny", id: "" }
];
class MyComponent extends React.Component {
myRef = React.createRef();
constructor() {
super();
this.state = {
suggestionsList: [],
selected: null,
inputValue: null
};
}
componentDidMount() {
this.setState({ suggestionsList: [...obj] });
}
searchList = (event) => {
let suggestionsList;
if (!event.query.trim().length) {
suggestionsList = [...obj];
} else {
suggestionsList = [...obj].filter((list) => {
return list.name.toLowerCase().startsWith(event.query.toLowerCase());
});
}
this.setState({ suggestionsList });
};
render() {
return (
<div className="containerBox">
<AutoComplete
suggestions={this.state.suggestionsList}
completeMethod={this.searchList}
minLength={1}
ref={this.myRef}
dropdown
inputId="my"
placeholder="Add People"
field="name"
onFocus={(e) => {
if (!this.state.inputValue && !this.state.selected) {
this.myRef.current.onDropdownClick(e, "");
}
}}
onKeyUp={(e) => this.setState({ inputValue: e.target.value })}
// completeOnFocus={true}
multiple={true}
autoFocus={true}
value={this.state.selected}
onChange={(e) => this.setState({ selected: e.value })}
/>
</div>
);
}
}
export default function App() {
return (
<div className="App">
<MyComponent />
</div>
);
}
Demo: https://codesandbox.io/s/prime-react-autocomplete-forked-n3x2x?file=/src/App.js

Add dropdown inside autocomplete tags and also add completeMethod and bind it to a search/filter function, add a value to bind the selected value, add a onChange function to it
You can find full documantation and working example here :PrimeFaces React Autocomplete

Related

DataSearch component executes search every time a key is pressed

So I'm trying to make the DataSearch component behave but the component calls the search/triggerquery for every key stroke and I don't understand why. Also javascript throws an exception because it want's the dataField attribute defined even though I'm making use of a customQuery. I only want the query to be called, when the user presses enter. Can anyone help?
class DocumentSearchComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "",
corpus: "xxxx",
url: "http://localhost:7777",
};
this.handleKey = this.handleKey.bind(this);
this.onChange = this.onChange.bind(this);
}
handleKey(e, triggerQuery) {
if (e.key === "Enter") {
triggerQuery();
}
};
onChange(value) {
this.setState({
value,
});
};
customQuery(test) {
return {
query: {...}
},
_source: ["title", "publicationDate"],
size: 10,
highlight: {
pre_tags: ['<em>'],
post_tags: ['</em>'],
fields: {
fullText: {}
}
}
}
}
render() {
return (
<div className="App">
<ReactiveBase app={this.state.corpus} url={this.state.url}>
<DataSearch
componentId="documentSearch"
className="search-bar"
placeholder="Search for documents"
autosuggest={false}
customQuery={this.customQuery}
value={this.state.value}
onChange={this.onChange}
onKeyPress={this.handleKey}
/>
<ReactiveList
className="result-list"
componentId="SearchResult"
react={{
and: "documentSearch",
}}
dataField="label"
sortOptions={[
{ label: "Relevance", dataField: "_score", sortBy: "desc" },
]}
>
{({ data }) =>
data.map((item) => (
<div key={item.id} className="vertical-margin">
<DocumentResult
corpus={this.state.corpus}
document={item}
></DocumentResult>
</div>
))
}
</ReactiveList>
</ReactiveBase>
</div>
);
}

How can I do to choose an option from a select when I click on a button using React?

I would like to choose the option "Apple" from the select when I click on the "Apple" button using React
import React from "react";
import { render } from "react-dom";
import ReactDOM from "react-dom";
import Select from "react-select";
import "react-select/dist/react-select.css";
class ReactSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
itemtitle: "",
multi: true,
multiValue: [],
options: [
{ value: "Color", label: "Yellow" },
{ value: "Fruit", label: "Apple" },
{ value: "Tool", label: "Spanner" }
]
};
}
onTitleChange(e, value) {
this.setState({ [e.target.name]: e.target.value });
this.setState({ multiValue: e.target.value });
}
handleOnChange(value) {
this.setState({ multiValue: value });
}
render() {
return (
<div>
<Select.Creatable
multi={this.state.multi}
options={this.state.options}
onChange={this.handleOnChange.bind(this)}
value={this.state.multiValue}
showNewOptionAtTop={false}
/>
<button>Apple</button>
</div>
);
}
}
ReactDOM.render(<ReactSelect />, document.body);
The full code of my project is there :
The full code
How can I do that ? Thank you very much !
You can update the select field value when you click the button something like this.
handleOnClick = () => {
this.setState({ multiValue: [{ value: "Fruit", label: "Apple" }] });
};
render() {
return (
<div>
<Select.Creatable
multi={this.state.multi}
options={this.state.options}
onChange={this.handleOnChange.bind(this)}
value={this.state.multiValue}
showNewOptionAtTop={false}
/>
<button
onClick={() => {
this.handleOnClick();
}}
>
Apples
</button>
</div>
);
}
Attached a sandbox link also.

Adding new options to form on click in ReactJs

I am doing a React search where user can add multiple filters. The idea is that at first there is only one filter (select and input field) and if user wishes to add more, he can add one more row of (select and input) and it will also take that into account.
I cannot figure out the part on how to add more rows of (select, input) and furthermore, how to read their data as the list size and everything can change.
So I have multiple options in the select array:
const options = [
{ label: "foo", value: 1 },
{ label: "bar", value: 2 },
{ label: "bin", value: 3 }
];
Now if user selects the first value from the Select box and then types a text in the input box I will get their values and I could do a search based on that.
const options = [
{ label: "foo", value: 1 },
{ label: "bar", value: 2 },
{ label: "bin", value: 3 }
];
class App extends React.Component {
state = {
selectedOption: null,
textValue: null
};
handleOptionChange = selectedOption => {
this.setState({ selectedOption: selectedOption.value });
};
handleTextChange = event => {
this.setState({ textValue: event.target.value });
};
handleSubmit = () => {
console.log(
"SelectedOption: " +
this.state.selectedOption +
", textValue: " +
this.state.textValue
);
};
addNewRow = () => {
console.log("adding new row of filters");
};
render() {
const { selectedOption } = this.state;
return (
<div>
<div style={{ display: "flex" }}>
<Select
value={selectedOption}
onChange={this.handleOptionChange}
options={options}
/>
<input
type="text"
value={this.state.textValue}
onChange={this.handleTextChange}
/>
</div>
<button onClick={this.addNewRow}>AddNewRow</button>
<button onClick={this.handleSubmit}>Submit</button>
</div>
);
}
}
export default App;
I have also created a CodeSandBox for this.
If user clicks on the addNewRow a new row should appear and the previous (search, input) should be selectable without the row that was previously selected.
I don't even really know how I should approach this.
To add new row of inputs on click of button you need to add new input item into the list of inputs, like I have mention below::
import React, { Component } from 'react'
import Select from "react-select";
const options = [
{ label: "foo", value: 1 },
{ label: "bar", value: 2 },
{ label: "bin", value: 3 }
];
class App extends Component {
constructor(props) {
super(props);
this.state = { inputGroups: ['input-0'] };
}
handleSubmit = () => {
console.log("form submitted");
};
AddNewRow() {
var newInput = `input-${this.state.inputGroups.length}`;
this.setState(prevState => ({ inputGroups: prevState.inputGroups.concat([newInput]) }));
}
render() {
return (
<div>
<div>
<div>
{this.state.inputGroups.map(input =>
<div key={input} style={{ display: "flex" }}>
<Select
options={options}
/>
<input
type="text"
// value={this.state.textValue}
// onChange={this.handleTextChange}
/>
</div>
)}
</div>
</div>
<button onClick={() => this.AddNewRow()}>AddNewRow</button>
<button onClick={this.handleSubmit()}>Submit</button>
</div>
);
}
}
export default App;
After click on "AddNewRow" button it will add new input group for you. Now you need to wrap this inputGroup inside "Form" to get data of each inputGroup on click of submit.
I hope it will resolve your issue.

Updating the Values of Multiple Instances of a React Component Returns .map is not a function

I am developing a webpage that is made up of a component containing a dropdown menu of restrictions, and textbox for integer entry. However, since the component can be cloned I am using the map function to make copies. When I go to update the value of either the textbox or the dropdown, the console returns TypeError: this.state.selectedIntervals.map is not a function.
My code is separated into a parent(App.js) and child component(Intervals.js). Intervals.js contains event handlers to check for values being updated and App.js makes copies of the Intervals component with the map function.
From previous posts, I have tried to check whether updating the value removes elements from my array and modifying the method through how events are handled in the child component with no luck.
The following is a reduced version of the code. Ignore the countries and selectedCountry parts of the state, they are for another purpose.
App.js
import React, { Component } from "react";
///import NavigationMenu from "../NavigationMenu";
import Intervals from "../Components/Intervals";
class Application extends Component {
state = {
countries: [
{ id: 1, country: "USA" },
{ id: 2, country: "Brazil" },
{ id: 3, country: "Russia" },
],
selectedCountry: [{ value: 0 }],
selectedIntervals: [{ id: 1, duration: 0, restriction: "None" }],
};
handleInterval = (newValue) => {
this.setState({ selectedIntervals: { duration: newValue } });
};
handleNewInterval = () => {
const selectedIntervals = [...this.state.selectedIntervals];
selectedIntervals.push({
id: this.state.selectedIntervals.length + 1,
duration: 0,
restriction: "None",
});
this.setState({ selectedIntervals });
};
handleDeleteInterval = () => {
const selectedIntervals = [...this.state.selectedIntervals];
selectedIntervals.pop();
this.setState({ selectedIntervals });
};
handleRestriction = (newValue) => {
this.setState({ selectedIntervals: { restriction: newValue } });
};
render() {
return (
<div>
<br />
<button onClick={this.handleNewInterval}>+</button>
<button onClick={this.handleDeleteInterval}>-</button>
<br />
<div>
{this.state.selectedIntervals.map((interval) => (
<Intervals
key={interval.id}
duration={interval.duration}
restriction={interval.restriction}
onIntervalUpdate={this.handleInterval}
onRestrictionUpdate={this.handleRestriction}
/>
))}
</div>
<br />
</div>
);
}
}
export default Application;
Intervals.js
import React, { Component } from "react";
class Intervals extends Component {
handleRestrictionChange = (event) => {
this.props.onRestrictionUpdate(event.target.value);
};
handleDurationChange = (event) => {
this.props.onIntervalUpdate(event.target.value);
};
render() {
return (
<div>
<label>
Enter the length of the interval:
<input type="text" onChange={this.handleDurationChange} />
<select onChange={this.handleRestrictionChange} defaultValue="None">
<option key="1" value="Lockdown">
Lockdown
</option>
<option key="2" value="Vacation">
Vacation
</option>
<option key="3" value="School closure">
School closure
</option>
<option key="4" value="None">
None
</option>
</select>
</label>
</div>
);
}
}
export default Intervals;
handleInterval = (newValue) => {
this.setState({ selectedIntervals: { duration: newValue } });
};
You forgot to wrap it in an array:
handleInterval = (newValue) => {
this.setState({ selectedIntervals: [{ duration: newValue }] });
};
EDIT: looks like you're trying to do a deep merge. setState won't merge only on the top level. Deep objects need to be merged manually.

Dropdown, React Router and back button

This small component changes URL when you select something from dropdown. Everything works correctly.. Except back button. Everything else changes if I press it but dropdown doesn't change.
How exactly?
If I go to landing page, default value is All
Now I select Red
Now Blue
Red again
Finally Blue
Now, if I click back button, dropdown always shows last selected value (Blue in my example)
How to overcome this issue?
class MyComponent extends React.Component {
constructor (props) {
super(props)
this.state = {
selected: {
// This only affects dropdown if landing to page
value: this.props.params.color, // Get param from url
label: // Some irrelevant uppercase magic here
}
}
}
static defaultProps = {
colors: [
{value: 'all', label: 'All'},
{value: 'red', label: 'Red'},
{value: 'blue', label: 'Blue'}
]
}
render() {
return (
<Dropdown
options={this.props.colors} {/* All options */}
value={this.props.selected} {/* Selected option */}
onChange={this.handleSelect.bind(this)}
/>
)
}
handleSelect(color) {
this.setState({selected: color})
browserHistory.push(`/${color.value}`)
}
}
Your issue is that you are using state to manage the selected prop of your Dropdown component, however the router does not update this when you navigate back / forward.
Instead remove state entirely from your component and use the router to detect the selected item directly:
import { find } from 'lodash';
class MyComponent extends React.Component {
static defaultProps = {
colors: [
{value: 'all', label: 'All'},
{value: 'red', label: 'Red'},
{value: 'blue', label: 'Blue'}
]
}
getSelected() {
const colours = this.props.colours
const selectedColour = this.props.params.colour
// Find the option matching the route param, or
// return a default value when the colour is not found
return find(colours, { value: selectedColour }) || colours[0];
}
render() {
const selectedOption = this.getSelected();
return (
<div>
<Dropdown
options={ this.props.colors } {/* All options */}
value={ selectedOption } {/* Selected option */}
onChange={ this.handleSelect.bind(this) }
/>
<p>You selected: { selectedOption.label }</p>
</div>
)
}
handleSelect(color) {
browserHistory.push(`/${color.value}`)
}
}

Resources