Reputation: 23
I want to give to my suggestor a value from a Json file. The name of those value are displayed in my select but when I am returning with an alert() my value it shows 'null'. I want to use as a value the name already displayed/visible in the select.
The purpose of my application is after somebody choose a name in the select to show all the data from both database that has the same name.
This is the structure of both JSON file they all have different id, name,admin_area & country value
{
"id": 3,
"name": "Satimola",
"admin_area": "Theo",
"country": "Taiwan"
}
Of course I tried to pass my array suggestionOldData as a value but it didn't work the console said :
Failed prop type: Invalid prop value
of type array
supplied to Suggestor
, expected string
.
import React from "react";
import { Component } from "react";
import ReactDOM from "react-dom";
// IMPORT DATA FROM JSON FILE
import NewData from "../../api/data/cities.json";
import OldData from "../../api/data/historical.json";
// IMPORT PAGINATION FILE
import Pagination from "./Pagination.js";
// IMPORT MODULE TO CREATE INPUT SEARCH
import Suggestor from "ssuggestor";
// CREATE A COMPONENT THAT WILL SHOW THE NEW DATA IN A TABLE
class NewDataTable extends React.Component {
constructor() {
super();
this.state = {
NewData: NewData,
pageOfItems: []
};
this.onChangePage = this.onChangePage.bind(this);
this.handleChange = this.handleChange.bind(this);
}
onChangePage(pageOfItems) {
// update state with new page of items
this.setState({ pageOfItems: pageOfItems });
}
// GET INPUT VALUE , GET DATA WITH THE SAME NAME IN BOTH ARRAY, CONSOLE.LOG BOTH
handleChange(event) {
var val = document.getElementById(Suggestor);
alert(val);
const consoleOldData = OldData.find(value => value.name);
const consoleNewData = NewData.find(value => value.name);
console.log("Old Data =>", consoleOldData);
console.log("New Data =>", consoleNewData);
}
render() {
// GET DATA.NAME FROM OldData
const suggesttionOldData = OldData.map(value => value.name);
return (
<div>
<form>
<Suggestor
id="Suggestor"
list={suggesttionOldData}
onSelect={this.handleChange}
placeholder=" ..."
value={this.state.value}
/>
</form>
<nav>
<Pagination
items={this.state.NewData}
onChangePage={this.onChangePage}
/>
</nav>
<table>
<tbody>
<tr>
<th>New Data</th>
</tr>
{this.state.pageOfItems.map(item => (
<tr key={item.id}>
<td key={item.id}>{item.name}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default NewDataTable;
This is the suggestor class
class Suggestor extends PureComponent {
constructor(props) {
super(props);
autoBind(this);
this.input = React.createRef();
this.state = {
filtered: this.filter(props.list, props.value, false),
value: props.value,
open: false,
index: 0
};
}
componentDidMount() {
document.addEventListener('click', this._onClick);
}
componentWillUnmount() {
document.removeEventListener('click', this._onClick);
}
_onClick(event) {
if (!this.input.current.parentNode.contains(event.target)) {
this.close();
}
}
componentWillReceiveProps(nextProps) {
let value = this.state.value;
if (nextProps.value !== this.props.value && nextProps.value !== value) {
value = nextProps.value;
}
this.setState({
filtered: this.filter(nextProps.list, value, true),
value
});
}
close() {
this.setState({
open: false,
filtered: this.unfilter(),
index: 0
});
}
handleClick() {
if (this.props.openOnClick) {
if (this.state.open) {
this.close();
} else {
this.setState({ open: true, filtered: this.unfilter() });
}
}
}
handleKeyDown(e) {
const { onKey, useKeys } = this.props;
onKey(e);
if (useKeys && this.processKey(e.keyCode)) {
e.preventDefault();
}
}
processKey(code) {
const { open, index, filtered, value } = this.state;
const ssuggestions = filtered.length ? filtered : this.unfilter();
let nextIndex;
switch (code) {
case keys.ENTER:
if (open && filtered[index]) {
this.changeValue(filtered[index].word, true);
} else {
this.setState({ open: true, filtered: this.unfilter() });
}
break;
case keys.ESCAPE:
this.close();
if (!open && value) {
this.changeValue('');
}
break;
case keys.DOWN:
nextIndex = (index + open) % ssuggestions.length;
break;
case keys.UP:
nextIndex = (index || ssuggestions.length) - 1;
break;
case keys.TAB:
if (this.props.selectOnTab && open && filtered[index]) {
this.changeValue(filtered[index].word, true);
} else {
this.close();
}
default:
return false;
}
if (nextIndex !== undefined) {
this.setState({ open: true, index: nextIndex, filtered: ssuggestions });
}
return true;
}
handleItemClick({ word }) {
this.changeValue(word, true);
}
handleItemMouseEnter(index) {
this.setState({ index });
}
handleChange(e) {
e.stopPropagation();
const value = e.target.value;
this.changeValue(value);
}
remove() {
this.changeValue('', true);
}
changeValue(value, select = false) {
const { list, suggestOn, accents, onChange, onSelect } = this.props;
const filtered = this.filter(list, value);
const suggest = value.length >= suggestOn;
const open = !!filtered.length && suggest;
this.setState({ value, filtered, open }, () => {
onChange(value);
if (select) {
const suggestion = filtered.find(({ word }) => transform(accents, word) === transform(accents, value));
onSelect(value, suggestion && suggestion.item);
this.close();
}
});
}
filter(list, value, onlyMatch = true) {
const { accents, selector } = this.props;
value = transform(accents, value);
let mapped = list.map(item => {
const word = selector(item);
return {
index: transform(accents, word).indexOf(value),
word,
item
};
});
if (onlyMatch) {
mapped = mapped.filter(item => item.index !== -1);
}
return mapped;
}
unfilter() {
return this.filter(this.props.list, this.state.value, false);
}
focus() {
this.input.current.focus();
}
render() {
const { theme, style, placeholder, arrow, close, tooltip, required } = this.props;
const { open, value, index, filtered } = this.state;
const displaySuggestions = open && !!filtered.length;
return (
<div className={theme.root} onClick={this.handleClick} onKeyDown={this.handleKeyDown} style={style}>
<input
type="text"
className={theme.input}
onChange={this.handleChange}
value={value}
title={tooltip}
placeholder={placeholder}
required={required}
ref={this.input}
/>
{arrow && <span className={theme.arrow} />}
{close && value && <span className={theme.close} onClick={this.remove} />}
{displaySuggestions && (
<ul className={theme.list}>
{filtered.map((item, i) => (
<ListItem
key={item.word}
theme={theme}
item={item}
index={i}
onItemClick={this.handleItemClick}
onItemMouseEnter={this.handleItemMouseEnter}
overItem={i === index}
search={value}
/>
))}
</ul>
)}
</div>
);
}
}
Suggestor.propTypes = {
list: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])).isRequired,
selector: PropTypes.func,
onChange: PropTypes.func,
onSelect: PropTypes.func,
onKey: PropTypes.func,
value: PropTypes.string,
openOnClick: PropTypes.bool,
selectOnTab: PropTypes.bool,
placeholder: PropTypes.string,
tooltip: PropTypes.string,
theme: PropTypes.shape({
root: PropTypes.string,
arrow: PropTypes.string,
close: PropTypes.string,
list: PropTypes.string,
item: PropTypes.string,
activeItem: PropTypes.string
}),
suggestOn: PropTypes.number,
style: PropTypes.object,
required: PropTypes.bool,
useKeys: PropTypes.bool,
accents: PropTypes.bool,
arrow: PropTypes.bool,
close: PropTypes.bool
};
Suggestor.defaultProps = {
theme: {},
selector: s => s,
onSelect: noop,
onChange: noop,
onKey: noop,
value: '',
openOnClick: true,
selectOnTab: false,
suggestOn: 1,
required: false,
accents: false,
useKeys: true,
arrow: true,
close: true
};
export default Suggestor;
Upvotes: 1
Views: 453
Reputation: 654
So, looking at the example mentioned in the readme for ssugester
package, it looks like you are passing wrong callback for the onSelect
method.
So, I believe changing your code to the following way should work.
Change the Suggester
component to have a function that represents the onSelect
callback in a more meaningful way, for example:
<Suggestor
id;= "Suggestor";
list = {suggesttionOldData};
onSelect = {this.onSuggesterSelect};
placeholder =' ...'
value = {this.state.value}
/ >
and in your NewDataTable
component, create another function called onSuggesterSelect
.
// GET INPUT VALUE , GET DATA WITH THE SAME NAME IN BOTH ARRAY, CONSOLE.LOG BOTH
onSuggesterSelect(value, suggestion) {
const val = value; // this should be your selected value (name) now.
alert(val);
const consoleOldData = OldData.find(value => value.name);
const consoleNewData = NewData.find(value => value.name);
console.log('Old Data =>', consoleOldData);
console.log('New Data =>', consoleNewData);
}
So, with these changes your component should look something like this:
import React from "react";
import { Component } from "react";
import ReactDOM from "react-dom";
// IMPORT DATA FROM JSON FILE
import NewData from "../../api/data/cities.json";
import OldData from "../../api/data/historical.json";
// IMPORT PAGINATION FILE
import Pagination from "./Pagination.js";
// IMPORT MODULE TO CREATE INPUT SEARCH
import Suggestor from "ssuggestor";
// CREATE A COMPONENT THAT WILL SHOW THE NEW DATA IN A TABLE
class NewDataTable extends React.Component {
constructor() {
super();
this.state = {
NewData: NewData,
pageOfItems: []
};
this.onChangePage = this.onChangePage.bind(this);
this.handleChange = this.handleChange.bind(this);
}
onChangePage(pageOfItems) {
// update state with new page of items
this.setState({ pageOfItems: pageOfItems });
}
// GET INPUT VALUE , GET DATA WITH THE SAME NAME IN BOTH ARRAY, CONSOLE.LOG BOTH
handleChange(event) {
var val = document.getElementById(Suggestor);
alert(val);
const consoleOldData = OldData.find(value => value.name);
const consoleNewData = NewData.find(value => value.name);
console.log("Old Data =>", consoleOldData);
console.log("New Data =>", consoleNewData);
}
onSuggesterSelect(value, suggestion) {
const val = value; // this should be your selected value (name) now.
alert(val);
const consoleOldData = OldData.find(value => value.name);
const consoleNewData = NewData.find(value => value.name);
console.log('Old Data =>', consoleOldData);
console.log('New Data =>', consoleNewData);
}
render() {
// GET DATA.NAME FROM OldData
const suggesttionOldData = OldData.map(value => value.name);
return (
<div>
<form>
<Suggestor
id="Suggestor"
list={suggesttionOldData}
onSelect={this.onSuggesterSelect}
placeholder=" ..."
value={this.state.value}
/>
</form>
<nav>
<Pagination
items={this.state.NewData}
onChangePage={this.onChangePage}
/>
</nav>
<table>
<tbody>
<tr>
<th>New Data</th>
</tr>
{this.state.pageOfItems.map(item => (
<tr key={item.id}>
<td key={item.id}>{item.name}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default NewDataTable;
I hope this works for you now.
Upvotes: 2
Reputation: 124
var val = document.getElementById(Suggestor); Change to var val = event.target.value
Upvotes: 0